转: IBinder对象在进程间传递的形式

原地址:http://blog.csdn.net/windskier/article/details/6625883

当service经常被远程调用时,我们常常用到aidl来定一个接口供service和client来使用,这个其实就是使用Binder机制的IPC通信。当client bind service成功之后,系统AM会调用回调函数onServiceConnected将service的IBinder传递给client, client再通过调用aidl生成的asInterface()方法获得service的调用接口,此时一个bind过程结束了,我们在client端就可以远程调用service的方法了。例如

  1. public void onServiceConnected(ComponentName className,  
  2.         IBinder service) {  
  3.     mSecondaryService = ISecondary.Stub.asInterface(service);  
  4. }  

    我们再看aidl生成的asInterface()的定义

  1. public static com.example.android.apis.app.ISecondary asInterface(android.os.IBinder obj)  
  2. {  
  3. if ((obj==null)) {  
  4. return null;  
  5. }  
  6. android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
  7. if (((iin!=null)&&(iin instanceof com.example.android.apis.app.ISecondary))) {  
  8. return ((com.example.android.apis.app.ISecondary)iin);  
  9. }  
  10. return new com.example.android.apis.app.ISecondary.Stub.Proxy(obj);  
  11. }  


    首先,asInterface()会去query传入的IBinder对象是否有LocalInterface,这里的LocalInterface是指传入的IBinder是service本身的引用还是代理。
    1.当asInterface的输入的IBinder为server的引用(Binder类型)时,则直接返回该引用,那么此时调用server的方法不为IPC通信,而是直接的函数调用;
    2.当asInterface的输入的IBinder为server的代理(BinderProxy类型)时,则需要创建该server的代理并返回,此时调用server的方法为IPC通信。

    那么以上两种情况发生的条件是什么呢?这里我们先给出答案,然后再深入到代码中去研究2种不同的情况。
    1.当client和service处在相同进程中的话,asInterface的输入的IBinder为server的引用时;
    2.当client和service处在不同进程中的话,asInterface的输入的IBinder为server的代理。

在研究上述实现代码之前,我们先介绍一下IBinder作为参数使用IPC进程间传递时的状态变化,其实这个就是我们本篇文章的核心内容,理解了这个机制,我们就会很容易理解我们上述的那个命题的原理了。



    模型


    IBinder作为参数在IPC通信中进行传递,可能会使某些人困惑,IBinder不就是IPC通信的媒介吗?怎么还会被作为参数来传递呢,这样理解就有点狭隘了,拿native层的IPC来说,client从SM(service manager)中获取service端的Interface,这个Interface同时也是IBinder类型,当C/S两端需要双工通信时,即所谓的Service端需要反过来调用Client端的方法时,就需要client通过前述的那个Interface将Client端的IBinder传递给Service。
    拿Java应用层的Service来说更是如此,如本文的这个命题,下面我们会分析,首先来介绍原理性的知识。
    Binder IPC通信中,Binder是通信的媒介,Parcel是通信的内容。方法远程调用过程中,其参数都被打包成Parcel的形式来传递的。IBinder对象也不例外,我们看一下Parcel类中的writeStrongBinder()(由于java层和native层的方法是相对应的,java层只是native的封装,因此我们只需要看native的即可),

  1. status_t Parcel::writeStrongBinder(const sp<IBinder>& val)  
  2. {  
  3.     return flatten_binder(ProcessState::self(), val, this);  
  4. }  

  1. status_t flatten_binder(const sp<ProcessState>& proc,  
  2.     const sp<IBinder>& binder, Parcel* out)  
  3. {  
  4.     flat_binder_object obj;  
  5.       
  6.     obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;  
  7.     if (binder != NULL) {  
  8.         IBinder *local = binder->localBinder();  
  9.         if (!local) {  
  10.             BpBinder *proxy = binder->remoteBinder();  
  11.             if (proxy == NULL) {  
  12.                 LOGE("null proxy");  
  13.             }  
  14.             const int32_t handle = proxy ? proxy->handle() : 0;  
  15.             obj.type = BINDER_TYPE_HANDLE;  
  16.             obj.handle = handle;  
  17.             obj.cookie = NULL;  
  18.         } else {  
  19.             obj.type = BINDER_TYPE_BINDER;  
  20.             obj.binder = local->getWeakRefs();  
  21.             obj.cookie = local;  
  22.         }  
  23.     } else {  
  24.         obj.type = BINDER_TYPE_BINDER;  
  25.         obj.binder = NULL;  
  26.         obj.cookie = NULL;  
  27.     }  
  28.       
  29.     return finish_flatten_binder(binder, obj, out);  
  30. }  

