当前位置: 代码迷 >> Android >> Android Binder进程间通信-登记Service组件-封装进程间通信数据
  详细解决方案

Android Binder进程间通信-登记Service组件-封装进程间通信数据

热度:52   发布时间:2016-04-28 05:35:16.0
Android Binder进程间通信---注册Service组件---封装进程间通信数据

本文参考《Android系统源代码情景分析》,作者罗升阳

一、测试代码:

       ~/Android/external/binder/server

        ----FregServer.cpp

        ~/Android/external/binder/common

        ----IFregService.cpp

        ----IFregService.h

       ~/Android/external/binder/client

       ----FregClient.cpp


       Binder库(libbinder)代码:

       ~/Android/frameworks/base/libs/binder

       ----BpBinder.cpp

       ----Parcel.cpp

       ----ProcessState.cpp

       ----Binder.cpp

       ----IInterface.cpp

       ----IPCThreadState.cpp

       ----IServiceManager.cpp

       ----Static.cpp

       ~/Android/frameworks/base/include/binder

       ----Binder.h

       ----BpBinder.h

       ----IInterface.h

       ----IPCThreadState.h

       ----IServiceManager.h

       ----IBinder.h

       ----Parcel.h

       ----ProcessState.h


        驱动层代码:

       ~/Android//kernel/goldfish/drivers/staging/android

       ----binder.c

       ----binder.h


二、源码分析

     程序首先开始从Service进程FregServer.cpp的main函数开始执行

     ~/Android/external/binder/server

     ----FregServer.cpp

class FregService : public BnFregService{        ...........public:	static void instantiate()	{		defaultServiceManager()->addService(String16(FREG_SERVICE), new FregService());//注册Service	}        ...........};int main(int argc, char** argv){	FregService::instantiate();	ProcessState::self()->startThreadPool();	IPCThreadState::self()->joinThreadPool();	return 0;}
        在Android Binder进程间通信---ServiceManager代理对象的获取过程http://blog.csdn.net/jltxgcy/article/details/25953361,一文中我们已经分析了defaultServiceManager()获取了ServiceManager代理对象。现在调用addService来注册Service组件。
       ~/Android/frameworks/base/libs/binder

       ----IServiceManager.cpp

class BpServiceManager : public BpInterface<IServiceManager>{public:    .........    virtual status_t addService(const String16& name, const sp<IBinder>& service)    {        Parcel data, reply;        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());//写入一个Binder进程间通信请求头        data.writeString16(name);//写入将要注册的Service组件的名称        data.writeStrongBinder(service);//将要注册的Service组件封装成一个flat_binder_object结构体,写入data        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);        return err == NO_ERROR ? reply.readExceptionCode() : err;    }    ..........};
       将进程间通信数据写入到一个Parcel对象data中,然后将Parcel对象data的内容传递给Binder驱动程序。

       首先调用Parcel对象data的成员函数writeInterfaceToken写入一个Binder进程间通信请求头,它的实现如下所示:

       ~/Android/frameworks/base/libs/binder

