zoukankan      html  css  js  c++  java
  • Binder机制,从Java到C (9. IPC通信过程)

    1.一次IPC通信過程的幾個步驟

    一次通信过程简单的说有下面5个步骤,第一眼看上去,肯定不知道什么玩意,多看几遍,慢慢看,其实是能理解的。

    1. Client将数据封装成Parcel。 前面已经讲过啦

    2. Client process 发送 BC_TRANSACTION 命令协议到kernel,Client跟kernel说,我要开始远程通信啦

    kernel找到Service process後,向Client process发送一个BR_TRANSACTION_COMPLETE返回协议,表示通信请求已被接受。kernel说,准了

    Client处理后,开始等待service的返回结果。client收到“准了”,然后默默等待,或者也可以干点其他什么事情

    3. kernal同時發送 BR_TRANSACTION 返回协议到Service process,请求service处理。kernel就去找client要找的人,跟他说,有人在请求你的服务

    4. Service process 处理了 BR_TRANSACTION 返回协议,发送BC_REPLY命令协议到kernel,server跟kernel说,我做完了,这是结果

    kernel找到client process後,向service发送 BR_TRANSACTION_COMPLETE返回协议,表示返回的通信就结果收到了,(kernel说,结果我收到啦)

    service处理后,就开始等待下一个请求。service做完事情,又默默的等着了

    5 kernel同時发送 BR_REPLY 返回协议到Client process,并将结果返回。kernel把结果返回给client
        Client process 处理BR_REPLAY返回协议,获得reply数据,结束通信。client收到结果,大功告成!

    下面就开始一步步详细的分析每一步的流程,会有一点烦躁

    2.一次IPC通信過程的代码流程

    Service需要注册到ServiceManager,也就是addService的IPC通信过程:
    1.将数据封装成Parcel:
    看一下MediaPlayerService的注册代码
    ./frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

    1 void MediaPlayerService::instantiate() {
    2     defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());
    3 }

    这个的defaultServiceManager()返回的其实是Service Manager代理对象BpServiceManager,实际上是调用了BpServiceManager的addService。

    那就看一下这个addService():


    ./frameworks/native/libs/binder/IServiceManager.cpp

     1 class BpServiceManager : public BpInterface<IServiceManager>
     2 {
     3 Public:
     4  5     virtual status_t addService(const String16& name, const sp<IBinder>& service,
     6             bool allowIsolated)
     7     {
     8         Parcel data, reply;
     9         data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    10         data.writeString16(name); //service的名称
    11         data.writeStrongBinder(service); //将IBinder object 封装成一个flat_binder_object写进parcel,传递給Binder驱动。
    12         data.writeInt32(allowIsolated ? 1 : 0);
    13         status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
    14         return err == NO_ERROR ? reply.readExceptionCode() : err;
    15     }
    16 17 };

    Parcel內部有mData和mObjects两个缓冲区
    mData:包含整数,字符串或者Binder对象(flat_binder_object)
    mObjects:记录了mData中Binder对象的位置。

    我们看一下怎么把一个Binder对象写进结构体flat_binder_object的:

    writeStrongBinder的实现:
    ./frameworks/native/libs/binder/Parcel.cpp

     1 status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
     2 {
     3     return flatten_binder(ProcessState::self(), val, this);
     4 }
     5 
     6 status_t flatten_binder(const sp<ProcessState>& proc,
     7     const sp<IBinder>& binder, Parcel* out)
     8 {
     9     flat_binder_object obj;//定义一个结构体
    10 
    11     obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; //0x7f表示Server线程的优先级不能低于0x7f
    12     if (binder != NULL) {
    13         IBinder *local = binder->localBinder();
    14         if (!local) {
    15             ...
    16         } else {//我们要注册MediaPlayerService,传进来的是Binder本地对象
    17             obj.type = BINDER_TYPE_BINDER; //所以把type写成Binder本地对象
    18             obj.binder = local->getWeakRefs(); //weekref
    19             obj.cookie = local; //Binder本地对象local的地址值
    20         }
    21     } else {
    22         ...
    23     }
    24 
    25     return finish_flatten_binder(binder, obj, out); //将flat_binder_object写到Parcel中。
    26 }

    2.发送和处理BC_TRANSACTION命令协议
     remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
    前面说过,这里的remote()是一个BpBinder对象,调用的代码是:

    ./frameworks/native/libs/binder/BpBinder.cpp

     1 status_t BpBinder::transact(
     2     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
     3 {
     4     // Once a binder has died, it will never come back to life.
     5     if (mAlive) {
     6         status_t status = IPCThreadState::self()->transact(
     7             mHandle, code, data, reply, flags);
     8 //mHandle 是这个Binder代理对象的句柄值,现在Binder代理对象是ServiceManager代理对象,so mHandle = 0;
     9 //code :ADD_SERVCIE_TRANSACTION
    10 //data: 要传递给Binder驱动的通信数据
    11 //reply: 输出參數,保存通信結果
    12 //flags:描述是同步还是异步,默认是同步
    13         if (status == DEAD_OBJECT) mAlive = 0;
    14         return status;
    15     }
    16 
    17     return DEAD_OBJECT;
    18 }

    下面就要调用transact()了:

    .framework/native/libs/binder/IPCThreadState.cpp

     1 status_t IPCThreadState::transact(int32_t handle,
     2                                   uint32_t code, const Parcel& data,
     3                                   Parcel* reply, uint32_t flags)
     4 {
     5     status_t err = data.errorCheck();
     6     ...
     7     if (err == NO_ERROR) {
     8         ...
     9         err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); (1)
    10     }
    11     ...
    12     if ((flags & TF_ONE_WAY) == 0) { //判断是否是同步通信,如果是,reply不为null。
    13        ...
    14         if (reply) {
    15             err = waitForResponse(reply); //发送BC_TRANSACTION命令协议。
    16         } else {
    17             ...
    18         }
    19        ...
    20     return err;
    21 }
    22 
    23 
    24 status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
    25 {
    26     int32_t cmd;
    27     int32_t err;
    28 
    29     while (1) {
    30         if ((err=talkWithDriver()) < NO_ERROR) break; //循环调用talkWithDriver()和Binder驱动程序交互
    31         ...
    32     }
    33 34     Return err;
    35 } 
     

    (1) BC_TRANSACTION命令协议后面跟的数据是使用一个struct binder_transaction_data描述的。这里要把parcel写入到这个struct中。这个struct添加到IPCThreadState的成员变量mOut中,表示有命令需要发送。

    下面图是mOut里的一条命令的储存格式:

     target.handle 就是代表了servicemanager

    code  在后面用来区分到底是要调用那个函数

    data_size  不用说,就是数据大小

    data.ptr.buffer 是存储的数据,有一般数据和binder数据

    offsets_size   偏移数组的大小

    data.ptr.offsets  binder数据在整个数据中的偏移位置,加上上面偏移数组的大小,就可以知道读出每个binder对象了。

    接着看,和Binder驱动开始交互了:

    .framework/native/libs/binder/IPCThreadState.cpp

     1 status_t IPCThreadState::talkWithDriver(bool doReceive) //mIn保存返回协议,mOut保存命令命令
     2 {
     3    ...
     4     binder_write_read bwr; //BC_TRANSACTION是通过IO控制命令BINDER_WRITE_READ发送到Binder驱动的,所以上文中的binder_transaction_data
                                         要写入binder_write_read结构体中。 里面的read_buffer/write_buffer对应mIn/mOut
    5 const bool needRead = mIn.dataPosition() >= mIn.dataSize(); 6 const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; 7 8 bwr.write_size = outAvail; 9 bwr.write_buffer = (long unsigned int)mOut.data(); 10 11 if (doReceive && needRead) { 12 bwr.read_size = mIn.dataCapacity(); 13 bwr.read_buffer = (long unsigned int)mIn.data(); 14 } else { 15 bwr.read_size = 0; 16 bwr.read_buffer = 0; 17 } 18 ... 19 if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR; 20 21 bwr.write_consumed = 0; 22 bwr.read_consumed = 0; 23 status_t err; 24 do { 25 ... 26 if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) //这里会调用kernel binder module的binder_thread_write()
                                                                                 和binder_thread_read()來处理命令和返回結果。
    27 err = NO_ERROR; 28 else 29 err = -errno; 30 ... 31 mOut.remove(0, bwr.write_consumed); //將已经处理的命令移除 32 ... 33 mIn.setDataSize(bwr.read_consumed); //将读取出來的返回协议保存在mIn中,在返回到前面的waitForResponse時,就可以解析mIn的內容了。 34 mIn.setDataPosition(0); 35 36 }

    上面的 ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)

    代码实现是在 .kernel/.../android/binder.c,不再android代码范畴了,就不详细列出了,下面是在kernel里处理的步骤:

    ------------------------------------------------------------------------------------
    1.从参数中读取BC_TRANSACTION命令协议和binder_transaction_data

    2.根据binder_transaction_data中的target.handle找到target Binder实体对象(kernel中记录binder的形式,实体对象是用binder_node记录)。
       根据target Binder实体对象找到Server process

    3.处理数据中的binder对象(flat_binder_object),凡是传递的binder对象,都会在kernel留下蛛丝马迹。
       如果这个binder对象是在kernel中第一次遇见,那么会为它创建Binder实体对象(binder_node)或者Binder引用对象(binder_ref)。
       如果kernel中可以找到这个binder对象,就获取它。

    4.将一个BINDER_WORK_TRANSACTION_COMPLETE工作项添加到Client process(media player)队列中处理。
       同时将一个BINDER_WORK_TRANSACTION工作项添加到Server process(service manager)队列中处理。
       这两个工作项是并行处理的。

    5.处理BINDER_WORK_TRANSACTION_COMPLETE工作项,将一个BR_TRANSACTION_COMPLETE返回协议发送到Client process中,把返回协议写到mIn中。
    -------------------------------------------------------------------------------------------------------------

    现在已经返回到IPCThreadState的talkWithDriver()。又返回到waitForResponse()中,处理BR_TRANSACTION_COMPLETE。
    然后开始等待Server process返回结果。

    3.发送和处理BR_TRANSACTION返回協議
    在前面处理BC_TRANSACTION中,会并行将一个BINDER_WORK_TRANSACTION工作项添加到Server process(service manager)队列中处理。

    接着kernel中会处理上面的工作项:

    1.kernel根据BINDER_WORK_TRANSACTION工作项,向Server process发送了一个BR_TRANSACTION返回协议。
    2.Server process,现在就是servicemanager,被唤醒后,会调用binder_parse()处理返回协议。
    3.servicemanager分局参数,判断执行操作SVC_MGR_ADD_SERVICE。调用对应的函數do_add_service(),为要注册的Service创建svcinfo结构提,并添加到全局队列svclist中。以后要查找这个service的时候,就从svclist中找了。


    binder_parse()之后的函数在下面的文件中:
    ./frameworks/base/cmds/servicemanager/binder.c
    ./frameworks/base/cmds/servicemanager/service_manager.c

    4.发送和处理BC_REPLY命令协议

    servicemanager进程注册成功后,就会通过IO控制命令BINDER_WRITE_READ将BC_REPLY发送到kernel
    /frameworks/base/cmds/servicemanager/binder.c

     1 int binder_write(struct binder_state *bs, void *data, unsigned len)
     2 {
     3     struct binder_write_read bwr;
     4     int res;
     5     bwr.write_size = len;
     6     bwr.write_consumed = 0;
     7     bwr.write_buffer = (unsigned) data;
     8     bwr.read_size = 0;
     9     bwr.read_consumed = 0;
    10     bwr.read_buffer = 0;
    11     res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    12     if (res < 0) {
    13         fprintf(stderr,"binder_write: ioctl failed (%s)
    ",
    14                 strerror(errno));
    15     }
    16     return res;
    17 }

    之后的,都是在Kernel中完成的操作,在kernel中的处理:
    1.读取BC_REPLY命令协议。
    2.找到target process(现在是Client process)。
    3.一个BINDER_WORK_TRANSACTION_COMPLETE工作项添加到servicemanager process队列中处理。
      同时将一个BINDER_WORK_TRANSACTION工作项添加到Client process队列中处理。
       这两个工作项是并行处理的。
    4.处理BINDER_WORK_TRANSACTION_COMPLETE工作项,将一个BR_TRANSACTION_COMPLETE返回协议发送到servicemanager中。

    servicemanager处理完BR_TRANSACTION_COMPLETE后,就又开始等待新的进程间通信请求了。

    5.发送和处理BR_REPLY返回协议

    在前面处理BC_REPLY中,会并行将一个BINDER_WORK_TRANSACTION工作项添加到Client process队列中处理。

    接着kernel中会处理上面的工作項:

    1.kernel根据BINDER_WORK_TRANSACTION工作項,向Client process發送了一個BR_REPLY返回协议。

    Client process返回到IPCThreadState的talkWithDriver(),再回到waitForResponse中处理BR_REPLY。

    waitForResponse()中將返回的結果取出,保存在Parcel對象reply中。之後,就跳出循环,結束該方法。Service的註冊過程就執行完了。


    Service註冊之後,就会启动Binder thread pool,等待client的請求。
    此時Service不是在注册的時候作为Client请求servicemanager的服务了。而是作为Service处理收到的请求。收到请求后会通过executeCommand()來处理。

  • 相关阅读:
    asp.net后台获取html控件的值
    asp.net自定义错误页面
    关于asp.net网站中web.config的配置
    在asp.net中如何使用Session
    Ubuntu 14.10 进入单用户模式
    原码,反码和补码
    利用位运算进行权限管理
    php redis扩展安装
    不同浏览器Cookie大小
    include和require的区别
  • 原文地址:https://www.cnblogs.com/zhangxinyan/p/3487905.html
Copyright © 2011-2022 走看看