上面代码分下面2种情况
1. 如果传递的IBinder为service的本地IBinder对象,那么该IBinder对象为BBinder类型的,因此上面的local不为NULL,故binder type为BINDER_TYPE_BINDER。
2. 如果传递的IBinder对象代理IBinder对象,那么binder type则为BINDER_TYPE_HANDLE。

client端将方法调用参数打包成Parcel之后,会发送到内核的Binder模块,因此下面我们将分析一下内核的Binder模块的处理。

kernel/drivers/staging/android/Binder.c中的函数binder_transaction()


  1. switch (fp->type) {  
  2.         case BINDER_TYPE_BINDER:  
  3.         case BINDER_TYPE_WEAK_BINDER: {  
  4.             struct binder_ref *ref;  
  5.             struct binder_node *node = binder_get_node(proc, fp->binder);  
  6.             if (node == NULL) {  
  7.                 node = binder_new_node(proc, fp->binder, fp->cookie);  
  8.                 if (node == NULL) {  
  9.                     return_error = BR_FAILED_REPLY;  
  10.                     goto err_binder_new_node_failed;  
  11.                 }  
  12.                 node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;  
  13.                 node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);  
  14.             }  
  15.             if (fp->cookie != node->cookie) {  
  16.                 binder_user_error("binder: %d:%d sending u%p "  
  17.                     "node %d, cookie mismatch %p != %p\n",  
  18.                     proc->pid, thread->pid,  
  19.                     fp->binder, node->debug_id,  
  20.                     fp->cookie, node->cookie);  
  21.                 goto err_binder_get_ref_for_node_failed;  
  22.             }  
  23.             ref = binder_get_ref_for_node(target_proc, node);  
  24.             if (ref == NULL) {  
  25.                 return_error = BR_FAILED_REPLY;  
  26.                 goto err_binder_get_ref_for_node_failed;  
  27.             }  
  28.             if (fp->type == BINDER_TYPE_BINDER)  
  29.                 fp->type = BINDER_TYPE_HANDLE;  
  30.             else  
  31.                 fp->type = BINDER_TYPE_WEAK_HANDLE;  
  32.             fp->handle = ref->desc;  
  33.             binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,  
  34.                        &thread->todo);  
  35.   
  36.             binder_debug(BINDER_DEBUG_TRANSACTION,  
  37.                      "        node %d u%p -> ref %d desc %d\n",  
  38.                      node->debug_id, node->ptr, ref->debug_id,  
  39.                      ref->desc);  
  40.         } break;  
  41.         case BINDER_TYPE_HANDLE:  
  42.         case BINDER_TYPE_WEAK_HANDLE: {  
  43.             struct binder_ref *ref = binder_get_ref(proc, fp->handle);  
  44.             if (ref == NULL) {  
  45.                 binder_user_error("binder: %d:%d got "  
  46.                     "transaction with invalid "  
  47.                     "handle, %ld\n", proc->pid,  
  48.                     thread->pid, fp->handle);  
  49.                 return_error = BR_FAILED_REPLY;  
  50.                 goto err_binder_get_ref_failed;  
  51.             }  
  52.             if (ref->node->proc == target_proc) {  
  53.                 if (fp->type == BINDER_TYPE_HANDLE)  
  54.                     fp->type = BINDER_TYPE_BINDER;  
  55.                 else  
  56.                     fp->type = BINDER_TYPE_WEAK_BINDER;  
  57.                 fp->binder = ref->node->ptr;  
  58.                 fp->cookie = ref->node->cookie;  
  59.                 binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);  
  60.                 binder_debug(BINDER_DEBUG_TRANSACTION,  
  61.                          "        ref %d desc %d -> node %d u%p\n",  
  62.                          ref->debug_id, ref->desc, ref->node->debug_id,  
  63.                          ref->node->ptr);  
  64.             } else {  
  65.                 struct binder_ref *new_ref;  
  66.                 new_ref = binder_get_ref_for_node(target_proc, ref->node);  
  67.                 if (new_ref == NULL) {  
  68.                     return_error = BR_FAILED_REPLY;  
  69.                     goto err_binder_get_ref_for_node_failed;  
  70.                 }  
  71.                 fp->handle = new_ref->desc;  
  72.                 binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);  
  73.                 binder_debug(BINDER_DEBUG_TRANSACTION,  
  74.                          "        ref %d desc %d -> ref %d desc %d (node %d)\n",  
  75.                          ref->debug_id, ref->desc, new_ref->debug_id,  
  76.                          new_ref->desc, ref->node->debug_id);  
  77.             }  
  78.         } break;  

    上面代码也分为了2种不同的分支:
    1. 传来的IBinder类型为BINDER_TYPE_BINDER时,会将binder type值为BINDER_TYPE_HANDLE;
    2. 传来的IBinder类型为BINDER_TYPE_HANDLE时,会判断该IBinder的实体被定义的进程(也就是该IBinder代表的server被定义的进程)与目标进程(也即IBinder被传递的目标进程)是否相同,如果相同,则将该IBinder type转化为BINDER_TYPE_BINDER,同时使其变为IBinder本地对象的引用。
    通过上述的处理,我们可以得出下面结论:
    1.不同进程间传递的IBinder本地对象引用(BINDER_TYPE_BINDER类型),在内核中均会被转化为代理(BINDER_TYPE_HANDLE类型,目前只是改变其类型,在IBinder接收方会根据其类型转化为代理);
    2.由于只有不同进程间传递才会将IBinder发送到Binder模块,所以IBinder在多级传递的过程中,有下面2种可能 进程A-->进程B-->进程A,进程A-->进程B-->进程C;其对应的IBinder类型就是BINDER_TYPE_BINDER-->BINDER_TYPE_HANDLE-->BINDER_TYPE_BINDER,BINDER_TYPE_BINDER-->BINDER_TYPE_HANDLE-->BINDER_TYPE_HANDLE。
    根据上述结论,我们就会明白Binder IPC通信过程中,相同进程间的IBinder本地对象,如果不经过不同进程的传递,那么IBinder就不会传给内核的Binder模块,因此它一直是IBinder的本地对象;如果在进程间传递,即使通过再多的进程间的传递,只要最后的目标是同一个进程的component,那么他得到的IBinder对象就是本地的对象。

          

   



    套用模型

    理解了上面的这个模型,我们再回过头看最开始的那个命题结论就很好理解了
    1.当client和service处在相同进程中的话,asInterface的输入的IBinder为server的引用时;
    2.当client和service处在不同进程中的话,asInterface的输入的IBinder为server的代理。

    假如某一个component(例如一个Acitivity)处在进程A,它需要bind一个service,而该service处在进程B中,我们简单介绍一下bind的过程。
    1. 进程A向AM(进程system_server)发出Bind请求,并将回调ServiceConnection提供给AM(传递给AM的也是一个接口(IServiceConnection),因为AM与A之间是双工通信,所以A需要向AM提供IBinder);
    2. AM启动进程B并创建service,进程B将service的IBinder对象传递给AM,AM再通过IServiceConnection传递给进程A。所以service的IBinder对象的传递路径为:进程B-->进程system_server(AM)-->进程A。

    套用上面的模型,就会得出本文最开始命题的结论。

    便于理解下图给出里bind 一个service的过程



