Binder详解

深入分析AndroidBinder机制(远程对象访问)

 

介绍

Binder是什么?它可以叫作:IPCRPC、线程迁移、远程对象访问,本文中理解它为远程对象访问更贴切些,简而言之就是一个进程能访问另一个进程中的对象调用该对象的方法,就好像对象在自己的进程中一样,这种访问是同步的访问,当然Binder也能实现异步的通信

Binder基于C/S架构:

Binder分为JavaC++两套实现,分别用于Java应用和Native应用开发,Java Binder实际上也是基于C++ Binder的一个封装,因此本文只分析C++ Binder

服务分为2种:Native ServiceAndroid Service

Native Service:是在系统init阶段通过init.rc脚本建立的服务,完全在C++空间完成的服务。

Androids service:是系统二阶段(init2)初始化时建立的服务,是指在JVM空间完成的服务,虽然也要使用Navite上的框架,但是服务主体存在于Android空间,所有的Androids service都运行在一个进程中:systemsever进程。

 

实现原理

Binder本质上说就是一种数据传输方式,当通过服务代理调用服务对象的方法时,服务代理把参数序列化进行传输,服务对象反序列化取出参数,然后调用服务对象的方法。

进程间的通信是通过Android专门为Linux增加的一个设备/dev/binder)来实现的。

本质上是使用了共享内存来进行通信,但该共享内存和我们平常理解会有一点不一样。

我们平常使用的共享内存是两个进程之间,即点到点的,如果有N个进程要两两通信而又不相互干扰,那么就必须有N*N个共享内存。Binder使用的共享内存是进程与binder设备之间,即binder做为一个中间者进行传递,类似会议电视的MCU

使用了共享内存,在驱动中还是会有一次拷贝的,进程A向进程B传递数据时,数据会被驱动从进程A中拷贝到binder和进程B之间的共享内存中,然后进程B就可以直接读了。

 

通信过程:

所有要进行通信的进程都得打开/dev/binder设备

binder设备驱动会为每个进程分配一个数据结构binder_proc,每进程中的每个用到了binder通信的线程分配数据结构binder_thread

binder设备驱动会为服务进程中的每个服务对象分配数据结构binder_node,它隶属于服务进程的binder_proc,是服务端相关的,binder_node中记录了服务对象在服务进程中的地址;会为客户进程中引用的每个服务分配binder_ref,是客户端相关的,binder_ref会指向客户进程引用的服务对象的binder_node

binder设备驱动为客户进程引用的每个服务都会维护一个handle,它存在于binder_ref中(binder_ref.desc),它就像进程打开某个文件产生的文件描述符一样,进程每引用一个服务,就会分配一个最小未使用的整数作为handlehandle是客户进程相关的,多个进程引用同一个服务得到的handle并不是一样的。

当服务进程向ServiceManager注册服务时,会带上服务的名称字符串,驱动会为服务进程中的服务对象增加一个binder_node,归属于服务进程的binder_proc

当把注册服务的请求发给ServiceManager时,ServiceManager也是服务对象的一个引用者,驱动会为ServiceManager增加一个binder_ref,指向服务对象的binder_node。驱动把binder_ref.descServiceManager)作为handle返回给ServiceManagerServiceManager保存此handle和服务名称字符串。

当客户进程向ServiceManager获取服务时,ServiceManager根据服务名称字符串找到服务对象在ServiceManager进程中的handle。在ServiceManager的应答的过程中,驱动根据此handleServiceManager进程的binder_proc找到对应的binder_ref,并根据它找到服务对象的binder_node。然后,驱动会为客户进程增加一个binder_ref,指向服务对象的binder_node,最后把binder_ref.desc(客户进程)作为handle返回给客户进程。

客户进程使用得到的handle向服务进程发起请求,驱动会在根据此handle在客户进程的binder_proc查找对应的binder_ref,并找到它指向的binder_node,并找到binder_node所属的binder_proc,最终驱动把请求放入服务进程的接收队列中。

服务进程收到请求后,从binder_node中找到服务对象的地址,然后调用该服务对象。所以,对于服务对象,在客户进程中表现出来的是handle,在服务进程中表现出来的是地址,驱动会对它们进行映射。

 

Binder框架

概览

框架的层次结构:

说明:

Bn代表服务端,Bp代表代理

ProcessStateIPCThreadState是进程、线程相关,是对Binder驱动的封装

Binder核心库又是对ProcessStateIPCThreadState的封装

C++ Binder框架是对Binder核心库和服务接口的封装

 

类关系图:

`

说明:绿色部分是用户编写应用程序需要实现的

 

IPCThreadStateProcessStateBinder关系图:

 

对于Binder核心库:

IBinder:是一个接口,被BpBinderBbinder继承

BpBinder:客户端,内部有一个成员mHandle记录了远程服务对象的handle

BpRefBase:客户端,内部有一个成员指向BpBinder,采用的是Bridge设计模式,实际是是通过BpBinder来完成通信

Bbinder:服务端

 

对于C++ Binder框架:

Iinterface:主要是定义了asBinder()、纯虚函数onAsBinder()asBinder()直接调用onAsBinder()onAsBinder()分别在BnInterfaceBpInterface中进行了实现,用于获取BnInterfaceBpBinder的地址,即IInterface的作用是通过接口获取对应的Binder对象的本地地址/代理BpBinder的地址。

BpInterface<XXX>:是一个接口,一个模板类,是一个粘合类,即继承BpInterface<XXX>便等同于同时继承IXXXBpRefBase

BnInterface<XXX>:是一个接口,一个模板类,是一个粘合类

 

对于用户实现:

IXXX:是一个接口类,继承IInterface,定义服务的方法,即纯虚函数method_1()等,不能被实例化

BpXXX:是一个实现类,实现了IXXX中的纯虚函数,因为不是接口类,这个实现类不需要在接口中体现(即不需要在接口的头文件中体现,如:IMediaPlayer.h),它封装了IXXX的操作和BpBinder的操作;

BnXXX:仍是一个接口类,未实现IXXX中的纯虚函数,不能被实例化,需要一个真正工作的类来继承、实现它,这个类才是真正执行具体功能的类。BnXXX仅实现了虚函数onTransact()(在BBinder::transact()被调用)。

XXX:实现BnXXX,会有一个XXX::instantiate()函数来注册服务。

 

Binder驱动

源代码:

kernel\drivers\staging\android\binder.h

kernel\drivers\staging\android\binder.c

 

参见下文驱动源代码的分析

Binder Adapter

源代码:

frameworks\base\include\binder\IPCThreadState.h

frameworks\base\include\binder\ProcessState.h

frameworks\base\libs\binder\IPCThreadState.cpp

frameworks\base\libs\binder\ProcessState.cpp

 

ProcessState

 

一个进程只有一个ProcessState对象,主要用于打开/dev/binder,设置设备支持的最大线程数,进行内存映射,把binder设备文件的句柄保存在mDriverFD以供IPCThreadState使用。维护进程中所有的Service代理(BpBinder对象)和其对应的handleBinder驱动为每个Service维护一个handle,对handle的操作封装在ProcessState中维护的BpBinder对象中)

ProcessStatesingleton模式,使用静态成员函数ProcessState::self()来构造。

 

构造函数:

 

ProcessState::ProcessState()

{

     mDriverFD(open_driver())  //打开binder设备

        open("/dev/binder", O_RDWR);

       ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);  //最大线程数设为15,保存在binder_proc.max_threads

     mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE |  MAP_NORESERVE, mDriverFD, 0); //内存映射,只读,用于接收transactions

}

 

ProcessState::getStrongProxyForHandle()

作用:为Servicehandle创建BpBinder对象。主要在Parcel::readStrongBinder()ProcessState::getContextObject()中调用。

 

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t  handle)

{

     sp<IBinder> result;

 

     AutoMutex _l(mLock);     //互斥锁,在ProcessState::expungeHandle()也有调用

 

// 查询Service代理对象列表,如果未代理对象未创建,将在列表中增加相应位置,以保存下面将要创建的代理对象

handle_entry* e = lookupHandleLocked(handle);

 

     if (e != NULL) {

         // 1BpBinder对象在创建时设置了RefBase标志:OBJECT_LIFETIME_WEAK。并且重写了RefBase的虚方法:onFirstRef()onLastStrongRef()

         // 2、创建的BpBinder对象在该函数中,只是记录它的地址和它的引用记录的地址,未记录下它的强引用/弱引用

         // 3、调用attemptIncWeak()是安全的,假设BpBinder对象因为弱引用计数减为0而调用BpBinder析构函数(参见:RefBase::weakref_type::decWeak()),该析构函数中要调用ProcessState::expungeHandle(),而expungeHandle()要获取本函数中相同的互斥锁mLock,然后把e->binder置为NULL。所以,如果下面的代码e->binder不为NULLexpungeHandle()也无法执行把它置成NULL,析构函数也就无法完成,对象的空间也不会释放,e->refs指向的空间就是有效的。但此时对象的引用计数可能为0,这样调用attemptIncWeak()会失败,当析构函数完成后,对象的空间会被释放,所以就要重新创建一个对象。

         IBinder* b = e->binder;

         if (b == NULL || !e->refs->attemptIncWeak(this)) { //如果弱引用计数为0,则attemptIncWeak()返回失败

            b = new BpBinder(handle);

            e->binder = b;

            if (b) e->refs = b->getWeakRefs();   // e->refse->binder的引用记录的地址

            result = b;

         } else {

            // This little bit of nastyness  is to allow us to add a primary

            // reference to the remote proxy  when this team doesn't have one

            // but another team is sending  the handle to us.

            result.force_set(b);     //调用的是 RefBase::forceIncStrong(),其中会调用BpBinder重写的onFirstRef()

            e->refs->decWeak(this);  //抵消上面的e->refs->attemptIncWeak()的增加

         }

     }

 

     return result;

}

 

ProcessState::startThreadPool()

只启动一次,它直接调用ProcessState::spawnPooledThread(true),创建PoolThread对象并调用PoolThread::run()(实际上就创建了一个线程,没看到线程池的概念),PoolThread继承自Thread,实际上调用的是Thread::run(),其中创建线程函数_threadLoop(),其中调用PoolThread::threadLoop(),其中调用IPCThreadState::self()->joinThreadPool(mIsMain);,此处mIsMain==true,即表示进入looper

 

IPCThreadState

 

每个线程都有一个IPCThreadState对象,它有一个成员变量mProcess指向它所属的ProcessState对象,它主要负责Binder数据读写和命令处理,客户端调用transact(),服务端调用joinThreadPool()

IPCThreadStatesingleton模式,使用静态成员函数IPCThreadState::self()来构造。

 

构造函数:

 

IPCThreadState::IPCThreadState()

{

     mProcess(ProcessState::self())

     mMyThreadId(androidGetTid())       //调用gettid()getpid(),返回pid_t,所以线程也是当成轻量级里程看待的

     pthread_setspecific(gTLS, this);   //设置线程私有数据,把IPCThreadState关联到全局静态变量gTLSThread Local Storage),而gTLSIPCThreadState::self()中创建和获取,与gTLS关联的私有数据释放函数为IPCThreadState::threadDestructor(),当线程退出时调用该函数,其中又调用ioctl(self->mProcess->mDriverFD,  BINDER_THREAD_EXIT, 0);

}

 

transact()BpBinder实际上调用的是IPCThreadState::transact(),先调用writeTransactionData()构造数据,再调用waitForResponse()写入数据并等待应答

talkWithDriver():读取/写入,调用ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr),把IPCThreadState::mOutParcel)中包含的binder_transaction_data封装成binder_write_read写到驱动,从驱动读取到的binder_write_read中包含的binder_transaction_data写到IPCThreadState::mInParcel

executeCommand()BR_***命令处理,对于BR_TRANSACTION,会调用BBinder::transact()。在joinThreadPool()waitForResponse()中调用

joinThreadPool():循环结构,调用talkWithDriver()读取命令,然后调用executeCommand()处理。函数名为加入线程池,更准确地说是调用binder_get_thread()在进程的内核数据中分配了一个binder_thread

writeTransactionData():把用户的Parcel先转换成binder_transaction_data,再把binder_transaction_data写入IPCThreadState::mOut(也是Parcel),仅用来构造mOut。在transact()sendReply()中调用

waitForResponse():写入命令并等待应答,先调用talkWithDriver()写入/读取,然后再处理BR_***

Binder核心库

源代码:

frameworks\base\include\binder\Binder.h

frameworks\base\include\binder\BpBinder.h

frameworks\base\include\binder\IBinder.h

frameworks\base\libs\binder\Binder.cpp

frameworks\base\libs\binder\BpBinder.cpp

 

BpBinder

 

ProcessState::getStrongProxyForHandle()创建,创建时会记录下Servicehandle,并增加句柄的引用计数(IPCThreadState::self()->incWeakHandle(handle);

 

构造函数

参数为服务的handle

 

BpBinder::BpBinder(int32_t handle)

     : mHandle(handle)

{

     extendObjectLifetime(OBJECT_LIFETIME_WEAK); 

     IPCThreadState::self()->incWeakHandle(handle); 

}

       IPCThreadState::incWeakHandle()就是向驱动写入了一个BC_INCREFS命令。

 

BpBinder::transact()

向服务端发送数据,实际上是调用IPCThreadState::transact()来实现。

 

BpBinder::transact()

{

IPCThreadState::self()->transact(mHandle,...)     // mHandleProcessState::getStrongProxyForHandle()创建BpBinder时设置

IPCThreadState::writeTransactionData(BC_TRANSACTION,...)    //构造写入数据

            IPCThreadState::waitForResponse()                      //写入命令并等待应答

                 IPCThreadState::talkWithDriver                       //写入和读取

                  ioctl(mProcess->mDriverFD,  BINDER_WRITE_READ, &bwr)

              // 处理BR_REPLY,...等命令

}

 

BpRefBase

 

采用Bridge设计模式,它的构造函数中有一个参数sp<IBinder>,它有一个成员mRemote指向BpBinder,实际的通信工作是通过BpBinder来完成的。

对于一个服务对象,在进程中只有一个BpBinder,但可以有多个BpRefBase引用这个BpBinder

 

构造函数

参数为BpBinder

 

BpRefBase::BpRefBase(const sp<IBinder>&  o)

     : mRemote(o.get()), mRefs(NULL), mState(0)

{

     if (mRemote) {

         mRemote->incStrong(this);            // Removed on first IncStrong().

         mRefs = mRemote->createWeak(this);   // Held for our entire lifetime.

     }

}

 

BBinder

 

IPCThreadState收到请求后,调用IPCThreadState::executeCommand()处理请求,其中会调用服务对象的BBinder::transact()方法,BBinder::transact()中又继续调用BBinder派生类BnXXX重写的onTransact()方法

 

Parcel

 

Parcel顾名思义:邮包,即是应用程序通过binder通信所使用的数据容器。

两个重要的函数:Parcel::writeStrongBinder()Parcel::readStrongBinder(),它们中会调用ProcessState::self()打开设备

 

Parcel::writeStrongBinder(constsp<IBinder>& val)

发送请求时,将binder信息写入Parcel

 

Parcel::writeStrongBinder()

//输入BpBinderBBinder,构造flat_binder_object

{

     flat_binder_object obj;

     flatten_binder(ProcessState::self(), val, this);

         IBinder *local = binder->localBinder();         // localBinder()IBinder定义且实现(返回NULL),被BBinder重写(返回this

         if (!local) {     //参数是BpBinder,传递服务代理信息,客户端A把它得到的服务对象的BpBinder告诉客户端B,客户端B不查询ServiceManager也能使用服务,实现服务信息共享

            BpBinder *proxy = binder->remoteBinder();   // remoteBinder()IBinder定义且实现(返回NULL),被BpBinder重写(返回this

            const int32_t handle = proxy ?  proxy->handle() : 0;

            obj.type = BINDER_TYPE_HANDLE;

            obj.handle = handle;     //服务对象的handle

            obj.cookie = NULL;

         } else {          //参数是BBinder,传递服务对象信息

            obj.type = BINDER_TYPE_BINDER;

            obj.binder = local->getWeakRefs();  //服务对象的引用记录的地址

            obj.cookie = local;      //服务对象的地址

         }

         finish_flatten_binder()      //flat_binder_object写到Parcel.mObjects缓冲区,在驱动传输的过程中(binder_transaction()),为创建binder_nodebinder_ref

            Parcel::writeObject()

}

 

Parcel::readStrongBinder()

接收应答时,从Parcel取出binder信息

 

Parcel::readStrongBinder()

//返回BpBinderBBinder,会把handle转换成BpBinder

{

     unflatten_binder(ProcessState::self(), *this, &val);

         Parcel::readObject()              //Parcel.mObjects缓冲区读取flat_binder_object

         switch (flat->type) {             //读取结构  flat_binder_object

            case BINDER_TYPE_BINDER:     //客户端和服务在同一进程,返回BBinder

                *out = static_cast<IBinder*>(flat->cookie);

            case BINDER_TYPE_HANDLE:     //客户端和服务不在同一进程,返回BpBinder

                *out = proc->getStrongProxyForHandle(flat->handle);

}

 

 

C++ Binder框架

源代码:

frameworks\base\include\binder\IInterface.h

frameworks\base\include\binder\Parcel.h

frameworks\base\libs\binder\IInterface.cpp

frameworks\base\libs\binder\Parcel.cpp

 

IInterface

 

IInterface::asBinder()

asBinder()直接调用纯虚函数IInterface::onAsBinder()onAsBinder()分别在BnInterfaceBpInterface中进行了实现,用于获取BnInterfaceBpBinder的地址,即IInterface的作用是通过接口获取对应的Binder对象的本地地址/代理BpBinder的地址

 

sp<IBinder> IInterface::asBinder()

{

     return this ? onAsBinder() : NULL;

}

 

template<typename INTERFACE>

IBinder* BnInterface<INTERFACE>::onAsBinder()

{

     return this;

}

 

template<typename INTERFACE>

inline IBinder* BpInterface<INTERFACE>::onAsBinder()

{

     return remote();

}

 

BpInterface<XXX>

 

构造函数

参数为BpBinder

 

template<typename INTERFACE>

inline BpInterface<INTERFACE>::BpInterface(const  sp<IBinder>& remote)

     : BpRefBase(remote)

{

}

 

interface_cast<XXX>(constsp<IBinder>& obj)

 

看名字就知道它是一个进行类型转换的函数,前面根据handle创建了BpBinder,进而创建了BpBinder,接下来就是要利用模板函数interface_cast<XXX>()根据BpBinder创建BpXXX

函数的参数可以是BpBinderBBinder,返回的是BpXXXBnXXX

 

template<typename INTERFACE>

inline sp<INTERFACE> interface_cast(const  sp<IBinder>& obj)

{

     return INTERFACE::asInterface(obj);

}

       函数直接调用了IXXX::asInterface(),它是通过宏DECLARE_META_INTERFACEIMPLEMENT_META_INTERFACE来声明和实现的。

 

DECLARE_META_INTERFACEIMPLEMENT_META_INTERFACE

 

IXXX类的声明中,调用DECLARE_META_INTERFACE(XXX);,在IXXX类的实现中,调用IMPLEMENT_META_INTERFACE(XXX, "接口名称");

其中关键的实现为:

 

#define  IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \

     ...

     android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \

            const android::sp<android::IBinder>&  obj)                   \

     {                                                                    \

         android::sp<I##INTERFACE> intr;                                 \

         if (obj != NULL) {                                              \

            intr = static_cast<I##INTERFACE*>(                          \

                obj->queryLocalInterface(                               \

                        I##INTERFACE::descriptor).get());               \

            if (intr == NULL) {                                         \

                intr = new Bp##INTERFACE(obj);                          \

            }                                                            \

         }                                                               \

         return intr;                                                     \

     }                                                                    \

注释:

IBinder定义并实现了虚函数queryLocalInterface()(为空函数直接返回NULL),BpBinder继承IBinder但未重写该虚函数,BnInterface继承BBinder继承IBinder,重写了该函数(if (_descriptor ==INTERFACE::descriptor) return this;),所以,如果asInterface()的参数为BpBinder,那么每次调用都会创建一个BpXXX,如果参数为BBinder,只是直接返回BBinder对象的地址,作用是在同一个进程中调用Binder将直接得到BBinder对象的地址。调用者无需要关心调用的对象是远程的还是本地的

参数NAME只是接口的名字,无实质作用,和服务的名字不是一回事

 

实现服务

参考代码:

frameworks\base\include\media\IMediaPlayerService.h

frameworks\base\media\libmedia\IMediaPlayerService.cpp

frameworks\base\media\libmediaplayerservice\MediaPlayerService.h

frameworks\base\media\libmediaplayerservice\MediaPlayerService.cpp

 

编码

 

IXXX.h

定义class IXXX:public IInterface
调用宏DECLARE_META_INTERFACE(XXX);
定义一系列接口用到的纯虚函数,如:method_1()method_2()

定义class BnXXX:public BnInterface<IXXX>
重写onTransact()

 

IXXX.cpp

定义class BpXXX:public BpInterface<IXXX>
构造函数中调用BpInterface<IXXX >(impl)
调用宏IMPLEMENT_META_INTERFACE(XXX,"android.xxx.IXXX");
实现接口的方法(其中调用remote()->transact

实现BnXXX::onTransact()
重写onTransact(),其中调用由BnXXX派生类XXX实现的接口方法

 

XXX.hXXX.cpp

定义class XXX:public BnXXX
实现接口的方法

 

BpXXX

 

构造函数

参数为BpBinderBpXXX的构造函数中有一个参数sp<IBinder>& impl,说明它采用了Bridge模式,BpBinder是它的实现。

 

BpXXX(const sp<IBinder>& impl)

     : BpInterface<IXXX>(impl)

{

}

 

BpXXX::method_1()

该函数内不执行具体的操作,只是把请求发给服务端

 

virtual void method_1(int id)

{

     Parcel data, reply;

     data.writeInt32(id);  //构造发送数据

 

     remote()->transact(CMD_METHOD_1, data, &reply);  // CMD_METHOD_1是发送的命令

}

BpXXX继承BpRefBaseBpRefBase定义了成员函数remote(),该函数返回的实际上就是BpBinder,然后调用BpBinder::transact()发送数据

 

BnXXX

 

BnXXX::onTransact()

BnXXX::onTransact()BBinder::transact()中调用,它根据收到的命令,分别调用对应的方法。

 

status_t BnXXX::onTransact(uint32_t code,  const Parcel& data, Parcel* reply, uint32_t flags)

{

     switch(code) {

         case CMD_METHOD_1: {

            pid_t pid = data.readInt32();

            rtn = method_1(pid);  //调用的是BnXXX的派生类XXX实现的method_1()

            reply->writeInt32(rtn);

         }

     }

}   

 

 

XXX

实现XXX::method_1()

 

 

ServiceManager

源代码:

frameworks\base\cmds\servicemanager\*

 

服务进程向ServiceManager注册服务,客户进程向ServiceManager查询服务,从而得到访问服务对象的handle

ServiceManager维护服务名称字符串,它本身也是一个服务,调用binder_become_context_manager()变为“Server大总管”的服务,他对于其它进程来说,它的handle永远是0。它是第一个启动的服务,在/init.rc中启动。

ISericeManager本地功能BnServiceManager并没有实现,本地功能实际上由servicemanager守护进程执行,而用户程序通过调用BpServiceManager来获得其他的服务。

 

ServiceManager主程序代码

frameworks\base\cmds\servicemanager\service_manager.c

 

main()

{

     // 其中调用binder_***()函数位于frameworks\base\cmds\servicemanager\binder.c

     binder_open(128*1024);

         open("/dev/binder")         //调用驱动的binder_open()

         mmap()                      ///dev/binder映射到一个128*1024字节大小的内存

     binder_become_context_manager()

         ioctl(BINDER_SET_CONTEXT_MGR)

     binder_loop(bs, svcmgr_handler);  //注册请求处理函数 svcmgr_handler()                   

         binder_write()              //写命令BC_ENTER_LOOPER

         // 开始循环

         ioctl(BINDER_WRITE_READ);  //只是读取

         binder_parse()              //调用svcmgr_handler()处理BR_TRANSACTION,...等命令,

}

 

svcmgr_handler()

请求处理函数

对于客户端请求服务,返回的是Servicehandlebinder类型是BINDER_TYPE_HANDLE,见函数bio_put_ref(),然后在驱动层binder_thread_write() ->binder_transaction()会进行转换,如果请求的服务在同一进程里,则转换类型成BINDER_TYPE_BINDER,直接使用服务对象的地址,而不使用handle,这在unflatten_binder()中有体现。

 

获取ServiceManager服务代理

 

sp<IServiceManager>  defaultServiceManager()

{

     if (gDefaultServiceManager != NULL) return gDefaultServiceManager; //单一实例

    

     {

         AutoMutex _l(gDefaultServiceManagerLock);

         if (gDefaultServiceManager == NULL) {

            gDefaultServiceManager =  interface_cast<IServiceManager>(   //调用interface_cast<XXX>根据BpBinder生成BpServiceManager

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

         }

     }

    

     return gDefaultServiceManager;

}

 

sp<IBinder> ProcessState::getContextObject(const  sp<IBinder>& caller)

{

     if (supportsProcesses()) {

         return getStrongProxyForHandle(0);   //调用ProcessState::getStrongProxyForHandle()创建BpBinderhandle0

     } else {

         return getContextObject(String16("default"), caller);

     }

}

 

注册服务

 

status_t BpServiceManager::addService(const  String16& name, const sp<IBinder>& service)

//参数service可以是BpBinderBBinderbinder驱动会记录下对象的地址

{

     data.writeStrongBinder(service);

     remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);

}

 

查询服务

 

sp<IBinder> BpServiceManager::getService(const  String16& name)

//函数返回BpBinderBBinder

{

     BpServiceManager::checkService()

         remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);

         reply.readStrongBinder()

}

 

 

调用服务

服务端

服务端如何工作

创建ProcessState对象,打开/dev/binder,映射好内存

调用defaultServiceManager()创建ServiceManager的代理

调用服务端类的方法instantiate(),创建服务端对象,并向ServiceManager注册

ProcessState::self()->startThreadPool();,其中也会调用IPCThreadState::joinThreadPool(),参数是true,加上下面的,总共调用了2

IPCThreadState::self()->joinThreadPool();,参数默认也是true,进入服务的循环监听状态。(网上有人测试过把最后一句屏蔽掉,也能正常工作。但是难道主线程提出了,程序还能不退出吗?)

 

参考代码:

frameworks\base\media\mediaserver\main_mediaserver.cpp

 

int main(int argc, char** argv)

{

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

     sp<IServiceManager> sm = defaultServiceManager();

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

     AudioFlinger::instantiate();

     MediaPlayerService::instantiate();

     CameraService::instantiate();

     AudioPolicyService::instantiate();

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

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

}

 

 

void MediaPlayerService::instantiate() {

     defaultServiceManager()->addService(

            String16("media.player"),  new MediaPlayerService());  //注册时,要附上服务名称、服务对象的地址,服务对象的地址最终是记录在驱动中

}

 

客户端

客户端如何调用服务

调用defaultServiceManager()创建ServiceManager的代理,其中会创建ProcessState对象

调用BpServiceManager::getService()获取服务的handle,并生成对应的BpBinder

调用BpBinder::linkToDeath(),注册服务死亡的通知

调用interface_cast<IXXX>()利用BpBinder生成BpXXX

 

参考代码:

frameworks\base\media\jni\android_media_MediaPlayer.cpp

frameworks\base\media\libmedia\mediaplayer.cpp

frameworks\base\media\libmedia\IMediaDeathNotifier.cpp

 

frameworks\base\media\jni\android_media_MediaPlayer.cpp

android_media_MediaPlayer_setDataSourceAndHeaders()

{

     mp->setDataSource(

                String8(pathStr),

                headers ? &headersVector :  NULL);

}

 

frameworks\base\media\libmedia\mediaplayer.cpp

status_t MediaPlayer::setDataSource(

         const char *url, const KeyedVector<String8, String8> *headers)

{

     status_t err = BAD_VALUE;

         const sp<IMediaPlayerService>& service(getMediaPlayerService());

         if (service != 0) {

            sp<IMediaPlayer> player(

                    service->create(getpid(),  this, url, headers, mAudioSessionId));

            err = setDataSource(player);

         }

     return err;

}

 

frameworks\base\media\libmedia\IMediaDeathNotifier.cpp

IMediaDeathNotifier::getMediaPlayerService()

{

     if (sMediaPlayerService.get() == 0) {

         sp<IServiceManager> sm = defaultServiceManager();

         sp<IBinder> binder;

         do {

            binder = sm->getService(String16("media.player"));

            if (binder != 0) {

                break;

             }

             usleep(500000); // 0.5 s

         } while(true);

 

         if (sDeathNotifier == NULL) {

         sDeathNotifier = new DeathNotifier();

     }

     binder->linkToDeath(sDeathNotifier);

     sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);

     }

     return sMediaPlayerService;

}

 

服务进阶

异步方式

Binder默认是同步的,但有时我们也需要异步,比如广播通知,我们可以在发送的时候指定一个ONE_WAY标志,来实现异步

 

参考代码:

frameworks\base\media\libmedia\IMediaPlayerClient.cpp

 

BpMediaPlayerClient::notify(int msg, int  ext1, int ext2)

{

     Parcel data, reply;

     data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());

     data.writeInt32(msg);

     data.writeInt32(ext1);

     data.writeInt32(ext2);

     remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);  //如果不设置最后一个参数,那么默认为0

}

 

服务和客户端在同一进程

Binder也可以用于服务端和客户端在同一进程的情况,这样客户端不用关心服务对象在哪里,不管它在哪,对于客户端来说,就像和自己同一进程中一样。

实现原理:

客户端首先向ServiceManager查询服务,ServiceManager不管服务在哪,一律返回的是服务在ServiceManager进程中的handle,当应答在驱动的传输过程中,驱动会判断并转换,如果在同一进程,那么返回给客户进程的将是服务对象的地址,而客户进程调用BpServiceManager::getService()返回的将是BBinder,然后客户进程再调用interface_cast<XXX>(),最终得到的是BnXXX

 

参考代码:

kernel\drivers\staging\android\binder.c

 

 

binder_transaction()

{

     fp = (struct flat_binder_object *)(t->buffer->data + *offp);

     switch (fp->type) {

     case BINDER_TYPE_HANDLE:  //如果传输的binder对象的类型是handle,而不是地址

     case BINDER_TYPE_WEAK_HANDLE: {

         struct binder_ref *ref = binder_get_ref(proc, fp->handle); //在源进程的数据中找到对应的binder_ref,进而可以得到服务对象的binder_nodebinder_proc

         if (ref->node->proc == target_proc) { //传输的目的进程和服务对象在同一进程

            if (fp->type ==  BINDER_TYPE_HANDLE)

                fp->type =  BINDER_TYPE_BINDER;  // 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);

         } else {

         }

}

 

客户端注册服务死亡通知

由于不在同一进程内,当服务对象死亡后,客户进程需要知道这一点。

BpBinder有一个成员函数BpBinder::linkToDeath(),还有一个成员变量Vector<Obituary>*  mObituaries;,它是BpBinder::Obituary的容器。

 

BpBinder::linkToDeath()

它有一个参数是IBinder::DeathRecipient死亡通知对象,DeathRecipient类只有一个虚方法binderDied(),要想得到死亡通知,就需要继承DeathRecipient,并重写binderDied()

函数的作用就是把死亡通知对象放入BpBinder.mObituaries容器中

 

BpBinder::linkToDeath(sp<DeathRecipient>&  recipient, ...)

{

创建BpBinder.mObitsSent对象,它是Obituary的容器——只执行一次

调用IPCThreadState::requestDeathNotification() 向驱动写入命令BC_REQUEST_DEATH_NOTIFICATION,把 BpBinder对象的地址记录到驱动中binder_ref.death.cookie中,binder_ref是服务对象的引用。——只执行一次

把参数recipient封装在一个临时变量Obituary对象

mObituaries->add(ob); ——把Obituary添加到BpBinder.mObitsSent

}

      

当服务对象死亡后,将可以从驱动中读到消息,从驱动中的binder_ref.death.cookie取出BpBinder对象的地址,然后调用BpBinder::sendObituary()遍历BpBinder.mObitsSent所有的Obituary对象,调用BpBinder::reportOneDeath()Obituary对象中获得DeathRecipient死亡通知对象,最后调用其binderDied()方法。

 

参考代码:

frameworks\base\media\libmedia\IMediaDeathNotifier.cpp

 

客户端MeidaPlayer继承了IMediaDeathNotifier,实现了纯虚函数IMediaDeathNotifier::died()IMediaDeathNotifier的构造函数会把this添加到IMediaDeathNotifier::sObitRecipients容器,当IMediaDeathNotifier::DeathNotifier::binderDied()被调用时,将遍历IMediaDeathNotifier::sObitRecipients容器中的对象,调用纯虚函数IMediaDeathNotifier::died()

所以,把获取服务的BpBinder的工作放到了IMediaDeathNotifier中实现,以便获取之后能注册死亡通知。

 

IMediaDeathNotifier::getMediaPlayerService()

{

         sp<IServiceManager> sm = defaultServiceManager();

            binder = sm->getService(String16("media.player"));

 

         if (sDeathNotifier == NULL) { // IMediaDeathNotifier::sDeathNotifier是静态成员

         sDeathNotifier = new DeathNotifier();   // IMediaDeathNotifier::DeathNotifier继承IBinder::DeathRecipient

     }

     binder->linkToDeath(sDeathNotifier);       // BpBinder::linkToDeath()

}

 

类关系图:

 

数据结构图:

说明:虚线表示间接关联

匿名(未注册)服务

并不是所有的服务都需要注册的,客户端获取服务的方式有3种:

服务端向提供一个名称向ServiceManager注册,客户端向ServiceManager查询服务。

服务端把自己的BBinder信息发给客户端,客户端收到信息后,创建对应的BpBinder

客户端把自己得到的服务端的BpBinder信息传递给其它客户端,其它客户端收到后创建对应的BpBinder

 

参考代码:

frameworks\base\media\libmedia\mediaplayer.cpp

frameworks\base\media\libmedia\IMediaPlayerClient.cpp

frameworks\base\media\libmediaplayerservice\MediaPlayerService.cpp

 

MediaPlayerService本身并不完成播放的具体实现,它相当于播放器的一个管理者,其下可以创建多个播放器BnMediaPlayer对象,MediaPlayerService::Client会继承并实现BnMediaPlayer

当客户通过调用BpMediaPlayerService::create()MediaPlayerService请求创建播放器时,MediaPlayerService会创建MediaPlayerService::Client,并把它的binder信息返回给客户进程,客户进程收到binder信息后,创建BpMediaPlayer对象。

Parcel写入和读取binder信息的操作是由Parcel::writeStrongBinder()Parcel::readStrongBinder(),还用到了IInterface::asBinder()。具体请参见“第三章中的Parcel”。

 

 

逻辑关系图:

 

       类关系图:

 

frameworks\base\media\libmedia\mediaplayer.cpp

 

status_t MediaPlayer::setDataSource(

         const char *url, const KeyedVector<String8, String8> *headers)

{

         const sp<IMediaPlayerService>& service(getMediaPlayerService());  //创建BpMediaPlayerService

            sp<IMediaPlayer> player(

                    service->create(getpid(),  this, url, headers, mAudioSessionId));   //调用BpMediaPlayerService::create(),最后得到BpMediaPlayer。还传递了this指针,见“双向通信”

            err = setDataSource(player);  //保存BpMediaPlayer

}

 

frameworks\base\media\libmedia\IMediaPlayerClient.cpp

 

virtual sp<IMediaPlayer>  BpMediaPlayerService::create(

         pid_t pid, const sp<IMediaPlayerClient>& client,...)

{

     Parcel data, reply;

     data.writeStrongBinder(client->asBinder());  //见“双向通信”,传入BnInterface<MeidaPlayerClient>对象地址

     data.writeCString(url);

 

     remote()->transact(CREATE_URL, data, &reply);

 

     return interface_cast<IMediaPlayer>(reply.readStrongBinder());  //调用Parcel:: readStrongBinder()从服务端的应答中,取出BpBinder并生成BpMediaPlayer

}

 

status_t BnMediaPlayerService::onTransact(

     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

     switch(code) {

         case CREATE_URL: {

            sp<IMediaPlayerClient>  client =

                interface_cast<IMediaPlayerClient>(data.readStrongBinder());  //见“双向通信”

            sp<IMediaPlayer> player =  create(

                    pid, client, url,  numHeaders > 0 ? &headers : NULL, audioSessionId);

 //  调用MediaPlayerService::create()。参数clientBpMediaPlayerClient对象,见“双向通信”

            reply->writeStrongBinder(player->asBinder());  //写入BnMediaPlayer对象的binder信息

            return NO_ERROR;

         } break;

}

 

frameworks\base\media\libmediaplayerservice\MediaPlayerService.cpp

 

sp<IMediaPlayer> MediaPlayerService::create(pid_t  pid, const sp<IMediaPlayerClient>& client,…)

{

     sp<Client> c = new Client(this, pid, connId, client,  audioSessionId); //创建MediaPlayerService::Client对象。参数client用于记录下BpMediaPlayerClient对象,见“双向通信”

     return c;

}

 

双向通信

仍然以上节的内容为例,客户端主动调用BnMediaPlayer的服务,但同时也希望能接收服务对象的通知。实现方式就是客户端自身也作为一个服务,来给BnMediaPlayer对象调用,即双向服务。

实现细节,请参考上节内容中的类关系图,MediaPlayer是客户端,同时又继承BnMediaPlayerClient作为一个服务端,来接收BnMediaPlayer对象的通知。

MediaPlayer调用BpMediaPlayerService::create()创建播放器时,也会将自己的binder信息写入到Parcel中,BnMediaPlayer对象收到请求后,从Parcel中取出binder信息并生成BpMediaPlayerClient,记录下来以供日后发布通信。

也就是说明MediaPlayerService这个服务,由3个接口组成:IMediaPlayerClientIMediaPlayerServiceIMediaPlayer

 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页