Android Binder进程间通信---注册Service组件---发送和处理BC_REPLY返回协议

本文参考《Android系统源代码情景分析》,作者罗升阳

一、测试代码:

~/Android/external/binder/server

----FregServer.cpp

~/Android/external/binder/common

----IFregService.cpp

----IFregService.h

~/Android/external/binder/client

----FregClient.cpp

Binder库(libbinder)代码:

~/Android/frameworks/base/libs/binder

----BpBinder.cpp

----Parcel.cpp

----ProcessState.cpp

----Binder.cpp

----IInterface.cpp

----IPCThreadState.cpp

----IServiceManager.cpp

----Static.cpp

~/Android/frameworks/base/include/binder

----Binder.h

----BpBinder.h

----IInterface.h

----IPCThreadState.h

----IServiceManager.h

----IBinder.h

----Parcel.h

----ProcessState.h

驱动层代码:

~/Android//kernel/goldfish/drivers/staging/android

----binder.c

----binder.h

二、源码分析

在Android Binder进程间通信---注册Service组件---Client发送BC_TRANSACTIONhttp://blog.csdn.net/jltxgcy/article/details/26076149一文中,在最后线程睡眠以等待进程间通信结果。

http://blog.csdn.net/jltxgcy/article/details/26076149文章中,我们假设请求注册Service组件FregService的线程thread正在Binder驱动程序函数binder_thread_read中等待Service
Manager完成注册操作。现在既然Service Manager已经完成了对Service组件FregService的注册,并且线程thread已经被Binder驱动程序唤醒,接下来它就会执行函数binder_thread_read来处理它的todo队列中的工作项了。

现在请求注册Service组件FregService的线程thread的todo队列中有一个类型为BINDER_WORK_TRANSACTION的工作项,因此,接下来我们就分析函数binder_thread_read处理这个工作项的过程。

~/Android//kernel/goldfish/drivers/staging/android

----binder.c

static int
binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,
	void  __user *buffer, int size, signed long *consumed, int non_block)
{
	void __user *ptr = buffer + *consumed;
	void __user *end = buffer + size;
        .........

	while (1) {
		uint32_t cmd;
		struct binder_transaction_data tr;
		struct binder_work *w;
		struct binder_transaction *t = NULL;

		if (!list_empty(&thread->todo))
			w = list_first_entry(&thread->todo, struct binder_work, entry);//从线程thread的todo队列中取出这个类型为BINDER_WORK_TRANSACTION的工作项
		else if (!list_empty(&proc->todo) && wait_for_proc_work)
			w = list_first_entry(&proc->todo, struct binder_work, entry);
		else {
			..........
		}

		.....

		switch (w->type) {
		case BINDER_WORK_TRANSACTION: {
			t = container_of(w, struct binder_transaction, work);//接着又将该工作项的宿主binder_transaction结构体取回来,并且保存在变量t中
		} break;
		........
		if (t->buffer->target_node) {//NULL
			.......
		} else {
			tr.target.ptr = NULL;
			tr.cookie = NULL;
			cmd = BR_REPLY;
		}
		tr.code = t->code;//0
		tr.flags = t->flags;//0
		tr.sender_euid = t->sender_euid;

		if (t->from) {
			struct task_struct *sender = t->from->proc->tsk;
			tr.sender_pid = task_tgid_nr_ns(sender, current->nsproxy->pid_ns);
		} else {
			tr.sender_pid = 0;
		}

		tr.data_size = t->buffer->data_size;//数据缓冲区大小
		tr.offsets_size = t->buffer->offsets_size;//偏移数组大小
		tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset;//内核缓冲区的内核空间地址和用户空间地址相差一个固定值,并且保存在它的成员变量user_buffer_offset中
		tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));//偏移保存在数据缓冲区的后面

		if (put_user(cmd, (uint32_t __user *)ptr))//将命令返回
			return -EFAULT;
		ptr += sizeof(uint32_t);
		if (copy_to_user(ptr, &tr, sizeof(tr)))//将binder_transaction_data结构体tr返回
			return -EFAULT;
		ptr += sizeof(tr);

		......

		list_del(&t->work.entry);//删除该任务项
		t->buffer->allow_user_free = 1;//允许释放
		if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
			........
		} else {
			t->buffer->transaction = NULL;
			kfree(t);//释放binder_transaction结构体t
		        .........
		}
		break;
	}

