深入分析AndroidBinder機制(遠程對象訪問)


介紹

Binder是什么?它可以叫作:IPC、RPC、線程遷移、遠程對象訪問,本文中理解它為遠程對象訪問更貼切些,簡而言之就是一個進程能訪問另一個進程中的對象,調用該對象的方法,就好像對象在自己的進程中一樣,這種訪問是同步的訪問,當然Binder也能實現異步的通信。

Binder基於C/S架構:

Binder分為Java和C++兩套實現,分別用於Java應用和Native應用開發,Java Binder實際上也是基於C++ Binder的一個封裝,因此本文只分析C++ Binder。

服務分為2種:Native Service、Android 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),它就像進程打開某個文件產生的文件描述符一樣,進程每引用一個服務,就會分配一個最小未使用的整數作為handle。handle是客戶進程相關的,多個進程引用同一個服務得到的handle並不是一樣的。

當服務進程向ServiceManager注冊服務時,會帶上服務的名稱字符串,驅動會為服務進程中的服務對象增加一個binder_node,歸屬於服務進程的binder_proc。

當把注冊服務的請求發給ServiceManager時,ServiceManager也是服務對象的一個引用者,驅動會為ServiceManager增加一個binder_ref,指向服務對象的binder_node。驅動把binder_ref.desc(ServiceManager)作為handle返回給ServiceManager,ServiceManager保存此handle和服務名稱字符串。

當客戶進程向ServiceManager獲取服務時,ServiceManager根據服務名稱字符串找到服務對象在ServiceManager進程中的handle。在ServiceManager的應答的過程中,驅動根據此handle在ServiceManager進程的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代表代理

ProcessState、IPCThreadState是進程、線程相關,是對Binder驅動的封裝

Binder核心庫又是對ProcessState、IPCThreadState的封裝

C++ Binder框架是對Binder核心庫和服務接口的封裝

 

類關系圖:

`

說明:綠色部分是用戶編寫應用程序需要實現的

 

IPCThreadState、ProcessState、Binder關系圖:

 

 

對於Binder核心庫:

IBinder:是一個接口,被BpBinder、Bbinder繼承

BpBinder:客戶端,內部有一個成員mHandle記錄了遠程服務對象的handle

BpRefBase:客戶端,內部有一個成員指向BpBinder,采用的是Bridge設計模式,實際是是通過BpBinder來完成通信

Bbinder:服務端

 

對於C++ Binder框架:

Iinterface:主要是定義了asBinder()、純虛函數onAsBinder(),asBinder()直接調用onAsBinder(),onAsBinder()分別在BnInterface、BpInterface中進行了實現,用於獲取BnInterface、BpBinder的地址,即IInterface的作用是通過接口獲取對應的Binder對象的本地地址/代理BpBinder的地址。

BpInterface<XXX>:是一個接口,一個模板類,是一個粘合類,即繼承BpInterface<XXX>便等同於同時繼承IXXX和BpRefBase。

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對象)和其對應的handle(Binder驅動為每個Service維護一個handle,對handle的操作封裝在ProcessState中維護的BpBinder對象中)

ProcessState是singleton模式,使用靜態成員函數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()

作用:為Service的handle創建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) {

         // 1、BpBinder對象在創建時設置了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不為NULL,expungeHandle()也無法執行把它置成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->refs是e->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()。

IPCThreadState是singleton模式,使用靜態成員函數IPCThreadState::self()來構造。

 

構造函數:

 

IPCThreadState::IPCThreadState()

{

     mProcess(ProcessState::self())

     mMyThreadId(androidGetTid())       //調用gettid()或getpid(),返回pid_t,所以線程也是當成輕量級里程看待的

     pthread_setspecific(gTLS, this);   //設置線程私有數據,把IPCThreadState關聯到全局靜態變量gTLS(Thread Local Storage),而gTLS在IPCThreadState::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::mOut(Parcel)中包含的binder_transaction_data封裝成binder_write_read寫到驅動,從驅動讀取到的binder_write_read中包含的binder_transaction_data寫到IPCThreadState::mIn(Parcel)

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()創建,創建時會記錄下Service的handle,並增加句柄的引用計數(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,...)     // mHandle在ProcessState::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()

//輸入BpBinder或BBinder,構造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_node、binder_ref

            Parcel::writeObject()

}

 

Parcel::readStrongBinder()

接收應答時,從Parcel取出binder信息

 

Parcel::readStrongBinder()

//返回BpBinder或BBinder,會把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()分別在BnInterface、BpInterface中進行了實現,用於獲取BnInterface、BpBinder的地址,即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。

函數的參數可以是BpBinder或BBinder,返回的是BpXXX或BnXXX。

 

template<typename INTERFACE>

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

{

     return INTERFACE::asInterface(obj);

}

       函數直接調用了IXXX::asInterface(),它是通過宏DECLARE_META_INTERFACE、IMPLEMENT_META_INTERFACE來聲明和實現的。

 

DECLARE_META_INTERFACE、IMPLEMENT_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.h、XXX.cpp:

定義class XXX:public BnXXX
實現接口的方法

 

BpXXX

 

構造函數

參數為BpBinder,BpXXX的構造函數中有一個參數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繼承BpRefBase,BpRefBase定義了成員函數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()

請求處理函數

對於客戶端請求服務,返回的是Service的handle,binder類型是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()創建BpBinder,handle為0

     } else {

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

     }

}

 

注冊服務

 

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

//參數service可以是BpBinder或BBinder,binder驅動會記錄下對象的地址

{

     data.writeStrongBinder(service);

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

}

 

查詢服務

 

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

//函數返回BpBinder或BBinder

{

     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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM