Android Binder机制(超级详尽)

1.binder通讯概述linux

 

    binder通讯是一种client-server的通讯结构,android

    1.从表面上来看,是client经过得到一个server的代理接口,对server进行直接调用;cookie

    2.实际上,代理接口中定义的方法与server中定义的方法是一一对应的;框架

    3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;函数

    4.代理接口将该Parcel发送给内核中的binder driver.oop

    5.server会读取binder driver中的请求数据,若是是发送给本身的,解包Parcel对象,处理并将结果返回;this

    6.整个的调用过程是一个同步过程,在server处理的时候,client会block住。.net

 

 

 

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,那么会将该service的handle返回给client,handle是每一个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对应的代理binder的handle为0,当client尝试与SM通讯时,须要建立一个handle为0的代理binder,这里的代理binder其实就是第一节中描述的那个代理接口;

3.通知binder driver(BD)使SM成为BD的context manager;

4.维护一个死循环,在这个死循环中,不停地去读内核中binder driver,查看是否有可读的内容;便是否有对service的操做要求, 若是有,则调用svcmgr_handler回调来处理请求的操做。

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

 

 

这里须要声明一下,当service在向SM注册时,该service就是一个client,而SM则做为了server。而某个进程须要与service通讯时,此时这个进程为client,service才做为server。所以service不必定为server,有时它也是做为client存在的。

 

因为下面几节会介绍一些与binder通讯相关的几个概念,因此将SM的功能介绍放在了后面的部分来说。

 

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

 

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主要功能是负责client向BD发送调用请求的数据。它是client端binder通讯的核心对象,经过调用transact函数向BD发送调用请求的数据,它的构造函数以下:

BpBinder(int32_t handle);

    经过BpBinder的构造函数发现,BpBinder会将当前通讯中server的handle记录下来,当有数据发送时,会通知BD数据的发送目标。

ProcessState经过以下方式来获取BpBinder对象:

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

在这个过程当中,ProcessState会维护一个BpBinder的vector 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实例经过调用IPCThreadState的transact函数来向mOut中写入数据,这样的话这个binder IPC过程的client端的调用请求的发送过程就明了了。

 

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

5.主要基类

5.1基类IInterface

为server端提供接口,它的子类声明了service可以实现的全部的方法;

 

5.2基类IBinder

    BBinder与BpBinder均为IBinder的子类,所以能够看出IBinder定义了binder IPC的通讯协议,BBinder与BpBinder在这个协议框架内进行的收和发操做,构建了基本的binder IPC机制。

5.3基类BpRefBase

    client端在查询SM得到所需的的BpBinder后,BpRefBase负责管理当前得到的BpBinder实例。

 

 

6.两个接口类

6.1 BpINTERFACE

若是client想要使用binder IPC来通讯,那么首先会从SM出查询并得到server端service的BpBinder,在client端,这个对象被认为是server端的远程代理。为了可以使client可以想本地调用同样调用一个远程server,server端须要向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经过调用BpRefBase的remote()来得到BpBinder指针。

 

6.2 BnINTERFACE

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

 

    顺着BnINTERFACE的继承关系再往上看,

        class BnINTERFACE: public BnInterface<IINTERFACE>

 

    IINTERFACE为client端的代理接口BpINTERFACE和server端的BnINTERFACE的共同接口类,这个共同接口类的目的就是保证service方法在C-S两端的一致性。

 

    再往上看

        class BnInterface : public INTERFACE, public BBinder

 

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

 

    那么BBinder与BpBinder的区别又是什么呢?

 

    其实它们的区别很简单,BpBinder是client端建立的用于消息发送的代理,而BBinder是server端用于接收消息的通道。查看各自的代码就会发现,虽然两个类型均有transact的方法,可是二者的做用不一样,BpBinder的transact方法是向IPCThreadState实例发送消息,通知其有消息要发送给BD;而BBinder则是当IPCThreadState实例收到BD消息时,经过BBinder的transact的方法将其传递给它的子类BnSERVICE的onTransact函数执行server端的操做。

 

7. Parcel

Parcel是binder IPC中的最基本的通讯单元,它存储C-S间函数调用的参数.可是Parcel只能存储基本的数据类型,若是是复杂的数据类型的话,在存储时,须要将其拆分为基本的数据类型来存储。

 

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

 

7.1 writeStrongBinder

当client须要将一个binder向server发送时,能够调用此函数。例如

        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;

    }

    因此写入到Parcel的binder类型为BINDER_TYPE_BINDER,同时你在阅读SM的代码时会发现若是SM收到的service的binder类型不为BINDER_TYPE_HANDLE时,SM将不会将此service添加到svclist,可是很显然每一个service的添加都是成功的,addService在开始传递的binder类型为BINDER_TYPE_BINDER,SM收到的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 binder的handle和service的name,那么当client须要和某个service通讯了,如何得到service的binder呢?看下一个函数

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返回的仅仅是binder的handle,那么须要从新建立一个BpBinder返回给client。

 

 

    有上面的代码能够看出,SM保存的service的binder仅仅是一个handle,而client则是经过向SM得到这个handle,从而从新构建代理binder与server通讯。

 

 

    这里顺带提一下一种特殊的状况,binder通讯的双方便可做为client,也能够做为server.也就是说此时的binder通讯是一个半双工的通讯。那么在这种状况下,操做的过程会比单工的状况复杂,可是基本的原理是同样的,有兴趣能够分析一下MediaPlayer和MediaPlayerService的例子。

 

8. 经典桥段分析

main_ mediaserver.cpp

int main(int argc, char** argv)

{

//建立进程mediaserver的ProcessState实例

    sp<ProcessState> proc(ProcessState::self());

//得到SM的BpServiceManager

    sp<IServiceManager> sm = defaultServiceManager();

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

//添加mediaserver中支持的service。

    AudioFlinger::instantiate();

    MediaPlayerService::instantiate();

    CameraService::instantiate();

    AudioPolicyService::instantiate();

//启动ProcessState的pool thread

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

//这一步有重复之嫌,加不加可有可无。

    IPCThreadState::self()->joinThreadPool();

}

 

9. Java 层的binder机制

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

相关文章
相关标签/搜索