       ----Parcel.cpp

status_t Parcel::writeInterfaceToken(const String16& interface){    writeInt32(IPCThreadState::self()->getStrictModePolicy() |               STRICT_MODE_PENALTY_GATHER);//整数值,用来描述一个Strict Mode Policy    // currently the interface identification token is just its name as a string    return writeString16(interface);//用来描述所请求服务的接口描述符}
      Binder进程间通信请求头由两部分内容组成。第一部分内容是一个整数值,用来描述一个Strict Mode Policy,第二部分内容是一个字符串,用来描述所请求服务的接口描述符。

      接着调用Parcel对象data的成员函数writeString16写入将要注册的Service组件的名称。

      最后,调用Parcel对象data的成员函数writeStrongBinder将要注册的Service组件封装成一个flat_binder_object结构体,然后传递给Binder驱动程序。将一个Service组件封装成一个flat_binder_object结构体是Binder进程间通信过程的一个重要步骤,接下来我们就着重分析这个过程。
       ~/Android/frameworks/base/libs/binder
       ----Parcel.cpp

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();//Binder本地对象的        if (!local) {            .........        } else {            obj.type = BINDER_TYPE_BINDER;            obj.binder = local->getWeakRefs();//弱引用计数的地址            obj.cookie = local;//binder本地对象指针        }    } else {        .........    }        return finish_flatten_binder(binder, obj, out);//将flat_binder_object结构体obj写入到Parcel对象out中}

      首先定义了一个flat_binder_object结构体obj,然后将它的标志值设置为0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS,其中,0x7f用来描述将要注册的Service组件在处理一个进程间通信请求时,它所使用的Server线程的优先级不能低于0x7f;而FLAT_BINDER_FLAG_ACCEPTS_FDS表示可以将包含文件描述符的进程间通信数据给将要注册的Service组件处理。

    其中flat_binder_object结构体,实现如下:

     ~/Android/frameworks/base/include/binder

     ----binder.h

struct flat_binder_object { unsigned long type; unsigned long flags; union { void *binder; signed long handle; }; void *cookie;};

      接下来调用binder->localBinder(),分析此函数前,我们先看一个uml类图。




       参数binder指向的是一个FregService组件,它继承了BBinder类,BBinder类是用来描述一个Binder本地对象的,它的成员函数localBinder用来返回一个Binder本地对象接口。对应实现代码如下:

       ~/Android/frameworks/base/libs/binder

       ----Binder.cpp

BBinder* BBinder::localBinder(){    return this;//BBinder对象指针}
      接下来分别设置type为BINDER_TYPE_BINDER,binder为其内部的一个弱引用计数对象的地址值,cookie为上面返回的Binder本地对象指针。

      

     最后调用全局函数finish_flatten_binder将flat_binder_object结构体obj写入到Parcel对象out中,它的实现如下所示:

     ~/Android/frameworks/base/libs/binder

     ---- Parcel.cpp

inline static status_t finish_flatten_binder(    const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out){    return out->writeObject(flat, false);//将flat_binder_object结构体flat写入到内部}
      它调用Parcel对象out的成员函数writeObject将flat_binder_object结构体flat写入到内部。Parcel类的成员函数writeObject的实现如下所示:

     ~/Android/frameworks/base/libs/binder
     ---- Parcel.cpp

status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData){    const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;//数据缓冲区如果有足够空间,enoughData为1    const bool enoughObjects = mObjectsSize < mObjectsCapacity;//偏移数组如果有足够空间,enoughObjects为1    if (enoughData && enoughObjects) {restart_write:        *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;//flat_binder_object结构体存入数据缓冲区mData                // Need to write meta-data?        if (nullMetaData || val.binder != NULL) {            mObjects[mObjectsSize] = mDataPos;//flat_binder_object结构体在mData中偏移写入偏移数组mObjects            acquire_object(ProcessState::self(), val, this);            mObjectsSize++;//偏移数组mObjects下一个用于写入数据的位置加一        }                // remember if it's a file descriptor        if (val.type == BINDER_TYPE_FD) {            mHasFds = mFdsKnown = true;        }        return finishWrite(sizeof(flat_binder_object));//调整缓冲区mData下一个用来写入数据的位置    }    if (!enoughData) {//如果没有足够的空间,那么扩展后重新写入        const status_t err = growData(sizeof(val));        if (err != NO_ERROR) return err;    }    if (!enoughObjects) {//如果没有足够的空间,那么扩展后重新写入        size_t newSize = ((mObjectsSize+2)*3)/2;        size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));        if (objects == NULL) return NO_MEMORY;        mObjects = objects;        mObjectsCapacity = newSize;    }        goto restart_write;}
      Parcel类内部有mData和mObjects两个缓冲区,其中,mData是一个数据缓冲区,它里面的内容可能包含有整数、字符串或者Binder对象,即flat_binder_object结构体;mObjects是一个偏移数组,它保存了数据缓冲区中所有Binder对象的位置。Binder驱动程序就是可以通过这个偏移数组找到进程间通信数据中的Binder对象的,以便对它们进行特殊处理。

      Parcel类的成员变量mDataPos记录了数据缓冲区mData下一个用来写入数据的位置,而成员变量mDataCapacity则记录了数据缓冲区mData的总大小。成员变量mObjectSize记录了偏移数组mObjects下一个用于写入数据的位置,mObjectCapacity则记录了偏移数组mObjects的总大小。

      如果有足够的缓冲区,那么要将flat_binder_object结构体存入数据缓冲区mData,flat_binder_object结构体在mData中偏移写入偏移数组mObjects。

      如果数据缓冲区mData和偏移数组mObjects没有足够的空间来写入一个Binder对象,首先扩展他们的空间,然后再写入。

  相关解决方案