done:

	*consumed = ptr - buffer;//cmd和binder_transaction_data结构体tr大小之和
	.......
	return 0;
}

首先从线程thread的todo队列中取出这个类型为BINDER_WORK_TRANSACTION的工作项,并且保存在变量w中。接着又将该工作项的宿主binder_transaction结构体取回来,并且保存在变量t中。

然后利用binder_transaction结构体t初始化binder_transaction_data结果体tr。然后将cmdBR_REPLY和tr返回用户空间。

线程thread执行完成函数binder_thread_read之后,先返回到函数binder_ioctl中,接着再返回IPCThreadState类的成员函数talkWithDriver中,最后返回到IPCThreadState类的成员函数waitForResponse中来处理BR_REPLY返回协议,如下所示:

~/Android/frameworks/base/libs/binder

----IPCThreadState.cpp

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    int32_t cmd;
    int32_t err;

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        .......

        cmd = mIn.readInt32();//cmd为BR_REPLY
        ......
        switch (cmd) {
        .......
        case BR_REPLY:
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));//从协议缓冲区mIn的内容读到一个binder_transaction_data结构体tr中
                .........

                if (reply) {//不为NULL
                    if ((tr.flags & TF_STATUS_CODE) == 0) {//tr.flags为0
                        reply->ipcSetDataReference(//将保存在binder_transaction结构体tr中的进程间通信结果保存在Parcel对象reply中
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(size_t),
                            freeBuffer, this);
                    } else {
                       .......
                    }
                } else {
                   ........
                }
            }
            goto finish;
           .........
        }
    }

finish:
   .....
    return err;
}

首先从返回协议缓冲区mIn中读取一个BR_REPLY返回协议代码。然后又从协议缓冲区mIn的内容读到一个binder_transaction_data结构体tr中。

如果binder_transaction_data结构体tr的成员变量flags的TF_STATUS_CODE位等于0,就说明当前进程之前所发出的一个进程间通信请求已经被成功地处理了。因此,就将保存在binder_transaction结构体tr中的进程间通信结果保存在Parcel对象reply中,这是通过调用Parcel对象reply的成员函数ipcSetDataReference来实现的。实现如下:

~/Android/frameworks/base/libs/binder

----Parcel.cpp

void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
    const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)
{
    freeDataNoInit();
    mError = NO_ERROR;
    mData = const_cast<uint8_t*>(data);//进程间通信结果数据的缓冲区
    mDataSize = mDataCapacity = dataSize;进程间通信结果数据的缓冲区大小
    ..........
    mDataPos = 0;
    ..........
    mObjects = const_cast<size_t*>(objects);//偏移数组起始位置
    mObjectsSize = mObjectsCapacity = objectsCount;//偏移数组大小
    .........
    mOwner = relFunc;//freeBuffer
    mOwnerCookie = relCookie;//当前线程IPCThreadState对象
    ........
}

参数data指向了用来保存进程间通信结果数据的缓冲区,它的大小由参数dataSize来描述。参数object指向了一个Binder对象偏移数组,用来描述保存在进程间通信数据缓冲区的Binder对象的位置,它的大小由参数objectsCount来描述,参数relFunc是一个函数指针,它指向了IPCTheadState类的成员函数freeBuffer,参数relCookie指向了当前线程的IPCThreadState对象。

然后依次赋值给Parcel类的不同成员变量,mData是数据缓冲区的其实地址,mDataSize为数据缓冲区大小,mDataPos为下一个用来读入的位置。mObjects为偏移数组起始地址,mObjetctSize是偏移数组mObjects下一个用于读入数据的位置,mObjectsCapacity为偏移数组的大小。

mOwner保存着freeBuffer的函数指针,mOwnerCookie保存者当前线程IPCThreadState对象。线程获得了保存在当前Parcel对象中的进程间通信结果数据之后,它就会析构该Parcel对象,而该Parcel对象在析构时,会调用它的成员变量mOwner和mOwnerCookie来调用IPCTheadState类的成员函数freeBuffer释放它内部使用的数据缓冲区mData。由于这个数据缓冲区是在Binder驱动程序中分配的,即它指向一个内核缓冲区,因此IPCThreadState类的成员函数freeBuffer会通过BC_FREE_BUFFER命令协议通知Binder驱动程序将内核缓冲区释放掉。

