Andorid Binder进程间通信总结

一、Server和Service Manager进程间通信

        Service Manager进程启动时,已经创建了Service Manager实体对象,没有Service Manager本地对象。

        Server首先获取了Server代理对象,句柄值为0。没有Server引用对象。

        Server----->Service Manager

        Server找到目标进程:根据Server代理对象的句柄值0,找到Service Manager实体对象,然后找到Service Manger进程,也就是目标进程。

        Server传递的数据:包含flat_binder_object结构体,其中handle为Service Manager的引用对象的句柄值,Service Manager的引用对象引用了Server的实体对象,Server的实体对象又引用了Server的本地对象。(binder_transaction函数case BINDER_TYPE_BINDER)。

        Service Manager处理数据:svcinfo结构体ptr为Servicer Manager的引用对象句柄值,name为传递进来的字符串。

        Service Manager----->Server

        Service Manager找到目标进程:根据thread->transaction_stack->from找到目标进程,即Server进程。

        Service Manager传递的数据:返回正确值0。

        Server处理数据:Server循环等待。


二、Client和Service Manager进程间通信

        Service Manager进程启动时,已经创建了Service Manager实体对象,没有Service Manager的本地对象。

        Client首先获取了Client代理对象,句柄值为0。没有Client引用对象。

         Client----->Service Manager

        Client找到目标进程:根据Client进程代理对象的句柄值0,找到Service Manager实体对象,然后找到Service Manger进程,也就是目标进程。

        Client传递的数据:svcinfo 结构体name那个字符串。

        Service Manager处理数据:获得binder_object结构体,其中pointer指向了Service Manager的引用对象(引用了Server的实体对象)的句柄值。

        Service Manager----->Client

        Service Manager找到目标进程:根据thread->transaction_stack->from找到目标进程,即Client进程。

        Service Manager传递的数据:传递的内容flat_binder_object结构体,handle为Client的引用对象(引用了Server的实体对象)的句柄值。(binder_transaction函数case BINDER_TYPE_HANDLE)。

        Client处理数据:返回Client代理对象(句柄值是上面Client引用对象的句柄值)。


三、Client和Server进程间通信

       目前已经获取了Client代理对象,Client引用对象,Server实体对象,Server本地对象。

       Client----->Server

       Client找到目标进程:根据Client代理对象的句柄值,首先找到Client引用对象,通过Client引用对象再找到Server的实体对象,通过Server实体对象,找到Server进程,也就是目标进程。

       Client传递的数据:一个用于匹配的描述符。和例如GET_VALUE命令。

       Server处理数据:根据找到的Server实体对象,找到Server本地对象,利用Server本地对象来执行GET_VALUE命令获取值

       Server----->Client

       Server找到目标进程:根据thread->transaction_stack->from找到目标进程,即Client进程。

       Server传递的数据:传递的数据返回值是getVal获取的值(利用Server本地对象来执行GET_VALUE命令获取值)。

       Client处理数据:把上面返回的结果读取出来。


四、Client端向Server端发送数据时,数据是存放在Server端的内核缓冲区中,Client完成把数据从用户空间拷贝到Server端的内核缓冲区;在Server端通过user address space就能访问缓冲区的内容。因为user address sapce和kernel address space都映射到缓冲区。他们之间存在一个固定的偏移。所以Client端向Server端传递数据只是一次拷贝。



五、附图

      1、Binder引用对象和实体对象在进程间通信的作用

      java实现:

Andorid Binder进程间通信总结_第1张图片


       C++实现:

Andorid Binder进程间通信总结_第2张图片

  

      2、Binder进程间通信传输数据图

      java实现:

Andorid Binder进程间通信总结_第3张图片

        C++实现:

Andorid Binder进程间通信总结_第4张图片


     3、最终的代理对象和本地对象的类继承图

     java层:

Andorid Binder进程间通信总结_第5张图片


      C++层:

Andorid Binder进程间通信总结_第6张图片


六、传递Binder对象

