本文参考《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类图。
~/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对象,首先扩展他们的空间,然后再写入。