Android Binder进程间通信---注册Service组件---发送和处理BC_REPLY返回协议,布布扣,bubuko.com

时间: 2024-10-13 23:30:16

Android Binder进程间通信---注册Service组件---发送和处理BC_REPLY返回协议的相关文章

Android Binder进程间通信---注册Service组件---发送和处理BC_TRANSACTION

本文参考<Android系统源代码情景分析>,作者罗升阳 一.测试代码: -/Android/external/binder/server ----FregServer.cpp ~/Android/external/binder/common ----IFregService.cpp ----IFregService.h ~/Android/external/binder/client ----FregClient.cpp Binder库(libbinder)代码: ~/Android/fra

Android Binder进程间通信---注册Service组件---启动Binder线程池

本文参考<Android系统源代码情景分析>,作者罗升阳 一.测试代码: -/Android/external/binder/server ----FregServer.cpp ~/Android/external/binder/common ----IFregService.cpp ----IFregService.h ~/Android/external/binder/client ----FregClient.cpp Binder库(libbinder)代码: ~/Android/fra

Android Binder进程间通信---注册Service组件---Server处理BC_TRANSACTION

这是我参照之前在iOS项目中用过的一个不规则形状按钮的第三方Button,这里用Cocos2d-x实现一个相似功能的按钮. 原文地址:http://blog.csdn.net/qqmcy/article/details/26161339 代码下载:http://download.csdn.net/detail/qqmcy/7365843 使用方法: .h // // TestScene.h // maptest // // Created by 杜甲 on 14-5-18. // // #ifn

Android Binder进程间通信---注册Service组件---封装进程间通信数据

本文参考<Android系统源代码情景分析>,作者罗升阳 一.测试代码: -/Android/external/binder/server ----FregServer.cpp ~/Android/external/binder/common ----IFregService.cpp ----IFregService.h ~/Android/external/binder/client ----FregClient.cpp Binder库(libbinder)代码: ~/Android/fra

Android Binder进程间通信---Service代理对象的获取过程

本文参考<Android系统源代码情景分析>,作者罗升阳 一.测试代码: -/Android/external/binder/server ----FregServer.cpp ~/Android/external/binder/common ----IFregService.cpp ----IFregService.h ~/Android/external/binder/client ----FregClient.cpp Binder库(libbinder)代码: ~/Android/fra

Android Binder进程间通信---ServiceManager代理对象的获取过程

本文参考<Android系统源代码情景分析>,作者罗升阳. 一.测试代码: -/Android/external/binder/server ----FregServer.cpp ~/Android/external/binder/common ----IFregService.cpp ----IFregService.h ~/Android/external/binder/client ----FregClient.cpp Binder库(libbinder)代码: ~/Android/fr

Android Binder进程间通信---Binder类图

上传两张Binder类图,有助于理解Binder进程间通信: Android Binder进程间通信---Binder类图

android binder 进程间通信机制5-Service注册和代理对象的获取

ServiceManager,其实也是一个Service,不过它的Server端实现并未使用Binder库的结构实现,而是直接打开binder/dev进行通信的,不具有普遍性. 下面以MediaServer中的MediaPlayService为例,说明更加普遍的使用binder通信机制的Service的实现. 一.Service组件的启动 Service组件是在Server进程中运行的,Server进程通常从其main函数启动,启动时通常做两件事: 1.首先将它里面的Service组件注册到Se

android binder 进程间通信机制6-Binder进程间通信机制的JAVA接口

Binder间进程通信的JAVA层接口,主要是通过JNI方法来调用Binder库的C/C++接口 在JAVA层,将Service组件称为JAVA服务,Service组件的代理称为JAVA服务代理. 一.ServiceManager的Java层代理对象(ServiceManagerProxy)的获取过程. 个人感觉JAVA层的ServiceManager的Java服务和Java服务代理的实现结构还是很像的,如下: Java服务类关系图: java服务代理的类关系图: ServiceManager代