一、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 ManagerClient找到目标进程:根据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实现:
C++实现:
2、Binder进程间通信传输数据图
java实现:
C++实现:
3、最终的代理对象和本地对象的类继承图
java层:
C++层:
六、传递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再一次睡眠等待。