.binder通信概述

    binder通信是一种client-server的通信结构,
   
1.从表面上来看,是client通过获得一个server的代理接口,对server进行直接调用;
   
2.实际上,代理接口中定义的方法与server中定义的方法是一一对应的;
   
3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;
   
4.代理接口将该Parcel发送给内核中的binder driver.
   
5.server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回;
   
6.整个的调用过程是一个同步过程,在server处理的时候,clientblock住。

 

 

 

2.service manager

Service Manager是一个linux级的进程,顾名思义,就是service的管理器。这里的service是什么概念呢?这里的service的概念和init过程中init.rc中的service是不同,init.rc中的service是都是linux进程,但是这里的service它并不一定是一个进程,也就是说可能一个或多个service属于同一个linux进程。在这篇文章中不加特殊说明均指android native端的service

任何service在被使用之前,均要向SM(Service Manager)注册,同时客户端需要访问某个service时,应该首先向SM查询是否存在该服务。如果SM存在这个service,那么会将该servicehandle返回给clienthandle是每个service的唯一标识符。
   

    SM的入口函数在service_manager.c中,下面是SM的代码部分
int main(int argc, char **argv)

{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);

    if (binder_become_context_manager(bs)) {
        LOGE("cannot become context manager (%s)/n", strerror(errno));
        return -1;
    }

    svcmgr_handle = svcmgr;
    binder_loop(bs, svcmgr_handler);
    return 0;
}

这个进程的主要工作如下:
   
1.初始化binder,打开/dev/binder设备;在内存中为binder映射128K字节空间;
   
2.指定SM对应的代理binderhandle0,当client尝试与SM通信时,需要创建一个handle0的代理binder,这里的代理binder其实就是第一节中描述的那个代理接口;

3.通知binder driver(BD)使SM成为BDcontext manager
4.
维护一个死循环,在这个死循环中,不停地去读内核中binder driver,查看是否有可读的内容;即是否有对service的操作要求, 如果有,则调用svcmgr_handler回调来处理请求的操作。

5.SM维护了一个svclist列表来存储service的信息。

 



这里需要声明一下,当service在向SM注册时,该service就是一个client,而SM则作为了server。而某个进程需要与service通信时,此时这个进程为clientservice才作为server。因此service不一定为server,有时它也是作为client存在的。

 

由于下面几节会介绍一些与binder通信相关的几个概念,所以将SM的功能介绍放在了后面的部分来讲。

应用和service之间的通信会涉及到2binder通信。

1.
应用向SM查询service是否存在,如果存在获得该service的代理binder,此为一次binder通信;
2.
应用通过代理binder调用service的方法,此为第二次binder通信。

3.ProcessState

ProcessState是以单例模式设计的。每个进程在使用binder机制通信时,均需要维护一个ProcessState实例来描述当前进程在binder通信时的binder状态。
   
ProcessState有如下2个主要功能:
   
1.创建一个thread,该线程负责与内核中的binder模块进行通信,称该线程为Pool thread
   
2.为指定的handle创建一个BpBinder对象,并管理该进程中所有的BpBinder对象。

 

3.1 Pool thread

            在Binder IPC中,所有进程均会启动一个thread来负责与BD来直接通信,也就是不停的读写BD,这个线程的实现主体是一个IPCThreadState对象,下面会介绍这个类型。

            下面是 Pool thread的启动方式:

ProcessState::self()->startThreadPool();

3.2 BpBinder获取

BpBinder主要功能是负责clientBD发送调用请求的数据。它是clientbinder通信的核心对象,通过调用transact函数向BD发送调用请求的数据,它的构造函数如下:

BpBinder(int32_t handle);
   
通过BpBinder的构造函数发现,BpBinder会将当前通信中serverhandle记录下来,当有数据发送时,会通知BD数据的发送目标。

ProcessState通过如下方式来获取BpBinder对象:

ProcessState::self()->getContextObject(handle);

在这个过程中,ProcessState会维护一个BpBindervector mHandleToObject,每当ProcessState创建一个BpBinder的实例时,回去查询mHandleToObject,如果对应的handle已经有binder指针,那么不再创建,否则创建binder并插入到mHandleToObject中。
   
ProcessState创建的BpBinder实例,一般情况下会作为参数构建一个client端的代理接口,这个代理接口的形式为BpINTERFACE,例如在与SM通信时,client会创建一个代理接口BpServiceManager.
    
   

4.IPCThreadState

IPCThreadState也是以单例模式设计的。由于每个进程只维护了一个ProcessState实例,同时ProcessState只启动一个Pool thread,也就是说每一个进程只会启动一个Pool thread,因此每个进程则只需要一个IPCThreadState即可。
    Pool thread
的实际内容则为:
    IPCThreadState::self()->joinThreadPool();

 

ProcessState中有2个Parcel成员,mIn和mOut,Pool thread会不停的查询BD中是否有数据可读,如果有将其读出并保存到mIn,同时不停的检查mOut是否有数据需要向BD发送,如果有,则将其内容写入到BD中,总而言之,从BD中读出的数据保存到mIn,待写入到BD中的数据保存在了mOut中。

ProcessState中生成的BpBinder实例通过调用IPCThreadStatetransact函数来向mOut中写入数据,这样的话这个binder IPC过程的client端的调用请求的发送过程就明了了

 

IPCThreadState有两个重要的函数,talkWithDriver函数负责从BD读写数据,executeCommand函数负责解析并执行mIn中的数据。

5.主要基类

5.1基类IInterface

server端提供接口,它的子类声明了service能够实现的所有的方法;


5.2基类IBinder
   
BBinderBpBinder均为IBinder的子类,因此可以看出IBinder定义了binder IPC的通信协议,BBinderBpBinder在这个协议框架内进行的收和发操作,构建了基本的binder IPC机制。
5.3基类BpRefBase
   
client端在查询SM获得所需的的BpBinder后,BpRefBase负责管理当前获得的BpBinder实例。

 

 

6.两个接口类

6.1 BpINTERFACE

如果client想要使用binder IPC来通信,那么首先会从SM出查询并获得serverserviceBpBinder,在client端,这个对象被认为是server端的远程代理。为了能够使client能够想本地调用一样调用一个远程serverserver端需要向client提供一个接口,client在在这个接口的基础上创建一个BpINTERFACE,使用这个对象,client的应用能够想本地调用一样直接调用server端的方法。而不用去关心具体的binder IPC实现。
下面看一下BpINTERFACE的原型:
   
class BpINTERFACE : public BpInterface<IINTERFACE>

    顺着继承关系再往上看
   
template<typename INTERFACE>
    class BpInterface : public INTERFACE, public BpRefBase

    BpINTERFACE分别继承自INTERFACE,和BpRefBase
BpINTERFACE既实现了service中各方法的本地操作,将每个方法的参数以Parcel的形式发送给BD
例如BpServiceManager
    virtual status_t addService(const String16& name, const sp<IBinder>& service)

    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeStrongBinder(service);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }
同时又将BpBinder作为了自己的成员来管理,将BpBinder存储在mRemote中,BpServiceManager通过调用BpRefBaseremote()来获得BpBinder指针。

 

6.2 BnINTERFACE

在定义android native端的service时,每个service均继承自BnINTERFACE(INTERFACEservice name)BnINTERFACE类型定义了一个onTransact函数,这个函数负责解包收到的Parcel并执行client端的请求的方法。

   
顺着BnINTERFACE的继承关系再往上看,
       
class BnINTERFACE: public BnInterface<IINTERFACE>

    IINTERFACEclient端的代理接口BpINTERFACEserver端的BnINTERFACE的共同接口类,这个共同接口类的目的就是保证service方法在C-S两端的一致性。

   
再往上看
       
class BnInterface : public INTERFACE, public BBinder

    同时我们发现了BBinder类型,这个类型又是干什么用的呢?既然每个service均可视为一个binder,那么真正的server端的binder的操作及状态的维护就是通过继承自BBinder来实现的。可见BBinderservice作为binder的本质所在。

   
那么BBinderBpBinder的区别又是什么呢?

   
其实它们的区别很简单,BpBinderclient端创建的用于消息发送的代理,而BBinderserver端用于接收消息的通道。查看各自的代码就会发现,虽然两个类型均有transact的方法,但是两者的作用不同,BpBindertransact方法是向IPCThreadState实例发送消息,通知其有消息要发送给BD;而BBinder则是当IPCThreadState实例收到BD消息时,通过BBindertransact的方法将其传递给它的子类BnSERVICEonTransact函数执行server端的操作。

 

7. Parcel

Parcelbinder IPC中的最基本的通信单元,它存储C-S间函数调用的参数.但是Parcel只能存储基本的数据类型,如果是复杂的数据类型的话,在存储时,需要将其拆分为基本的数据类型来存储。

   
简单的Parcel读写不再介绍,下面着重介绍一下2个函数

 

7.1 writeStrongBinder

client需要将一个binderserver发送时,可以调用此函数。例如
        virtual status_t addService(const String16& name, const sp<IBinder>& service)

        {
            Parcel data, reply;
            data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
            data.writeString16(name);
            data.writeStrongBinder(service);
            status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
            return err == NO_ERROR ? reply.readExceptionCode() : err;
        }


看一下writeStrongBinder的实体
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)

{
    return flatten_binder(ProcessState::self(), val, this);
}

接着往里看flatten_binder
status_t flatten_binder(const sp<ProcessState>& proc,

    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;
    
    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) {
        IBinder *local = binder->localBinder();
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == NULL) {
                LOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.handle = handle;
            obj.cookie = NULL;
        } else {
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = local->getWeakRefs();
            obj.cookie = local;
        }
    } else {
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = NULL;
        obj.cookie = NULL;
    }
    
    return finish_flatten_binder(binder, obj, out);
}

    还是拿addService为例,它的参数为一个BnINTERFACE类型指针,BnINTERFACE又继承自BBinder
    BBinder* BBinder::localBinder()

    {
        return this;
    }
    所以写入到Parcelbinder类型为BINDER_TYPE_BINDER,同时你在阅读SM的代码时会发现如果SM收到的servicebinder类型不为BINDER_TYPE_HANDLE时,SM将不会将此service添加到svclist,但是很显然每个service的添加都是成功的,addService在开始传递的binder类型为BINDER_TYPE_BINDERSM收到的binder类型为BINDER_TYPE_HANDLE,那么这个过程当中究竟发生了什么?
   
为了搞明白这个问题,花费我很多的事件,最终发现了问题的所在,原来在BD中做了如下操作(drivers/staging/android/Binder.c)


static void binder_transaction(struct binder_proc *proc,

                   struct binder_thread *thread,
                   struct binder_transaction_data *tr, int reply)
{
..........................................

    if (fp->type == BINDER_TYPE_BINDER)
        fp->type = BINDER_TYPE_HANDLE;
    else
        fp->type = BINDER_TYPE_WEAK_HANDLE;
    fp->handle = ref->desc;
..........................................
}

 


阅读完addService的代码,你会发现SM只是保存了service binderhandleservicename,那么当client需要和某个service通信了,如何获得servicebinder呢?看下一个函数

7.2 readStrongBinder

server端收到client的调用请求之后,如果需要返回一个binder时,可以向BD发送这个binder,当IPCThreadState实例收到这个返回的Parcel时,client可以通过这个函数将这个被server返回的binder读出。


sp<IBinder> Parcel::readStrongBinder() const

{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}


往里查看unflatten_binder


status_t unflatten_binder(const sp<ProcessState>& proc,

    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);
    
    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = static_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }        
    }
    return BAD_TYPE;
}


发现如果server返回的binder类型为BINDER_TYPE_BINDER的话,也就是返回一个binder引用的话,直接获取这个binder;如果server返回的binder类型为BINDER_TYPE_HANDLE时,也就是server返回的仅仅是binderhandle,那么需要重新创建一个BpBinder返回给client


   
有上面的代码可以看出,SM保存的servicebinder仅仅是一个handle,而client则是通过向SM获得这个handle,从而重新构建代理binderserver通信。


   
这里顺带提一下一种特殊的情况,binder通信的双方即可作为client,也可以作为server.也就是说此时的binder通信是一个半双工的通信。那么在这种情况下,操作的过程会比单工的情况复杂,但是基本的原理是一样的,有兴趣可以分析一下MediaPlayerMediaPlayerService的例子。

 

8. 经典桥段分析

main_ mediaserver.cpp
int main(int argc, char** argv)

{

//创建进程mediaserverProcessState实例
    sp<ProcessState> proc(ProcessState::self());

//获得SMBpServiceManager
    sp<IServiceManager> sm = defaultServiceManager();

    LOGI("ServiceManager: %p", sm.get());

//添加mediaserver中支持的service
    AudioFlinger::instantiate();

    MediaPlayerService::instantiate();
    CameraService::instantiate();
    AudioPolicyService::instantiate();

//启动ProcessStatepool thread
    ProcessState::self()->startThreadPool();

//这一步有重复之嫌,加不加无关紧要。
    IPCThreadState::self()->joinThreadPool();

}

 

9. Java 层的binder机制

了解了native通信机制后,再去分析JAVA层的binder机制,就会很好理解了。它只是对nativebinder做了一个封装。这一部分基本上没有太复杂的过程,这里不再赘述了。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值