switch (fp->type) {
		case BINDER_TYPE_BINDER:
		case BINDER_TYPE_WEAK_BINDER: {
			struct binder_ref *ref;
			struct binder_node *node = binder_get_node(proc, fp->binder);
			if (node == NULL) {
				node = binder_new_node(proc, fp->binder, fp->cookie);
				if (node == NULL) {
					return_error = BR_FAILED_REPLY;
					goto err_binder_new_node_failed;
				}
				node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
				node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
			}
			if (fp->cookie != node->cookie) {
				binder_user_error("binder: %d:%d sending u%p "
					"node %d, cookie mismatch %p != %p\n",
					proc->pid, thread->pid,
					fp->binder, node->debug_id,
					fp->cookie, node->cookie);
				goto err_binder_get_ref_for_node_failed;
			}
			ref = binder_get_ref_for_node(target_proc, node);
			if (ref == NULL) {
				return_error = BR_FAILED_REPLY;
				goto err_binder_get_ref_for_node_failed;
			}
			if (fp->type == BINDER_TYPE_BINDER)
				fp->type = BINDER_TYPE_HANDLE;
			else
				fp->type = BINDER_TYPE_WEAK_HANDLE;
			fp->handle = ref->desc;
			binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);
			if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)
				printk(KERN_INFO "        node %d u%p -> ref %d desc %d\n",
				       node->debug_id, node->ptr, ref->debug_id, ref->desc);
		} break;
		case BINDER_TYPE_HANDLE:
		case BINDER_TYPE_WEAK_HANDLE: {
			struct binder_ref *ref = binder_get_ref(proc, fp->handle);
			if (ref == NULL) {
				binder_user_error("binder: %d:%d got "
					"transaction with invalid "
					"handle, %ld\n", proc->pid,
					thread->pid, fp->handle);
				return_error = BR_FAILED_REPLY;
				goto err_binder_get_ref_failed;
			}
			if (ref->node->proc == target_proc) {
				if (fp->type == BINDER_TYPE_HANDLE)
					fp->type = BINDER_TYPE_BINDER;
				else
					fp->type = BINDER_TYPE_WEAK_BINDER;
				fp->binder = ref->node->ptr;
				fp->cookie = ref->node->cookie;
				binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
				if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)
					printk(KERN_INFO "        ref %d desc %d -> node %d u%p\n",
					       ref->debug_id, ref->desc, ref->node->debug_id, ref->node->ptr);
			} else {
				struct binder_ref *new_ref;
				new_ref = binder_get_ref_for_node(target_proc, ref->node);
				if (new_ref == NULL) {
					return_error = BR_FAILED_REPLY;
					goto err_binder_get_ref_for_node_failed;
				}
				fp->handle = new_ref->desc;
				binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
				if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)
					printk(KERN_INFO "        ref %d desc %d -> ref %d desc %d (node %d)\n",
					       ref->debug_id, ref->desc, new_ref->debug_id, new_ref->desc, ref->node->debug_id);
			}
		} break;
      一、如果是Binder实体对象,那么要转化成Binder引用对象传递给另一个进程。

      二、如果是Binder引用对象,如果Binder引用对象的实体对象的进程,就是目标进程,那么转换成目标进程的Binder实体对象。

      三、如果是Binder引用对象,如果Binder引用对象的实体对象(1)的进程,不是目标进程,那么转换成目标进程的引用对象,这个引用对象指向了实体对象(1)。

      PS:(1)代表了到底是哪个实体对象,上面的第三条,涉及到三个进程。


七、利用Binder同步和异步传输数据

     发送端传输数据:

status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)//注意data是一个引用,reply是一个指针
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);//每个参数的介绍在下面
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }
    return DEAD_OBJECT;
}
status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();

    flags |= TF_ACCEPT_FDS;//flags等于0|TF_ACCEPT_FDS
    .......
    if (err == NO_ERROR) {
        ..........
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);//将data的内容写入到一个binder_transaction_data结构体中
    }
    ........
    if ((flags & TF_ONE_WAY) == 0) {//最后一位为0,按位与TF_ONE_WAY等于0,表示同步的进程间通信请求
        ..........
        if (reply) {//reply不为空,是一个指针
            err = waitForResponse(reply);
        } else {
            .........
        }
        ..........
    } else {
        err = waitForResponse(NULL, NULL);//异步,不需要返回结果,也就没有reply
    }
    
    return err;
}
    我们看在同步和异步请求中,两者的区别在于flags,flags默认为0,表示同步方式。如果flags为TF_ONE_WAY。则为异步方式。

    同步方式指需要得到返回数据,watiForResponse的reply不为空;而异步方式指不需要得到返回数据,waitForResponse的reply为空。

    我们继续看watiForResponse的差异。

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

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
        
        cmd = mIn.readInt32();//读取了BR_TRANSACTION_COMPLETE协议,mIn中就没有数据了
        .....

        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;//reply不为NULL
            break;
        .....
    }
    ........
    return err;
}
     talkWithDriver向目标进程发送了binder_transaction结构体,里面包含了要传输的数据,其type为 BC_TRANSACTION;向本进程也发送了 binder_transaction结构体,其type为BR_TRANSACTION_COMPLETE。

    此时同步和异步两种方式的区别出来了,当reply不为空时,那么会再次执行talkWithDriver,会在binder_thread_read再一次睡眠等待目标进程发给它reply。

    如果reply为空,那么就直接返回了,不会继续等待。


    接收端接收数据:

void IPCThreadState::joinThreadPool(bool isMain)//默认值为true
{
    .........

    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);//isMain为true,BC_ENTER_LOOPER
    
    ........
        
    status_t result;
    do {
        int32_t cmd;
        
        .......
        result = talkWithDriver();//将自己注册到Binder线程池中,一个无线循环中不断等待进程间通信请求
        if (result >= NO_ERROR) {
            size_t IN = mIn.dataAvail();
            if (IN < sizeof(int32_t)) continue;
            cmd = mIn.readInt32();
            ........


            result = executeCommand(cmd);//处理进程间通信请求
        }
        
       .........
        if(result == TIMED_OUT && !isMain) {//一直为false,因为isMain为true
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);

    ........
    
    mOut.writeInt32(BC_EXIT_LOOPER);//退出Binder线程池
    talkWithDriver(false);
}

     接收端在talkWithDriver中binder_thread_read睡眠等待,发送端进程,发送BC_REPLY,唤醒接收进程。程序逐层返回,最终返回到executeCommand函数,继续执行函数sendReply,实现如下:

status_t IPCThreadState::executeCommand(int32_t cmd){
case BR_TRANSACTION:
        {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));
            LOG_ASSERT(result == NO_ERROR,
                "Not enough command data for brTRANSACTION");
            if (result != NO_ERROR) break;
            
            Parcel buffer;
            buffer.ipcSetDataReference(
                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);
            
            const pid_t origPid = mCallingPid;
            const uid_t origUid = mCallingUid;
            
            mCallingPid = tr.sender_pid;
            mCallingUid = tr.sender_euid;
            
            .....
            if (tr.target.ptr) {
                sp<BBinder> b((BBinder*)tr.cookie);
                const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);

            } else {
                const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);
            }
            
            //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
            //     mCallingPid, origPid, origUid);
            
            if ((tr.flags & TF_ONE_WAY) == 0) {
                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                sendReply(reply, 0);
            } else {
                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
            }
            
            .....
            
        }
        break;
}
     如果是异步发送过来的,直接结束executeCommand,返回到talkWithDriver中的binder_thread_read继续睡眠等待。

     如果是同步发送过来的,那么则执行sendReply,最后的结果也是在talkWithDriver中的binder_thread_read继续睡眠等待。

status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)//flags为0
{
    status_t err;
    status_t statusBuffer;
    err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
    if (err < NO_ERROR) return err;
    
    return waitForResponse(NULL, NULL);
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    int32_t cmd;
    int32_t err;

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
        
        cmd = mIn.readInt32();//读取了BR_TRANSACTION_COMPLETE协议,mIn中就没有数据了
        .....

        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;//reply为NULL
            break;
        .....
    }
    ........
    return err;
}
     在talkWithDriver中 binder_thread_write,首先向接收端发送 binder_transaction结构体,里面包含了要传输的数据,其type为 BC_REPLY。然后在binder_thread_read读入本进程的binder_transaction结构体,其type为BR_TRANSACTION_COMPLETE。由于reply为NULL,那么退出waitForResponse,继续退出sendReply,然后返回do while循环,在talkWithDriver时,在binder_thread_read再一次睡眠等待。

你可能感兴趣的:(Andorid Binder进程间通信总结)