android系統應用層使用Binder進程間通訊的時候並非直接和binder驅動程序互動,而是經過了一個封裝庫,咱們稱之爲Binder進程間通訊庫。node
咱們以前說到了Client組件和Servicr組件,分別對應Binder驅動程序中的Binder實體對象(binder_node)和Binder引用對象(binder_ref)。在Binder通訊庫中也有兩個類和之對應,分別是Binder本地對象BnInterface 表示Service和 Binder代理對象 BpInterface 表示clientandroid
這兩個接口都定義在/frameworks/native/include/binder/IInterface.h 文件中。架構
// ---------------------------------------------------------------------- template<typename INTERFACE> class BnInterface : public INTERFACE, public BBinder { public: virtual sp<IInterface> queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const; protected: virtual IBinder* onAsBinder(); }; // ---------------------------------------------------------------------- template<typename INTERFACE> class BpInterface : public INTERFACE, public BpRefBase { public: explicit BpInterface(const sp<IBinder>& remote); protected: virtual IBinder* onAsBinder(); }; // ----------------------------------------------------------------------
這裏用到了一種頗有意思的寫法,用模板參數Interface表示一個類,而後BnInterface和BpInterface都直接繼承了這個類。至於INTERFACE具體是什麼,後面再看。函數
BnInterface繼承了BBinder類,定義在/frameworks/native/include/binder/Binder.h ui
class BBinder : public IBinder { .... virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); .... virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); .... };
關鍵是其中的兩個函數,當Binder代理對象(Client) 經過Binder驅動程序向一個Binder本地對象(Service)發出一個進程間通訊請求時,Binder驅動程序會調用 Binder本地對象(Service)的 transact方法。咱們在後面實例中將會看到。spa
BpInterface繼承了BpRefBase,一樣定義在/frameworks/native/include/binder/Binder.h 中。其中有一個很是重要的成員變量mRemote,他會指向一個BpBinder對象。線程
BpBinder定義在/frameworks/native/include/binder/BpBinder.h 該類中有一個成員變量mHandle是一個整數,表明一個句柄,直接指向了Binder驅動程序中的Client組件,也就是一個binder_ref的結構體。這裏就創建了binder驅動程序和binder進程間通訊庫的對應關係。代理
BpBinder中的函數transact方法用來向Server進程中的Service組件發送進程間通訊請求(固然這是經過Binder驅動程序來實現的。)這個方法會把mHander和通訊數據發送給驅動程序,這樣,驅動程序就可以先找到相應的Client組件(binder_ref),繼而找到對應的Service組件(binder_node),最後將數據發送給這個Service組件。code
從上文可知,不管是BBinder類仍是BpBinder類,都須要和binder驅動程序進行交互,可是實際上,他並非本身去操做的,而是經過一個IPCThreadState的類來進行交互。server
定義在/frameworks/native/include/binder/IPCThreadState.h 咱們知道,每個使用binder進程間通訊的進程都會維護一個線程池,每個線程都會對應一個IPCThreadState對象。
其中成員變量self指向本身,成員函數transanct用來和驅動程序交互(內部進一步會調用成員函數talkWithDriver)。
IPCThreadState 內部有一個成員變量mProcess,是一個ProcessState對象,對應使用了進程間通訊的進程。它會負責初始化Binder設備(打開/dev/binder設備文件),將設備文件映射到進程的地址空間。
定義在/frameworks/native/include/binder/ProcessState.h 類中有一個靜態方法self,經過調用ProcessState.self就能過獲取進程惟一ProcessState對象(該對象是在第一次調用ProcessState.self方法時建立,同時調用函數open打開設備文件,調用mmap映射地址空間,而且將用戶空間的虛擬地址空間的地址存放在mVMStart中)。
假設咱們存在一個硬件設備叫作Frag,該硬件設備是一個簡單的寄存器,只有簡單的存取功能。如今咱們有一個service進程,用來管理這個設備,同時向外提供了訪問服務。
如今有一個client進程想要訪問這個設備,這就涉及到進程通訊了,咱們嘗試實現這個架構。
顯而易見,總歸有兩個模塊,一個server模塊,用來表示service進程。一個client模塊,用來表示 client進程。可是,對於兩個想要通訊的進程來講,雖然有了溝通途徑(binder),可是還須要定義一門溝通語言。在binder進程間通訊中,咱們把這個共同語言叫作 服務接口 。只有定義了這個以後,才能無障礙交流。因此還存在第三個模塊common(server 和 client都要使用到)
其中服務接口都會繼承與 IInterface 接口,順帶一提這個接口定義以下
class IInterface : public virtual RefBase { public: IInterface(); static sp<IBinder> asBinder(const IInterface*); static sp<IBinder> asBinder(const sp<IInterface>&); protected: virtual ~IInterface(); virtual IBinder* onAsBinder() = 0; };
幾乎只有一個asBinder方法而已。
對於本例,咱們定義了一個IFregService
#define FREG_SERVICE "shy.luo.FregService" using namespace android; class IFregService: public IInterface { public: DECLARE_META_INTERFACE(FregService); virtual int32_t getVal() = 0; virtual void setVal(int32_t val) = 0; };
該方法定義了getVal和setVal。另外 DECLARE_META_INTERFACE是一個宏,定義在/frameworks/native/include/binder/IInterface.h 。裏面預先寫好了IInterface實現類須要重寫的方法,主要是對這個組件進行命名(descriptor)和一個asInterface方法,該方法的做用主要是經過一個IBinder對象來獲取對應的代理對象,經過代理對象向service進程請求功能。
相對的還有一個用來實現的宏IMPLEMENT_META_INTERFACE一樣定義在/frameworks/native/include/binder/IInterface.h ,主要是用來實現一個asInterface方法。
除了服務接口以外,咱們還須要實現兩個類,分別繼承與BnInterface和BpInterface,表示真正的本地對象和代理對象。
class BnFregService: public BnInterface<IFregService> { public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; class BpFregService: public BpInterface<IFregService> { public: BpFregService(const sp<IBinder>& impl) : BpInterface<IFregService>(impl) { } public: int32_t getVal() { Parcel data; data.writeInterfaceToken(IFregService::getInterfaceDescriptor()); Parcel reply; remote()->transact(GET_VAL, data, &reply); int32_t val = reply.readInt32(); return val; } void setVal(int32_t val) { Parcel data; data.writeInterfaceToken(IFregService::getInterfaceDescriptor()); data.writeInt32(val); Parcel reply; remote()->transact(SET_VAL, data, &reply); } };
BpFregService的實現相對比較容易理解,getVal和setVal實際操做上並麼有區別,都是首先將參數防撞在一個Parcel對象中,而後調用父類BpBinder的transact向service組件發送請求(固然這個會經過binder驅動程序)。
BnFregService雖然是一個本地對象,可是他並非負責實現setVal和getVal的實現(實現會交給它的子類,這裏是FregService),主要是實現了上面介紹的onTransact方法,用來分發收到的命令。
status_t BnFregService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case GET_VAL: { CHECK_INTERFACE(IFregService, data, reply); int32_t val = getVal(); reply->writeInt32(val); return NO_ERROR; } case SET_VAL: { CHECK_INTERFACE(IFregService, data, reply); int32_t val = data.readInt32(); setVal(val); return NO_ERROR; } default: { return BBinder::onTransact(code, data, reply, flags); } } }
好比這裏咱們定義了兩個命令GET_VAL和SET_VAL(上面的BpFregService的setVal和getVal都會發送相應的命令。)分別交給子類的getVal和setVal方法去處理。
common模塊的內容大概就是這麼多,接下去是service模塊,真正實現getVal和setVal功能,並向外提供服務的模塊
class FregService : public BnFregService { public: FregService() { fd = open(FREG_DEVICE_NAME, O_RDWR); if(fd == -1) { LOGE("Failed to open device %s.\n", FREG_DEVICE_NAME); } } virtual ~FregService() { if(fd != -1) { close(fd); } } public: static void instantiate() { defaultServiceManager()->addService(String16(FREG_SERVICE), new FregService()); } int32_t getVal() { int32_t val = 0; if(fd != -1) { read(fd, &val, sizeof(val)); } return val; } void setVal(int32_t val) { if(fd != -1) { write(fd, &val, sizeof(val)); } } private: int fd; }; int main(int argc, char** argv) { FregService::instantiate(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); return 0; }
就FregService類來講並不複雜,繼承了BnFregService,主要的做用就是經過open打開設備文件,而後經過write和read來操做設備文件(這不是binder的工做,而是設備驅動自己的工做內容)。
主要的工做內容仍是集中在main方法上,首先調用
defaultServiceManager()->addService(String16(FREG_SERVICE), new FregService());
該代碼的主要做用就是將本service註冊到ServiceManager中(實現咱們之後會看到)。而後調用startThreadPool來啓動一個Binder線程池,而後經過joinThreadPool將當前線程添加到線程池中,這樣就可以開始處理客戶端的請求了。
客戶端的代碼以下
int main() { sp<IBinder> binder = defaultServiceManager()->getService(String16(FREG_SERVICE)); if(binder == NULL) { LOGE("Failed to get freg service: %s.\n", FREG_SERVICE); return -1; } sp<IFregService> service = IFregService::asInterface(binder); if(service == NULL) { LOGE("Failed to get freg service interface.\n"); return -2; } printf("Read original value from FregService:\n"); int32_t val = service->getVal(); printf(" %d.\n", val); printf("Add value 1 to FregService.\n"); val += 1; service->setVal(val); printf("Read the value from FregService again:\n"); val = service->getVal(); printf(" %d.\n", val); return 0; }
首先經過getService從ServiceManager中訊中相應的服務類,返回值是一個IBinder對象,而後將IBinder轉換成爲定義的IFregService子類,實際上就是BpFregService類型的對象。
至此整個demo結束。