理解Android Binder機(jī)制(2/3):C++層
本文是Android Binder機(jī)制解析的第二篇文章,會講解Binder Framework的C++部分邏輯。
本系列的文章列表如下:
- 理解Android Binder機(jī)制(1/3):驅(qū)動篇
- 理解Android Binder機(jī)制(2/3):C++層
- 理解Android Binder機(jī)制(3/3):Java層
前言
Framework是一個中間層,它對接了底層實(shí)現(xiàn),封裝了復(fù)雜的內(nèi)部邏輯,并提供供外部使用的接口。Framework層是應(yīng)用程序開發(fā)的基礎(chǔ)。
Binder Framework層分為C++和Java兩個部分,為了達(dá)到功能的復(fù)用,中間通過JNI進(jìn)行銜接。
Binder Framework的C++部分,頭文件位于這個路徑:/frameworks/native/include/binder/,實(shí)現(xiàn)位于這個路徑:/frameworks/native/libs/binder/ 。Binder庫最終會編譯成一個動態(tài)鏈接庫:libbinder.so,供其他進(jìn)程鏈接使用。
為了便于說明,下文中我們將Binder Framework 的C++部分稱之為libbinder。
主要結(jié)構(gòu)
libbinder中,將實(shí)現(xiàn)分為Proxy和Native兩端。Proxy對應(yīng)了上文提到的Client端,是服務(wù)對外提供的接口。而Native是服務(wù)實(shí)現(xiàn)的一端,對應(yīng)了上文提到的Server端。類名中帶有小寫字母p的(例如BpInterface),就是指Proxy端。類名帶有小寫字母n的(例如BnInterface),就是指Native端。
Proxy代表了調(diào)用方,通常與服務(wù)的實(shí)現(xiàn)不在同一個進(jìn)程,因此下文中,我們也稱Proxy端為“遠(yuǎn)程”端。Native端是服務(wù)實(shí)現(xiàn)的自身,因此下文中,我們也稱Native端為”本地“端。
這里,我們先對libbinder中的主要類做一個簡要說明,了解一下它們的關(guān)系,然后再詳細(xì)的講解。
| 類名 | 說明 |
|---|---|
| BpRefBase | RefBase的子類,提供remote()方法獲取遠(yuǎn)程Binder |
| IInterface | Binder服務(wù)接口的基類,Binder服務(wù)通常需要同時提供本地接口和遠(yuǎn)程接口 |
| BpInterface | 遠(yuǎn)程接口的基類,遠(yuǎn)程接口是供客戶端調(diào)用的接口集 |
| BnInterface | 本地接口的基類,本地接口是需要服務(wù)中真正實(shí)現(xiàn)的接口集 |
| IBiner | Binder對象的基類,BBinder和BpBinder都是這個類的子類 |
| BpBinder | 遠(yuǎn)程Binder,這個類提供transact方法來發(fā)送請求,BpXXX實(shí)現(xiàn)中會用到 |
| BBinder | 本地Binder,服務(wù)實(shí)現(xiàn)方的基類,提供了onTransact接口來接收請求 |
| ProcessState | 代表了使用Binder的進(jìn)程 |
| IPCThreadState | 代表了使用Binder的線程,這個類中封裝了與Binder驅(qū)動通信的邏輯 |
| Parcel | 在Binder上傳遞的數(shù)據(jù)的包裝器 |
下圖描述了這些類之間的關(guān)系:
另外說明一下,Binder服務(wù)的實(shí)現(xiàn)類(圖中紫色部分)通常都會遵守下面的命名規(guī)則:
- 服務(wù)的接口使用I字母作為前綴
- 遠(yuǎn)程接口使用Bp作為前綴
-
本地接口使用Bn作為前綴
圖片.png
看了上面這些介紹,你可能還是不太容易理解。不過不要緊,下面我們會逐步拆分講解這些內(nèi)容。
在這幅圖中,淺黃色部分的結(jié)構(gòu)是最難理解的,因此我們先從它們著手。
我們先來看看IBinder這個類。這個類描述了所有在Binder上傳遞的對象,它既是Binder本地對象BBinder的父類,也是Binder遠(yuǎn)程對象BpBinder的父類。這個類中的主要方法說明如下:
| 類名 | 說明 |
|---|---|
| localBinder | 獲取本地Binder對象 |
| remoteBinder | 獲取遠(yuǎn)程Binder對象 |
| transact | 進(jìn)行一次Binder操作 |
| queryLocalInterface | 嘗試獲取本地Binder,如何失敗返回NULL |
| getInterfaceDescriptor | 獲取Binder的服務(wù)接口描述,其實(shí)就是Binder服務(wù)的唯一標(biāo)識 |
| isBinderAlive | 查詢Binder服務(wù)是否還活著 |
| pingBinder | 發(fā)送PING_TRANSACTION給Binder服務(wù) |
BpBinder的實(shí)例代表了遠(yuǎn)程Binder,這個類的對象將被客戶端調(diào)用。其中handle方法會返回指向Binder服務(wù)實(shí)現(xiàn)者的句柄,這個類最重要就是提供了transact方法,這個方法會將遠(yuǎn)程調(diào)用的參數(shù)封裝好發(fā)送的Binder驅(qū)動。
由于每個Binder服務(wù)通常都會提供多個服務(wù)接口,而這個方法中的uint32_t code參數(shù)就是用來對服務(wù)接口進(jìn)行編號區(qū)分的。Binder服務(wù)的每個接口都需要指定一個唯一的code,這個code要在Proxy和Native端配對好。當(dāng)客戶端將請求發(fā)送到服務(wù)端的時候,服務(wù)端根據(jù)這個code(onTransact方法中)來區(qū)分調(diào)用哪個接口方法。
BBinder的實(shí)例代表了本地Binder,它描述了服務(wù)的提供方,所有Binder服務(wù)的實(shí)現(xiàn)者都要繼承這個類(的子類),在繼承類中,最重要的就是實(shí)現(xiàn)onTransact方法,因?yàn)檫@個方法是所有請求的入口。因此,這個方法是和BpBinder中的transact方法對應(yīng)的,這個方法同樣也有一個uint32_t code參數(shù),在這個方法的實(shí)現(xiàn)中,由服務(wù)提供者通過code對請求的接口進(jìn)行區(qū)分,然后調(diào)用具體實(shí)現(xiàn)服務(wù)的方法。
IBinder中定義了uint32_t code允許的范圍:
FIRST_CALL_TRANSACTION = 0x00000001,
LAST_CALL_TRANSACTION = 0x00ffffff,
Binder服務(wù)要保證自己提供的每個服務(wù)接口有一個唯一的code,例如某個Binder服務(wù)可以將:add接口code設(shè)為1,minus接口code設(shè)為2,multiple接口code設(shè)為3,divide接口code設(shè)為4,等等。
講完了IBinder,BpBinder和BBinder三個類,我們再來看看BpReBase,IInterface,BpInterface和BnInterface。
每個Binder服務(wù)都是為了某個功能而實(shí)現(xiàn)的,因此其本身會定義一套接口集(通常是C++的一個類)來描述自己提供的所有功能。而Binder服務(wù)既有自身實(shí)現(xiàn)服務(wù)的類,也要有給客戶端進(jìn)程調(diào)用的類。為了便于開發(fā),這兩中類里面的服務(wù)接口應(yīng)當(dāng)是一致的,例如:假設(shè)服務(wù)實(shí)現(xiàn)方提供了一個接口為add(int a, int b)的服務(wù)方法,那么其遠(yuǎn)程接口中也應(yīng)當(dāng)有一個add(int a, int b)方法。因此為了實(shí)現(xiàn)方便,本地實(shí)現(xiàn)類和遠(yuǎn)程接口類需要有一個公共的描述服務(wù)接口的基類(即上圖中的IXXXService)來繼承。而這個基類通常是IInterface的子類,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;
};
之所以要繼承自IInterface類是因?yàn)檫@個類中定義了onAsBinder讓子類實(shí)現(xiàn)。onAsBinder在本地對象的實(shí)現(xiàn)類中返回的是本地對象,在遠(yuǎn)程對象的實(shí)現(xiàn)類中返回的是遠(yuǎn)程對象。onAsBinder方法被兩個靜態(tài)方法asBinder方法調(diào)用。有了這些接口之后,在代碼中便可以直接通過IXXX::asBinder方法獲取到不用區(qū)分本地還是遠(yuǎn)程的IBinder對象。這個在跨進(jìn)程傳遞Binder對象的時候有很大的作用(因?yàn)椴挥脜^(qū)分具體細(xì)節(jié),只要直接調(diào)用和傳遞就好)。
下面,我們來看一下BpInterface和BnInterface的定義:
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:
BpInterface(const sp<IBinder>& remote);
protected:
virtual IBinder* onAsBinder();
};
這兩個類都是模板類,它們在繼承自INTERFACE的基礎(chǔ)上各自繼承了另外一個類。這里的INTERFACE便是我們Binder服務(wù)接口的基類。另外,BnInterface繼承了BBinder類,由此可以通過復(fù)寫onTransact方法來提供實(shí)現(xiàn)。BpInterface繼承了BpRefBase,通過這個類的remote方法可以獲取到指向服務(wù)實(shí)現(xiàn)方的句柄。在客戶端接口的實(shí)現(xiàn)類中,每個接口在組裝好參數(shù)之后,都會調(diào)用remote()->transact來發(fā)送請求,而這里其實(shí)就是調(diào)用的BpBinder的transact方法,這樣請求便通過Binder到達(dá)了服務(wù)實(shí)現(xiàn)方的onTransact中。這個過程如下圖所示:

基于Binder框架開發(fā)的服務(wù),除了滿足上文提到的類名規(guī)則之外,還需要遵守其他一些共同的規(guī)約:
- 為了進(jìn)行服務(wù)的區(qū)分,每個Binder服務(wù)需要指定一個唯一的標(biāo)識,這個標(biāo)識通過
getInterfaceDescriptor返回,類型是一個字符串。通常,Binder服務(wù)會在類中定義static const android::String16 descriptor;這樣一個常量來描述這個標(biāo)識符,然后在getInterfaceDescriptor方法中返回這個常量。 - 為了便于調(diào)用者獲取到調(diào)用接口,服務(wù)接口的公共基類需要提供一個
android::sp<IXXX> asInterface方法來返回基類對象指針。
由于上面提到的這兩點(diǎn)對于所有Binder服務(wù)的實(shí)現(xiàn)邏輯都是類似的。為了簡化開發(fā)者的重復(fù)工作,在libbinder中,定義了兩個宏來簡化這些重復(fù)工作,它們是
#define DECLARE_META_INTERFACE(INTERFACE) \
static const android::String16 descriptor; \
static android::sp<I##INTERFACE> asInterface( \
const android::sp<android::IBinder>& obj); \
virtual const android::String16& getInterfaceDescriptor() const; \
I##INTERFACE(); \
virtual ~I##INTERFACE(); \
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const android::String16 I##INTERFACE::descriptor(NAME); \
const android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
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; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { } \
- DECLARE_META_INTERFACE 宏的解析:
這段代碼是一個宏定義,用于在Android的C++代碼中生成一些通用的接口聲明和定義。這個宏的目的是為了簡化接口的實(shí)現(xiàn)和聲明,特別是在與Android的Binder IPC(進(jìn)程間通信)系統(tǒng)交互時。
讓我們逐步解析這個宏:
#define DECLARE_META_INTERFACE(INTERFACE):這是一個宏定義,名為DECLARE_META_INTERFACE,它接受一個參數(shù)INTERFACE。
static const android::String16 descriptor;: 這定義了一個靜態(tài)常量字符串,名為descriptor,類型為android::String16。這通常用于存儲該接口的描述符,即一個唯一標(biāo)識該接口的字符串。
static android::sp<I##INTERFACE> asInterface(...);: 這是一個靜態(tài)方法,返回一個指向I##INTERFACE類型的智能指針(android::sp)。##是C/C++預(yù)處理器中的連接符,用于連接I和INTERFACE(宏的參數(shù))。這個方法的目的是將一個IBinder對象轉(zhuǎn)換為對應(yīng)的接口。
virtual const android::String16& getInterfaceDescriptor() const;: 這是一個虛方法,返回接口的描述符(即descriptor)。這是Binder IPC系統(tǒng)的一部分,用于驗(yàn)證接口的身份。
I##INTERFACE();: 這是接口的默認(rèn)構(gòu)造函數(shù)。由于使用了##連接符,所以它會變成IINTERFACE(),其中INTERFACE是宏的參數(shù)。
virtual ~I##INTERFACE();: 這是接口的虛析構(gòu)函數(shù)。與構(gòu)造函數(shù)類似,使用##連接符將其變成 ~IINTERFACE()。
當(dāng)你使用這個宏時,你需要提供一個接口名作為參數(shù)。例如:
DECLARE_META_INTERFACE(MyInterface);
這將會展開為:
static const android::String16 descriptor;
static android::sp<IMyInterface> asInterface(const android::sp<android::IBinder>& obj);
virtual const android::String16& getInterfaceDescriptor() const;
IMyInterface();
virtual ~IMyInterface();
- 名為IMPLEMENT_META_INTERFACE,它用于實(shí)現(xiàn)Android中Binder IPC接口的一部分。這個宏為指定的接口生成了必要的成員函數(shù)實(shí)現(xiàn),包括描述符的靜態(tài)成員變量、獲取接口描述符的方法、將IBinder對象轉(zhuǎn)換為接口的方法(asInterface),以及接口的默認(rèn)構(gòu)造函數(shù)和析構(gòu)函數(shù)。
讓我們逐行解析這個宏:
`#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)`: 定義一個名為IMPLEMENT_META_INTERFACE的宏,它接受兩個參數(shù):INTERFACE(接口名)和NAME(接口的描述符字符串)。
2-3. const android::String16 I##INTERFACE::descriptor(NAME);: 定義并初始化接口的靜態(tài)成員變量descriptor,其類型為android::String16。這里使用了##連接符來拼接I和INTERFACE,形成完整的接口名。NAME是傳遞給宏的第二個參數(shù),即接口的描述符字符串。
4-8. const android::String16& I##INTERFACE::getInterfaceDescriptor() const: 實(shí)現(xiàn)接口的getInterfaceDescriptor方法,該方法返回接口的描述符。這個方法很簡單,只是返回之前定義的靜態(tài)成員變量descriptor。
10-26. android::sp<I##INTERFACE> I##INTERFACE::asInterface(...): 實(shí)現(xiàn)接口的asInterface方法,該方法嘗試將IBinder對象轉(zhuǎn)換為對應(yīng)的接口。首先,它創(chuàng)建一個I##INTERFACE類型的智能指針intr。然后,如果傳入的obj(一個IBinder對象的智能指針)不為空,它嘗試通過調(diào)用queryLocalInterface方法獲取本地接口,如果失敗,則創(chuàng)建一個Bp##INTERFACE(Binder Proxy)對象,并將obj傳遞給它。最后,返回intr。
28-29. I##INTERFACE::I##INTERFACE() { }: 實(shí)現(xiàn)接口的默認(rèn)構(gòu)造函數(shù),它什么也不做。
31-32. I##INTERFACE::~I##INTERFACE() { }: 實(shí)現(xiàn)接口的析構(gòu)函數(shù),它同樣什么也不做。這是因?yàn)榻涌谕ǔ2话魏涡枰@式清理的資源。
當(dāng)使用這個宏時,你需要提供接口名和描述符字符串作為參數(shù)。例如:
class IMyInterface : public android::IInterface {
// ... 其他接口方法和聲明 ...
};
IMPLEMENT_META_INTERFACE(MyInterface, "com.example.IMyInterface");
這將為IMyInterface生成上述的成員函數(shù)實(shí)現(xiàn),包括描述符、getInterfaceDescriptor、asInterface、默認(rèn)構(gòu)造函數(shù)和析構(gòu)函數(shù)。這樣,你就不需要手動為這些常見的函數(shù)實(shí)現(xiàn)編寫代碼了
有了這兩個宏之后,開發(fā)者只要在接口基類(IXXX)頭文件中,使用DECLARE_META_INTERFACE宏便完成了需要的組件的聲明。然后在cpp文件中使用IMPLEMENT_META_INTERFACE便完成了這些組件的實(shí)現(xiàn)。
Binder的初始化
在講解Binder驅(qū)動的時候我們就提到:任何使用Binder機(jī)制的進(jìn)程都必須要對/dev/binder設(shè)備進(jìn)行open以及mmap之后才能使用,這部分邏輯是所有使用Binder機(jī)制進(jìn)程共同的。對于這種共同邏輯的封裝便是Framework層的職責(zé)之一。libbinder中,ProcessState類封裝了這個邏輯,相關(guān)代碼見下文。
這里是ProcessState構(gòu)造函數(shù),在這個函數(shù)中,初始化mDriverFD的時候調(diào)用了open_driver方法打開binder設(shè)備,然后又在函數(shù)體中,通過mmap進(jìn)行內(nèi)存映射。
ProcessState::ProcessState()
: mDriverFD(open_driver())
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mStarvationStartTimeMs(0)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -1;
}
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
open_driver的函數(shù)實(shí)現(xiàn)如下所示。在這個函數(shù)中完成了三個工作:
- 首先通過open系統(tǒng)調(diào)用打開了dev/binder設(shè)備
- 然后通過ioctl獲取Binder實(shí)現(xiàn)的版本號,并檢查是否匹配
- 最后通過ioctl設(shè)置進(jìn)程支持的最大線程數(shù)量
關(guān)于這部分邏輯背后的處理,在講解Binder驅(qū)動的時候,我們已經(jīng)講解過了。
static int open_driver()
{
int fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -1;
}
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
}
return fd;
}
ProcessState是一個Singleton(單例)類型的類,在一個進(jìn)程中,只會存在一個實(shí)例。通過ProcessState::self()接口獲取這個實(shí)例。一旦獲取這個實(shí)例,便會執(zhí)行其構(gòu)造函數(shù),由此完成了對于Binder設(shè)備的初始化工作。
關(guān)于Binder傳遞數(shù)據(jù)的大小限制
由于Binder的數(shù)據(jù)需要跨進(jìn)程傳遞,并且還需要在內(nèi)核上開辟空間,因此允許在Binder上傳遞的數(shù)據(jù)并不是無無限大的。mmap中指定的大小便是對數(shù)據(jù)傳遞的大小限制:
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) // 1M - 8k
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
這里我們看到,在進(jìn)行mmap的時候,指定了最大size為BINDER_VM_SIZE,即 1M - 8k的大小。 因此我們在開發(fā)過程中,一次Binder調(diào)用的數(shù)據(jù)總和不能超過這個大小。
對于這個區(qū)域的大小,我們也可以在設(shè)備上進(jìn)行確認(rèn)。這里我們還之前提到的system_server為例。上面我們講解了通過procfs來獲取映射的內(nèi)存地址,除此之外,我們也可以通過showmap命令,來確定這塊區(qū)域的大小,相關(guān)命令如下:
angler:/ # ps | grep system_server
system 1889 526 2353404 135968 SyS_epoll_ 72972eeaf4 S system_server
angler:/ # showmap 1889 | grep "/dev/binder"
1016 4 4 0 0 4 0 0 1 /dev/binder
這里可以看到,這塊區(qū)域的大小正是 1M - 8K = 1016k。
Tips: 通過showmap命令可以看到進(jìn)程的詳細(xì)內(nèi)存占用情況。在實(shí)際的開發(fā)過程中,當(dāng)我們要對某個進(jìn)程做內(nèi)存占用分析的時候,這個命令是相當(dāng)有用的。建議讀者嘗試通過showmap命令查看system_server或其他感興趣進(jìn)程的完整map,看看這些進(jìn)程都依賴了哪些庫或者模塊,以及內(nèi)存占用情況是怎樣的。
與驅(qū)動的通信
上文提到ProcessState是一個單例類,一個進(jìn)程只有一個實(shí)例。而負(fù)責(zé)與Binder驅(qū)動通信的IPCThreadState也是一個單例類。但這個類不是一個進(jìn)程只有一個實(shí)例,而是一個線程有一個實(shí)例。
IPCThreadState負(fù)責(zé)了與驅(qū)動通信的細(xì)節(jié)處理。這個類中的關(guān)鍵幾個方法說明如下:
| 方法 | 說明 |
|---|---|
| transact | 公開接口。供Proxy發(fā)送數(shù)據(jù)到驅(qū)動,并讀取返回結(jié)果 |
| sendReply | 供Server端寫回請求的返回結(jié)果 |
| waitForResponse | 發(fā)送請求后等待響應(yīng)結(jié)果 |
| talkWithDriver | 通過ioctl BINDER_WRITE_READ來與驅(qū)動通信 |
| writeTransactionData | 寫入一次事務(wù)的數(shù)據(jù) |
| executeCommand | 處理binder_driver_return_protocol協(xié)議命令 |
| freeBuffer | 通過BC_FREE_BUFFER命令釋放Buffer |
BpBinder::transact方法在發(fā)送請求的時候,其實(shí)就是直接調(diào)用了IPCThreadState對應(yīng)的方法來發(fā)送請求到Binder驅(qū)動的,相關(guān)代碼如下:
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
而IPCThreadState::transact方法主要邏輯如下:
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck();
flags |= TF_ACCEPT_FDS;
if (err == NO_ERROR) {
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
這段代碼應(yīng)該還是比較好理解的:首先通過writeTransactionData寫入數(shù)據(jù),然后通過waitForResponse等待返回結(jié)果。TF_ONE_WAY表示此次請求是單向的,即:不用真正等待結(jié)果即可返回。
而writeTransactionData方法其實(shí)就是在組裝binder_transaction_data數(shù)據(jù):
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
binder_transaction_data tr;
tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
tr.offsets_size = 0;
tr.data.ptr.offsets = 0;
} else {
return (mLastError = err);
}
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
對于binder_transaction_data在講解Binder驅(qū)動的時候我們已經(jīng)詳細(xì)講解過了。而這里的Parcel我們還不了解,那么接下來我們馬上就來看一下這個類。
數(shù)據(jù)包裝器:Parcel
Binder上提供的是跨進(jìn)程的服務(wù),每個服務(wù)包含了不同的接口,每個接口的參數(shù)數(shù)量和類型都不一樣。那么當(dāng)客戶端想要調(diào)用服務(wù)端的接口,參數(shù)是如何跨進(jìn)程傳遞給服務(wù)端的呢?除此之外,服務(wù)端想要給客戶端返回結(jié)果,結(jié)果又是如何傳遞回來的呢?
這些問題的答案就是:Parcel。Parcel就像一個包裝器,調(diào)用者可以以任意順序往里面放入需要的數(shù)據(jù),所有寫入的數(shù)據(jù)就像是被打成一個整體的包,然后可以直接在Binde上傳輸。
Parcel提供了所有基本類型的寫入和讀出接口,下面是其中的一部分:
...
status_t writeInt32(int32_t val);
status_t writeUint32(uint32_t val);
status_t writeInt64(int64_t val);
status_t writeUint64(uint64_t val);
status_t writeFloat(float val);
status_t writeDouble(double val);
status_t writeCString(const char* str);
status_t writeString8(const String8& str);
status_t readInt32(int32_t *pArg) const;
uint32_t readUint32() const;
status_t readUint32(uint32_t *pArg) const;
int64_t readInt64() const;
status_t readInt64(int64_t *pArg) const;
uint64_t readUint64() const;
status_t readUint64(uint64_t *pArg) const;
float readFloat() const;
status_t readFloat(float *pArg) const;
double readDouble() const;
status_t readDouble(double *pArg) const;
intptr_t readIntPtr() const;
status_t readIntPtr(intptr_t *pArg) const;
bool readBool() const;
status_t readBool(bool *pArg) const;
char16_t readChar() const;
status_t readChar(char16_t *pArg) const;
int8_t readByte() const;
status_t readByte(int8_t *pArg) const;
// Read a UTF16 encoded string, convert to UTF8
status_t readUtf8FromUtf16(std::string* str) const;
status_t readUtf8FromUtf16(std::unique_ptr<std::string>* str) const;
const char* readCString() const;
...
因此對于基本類型,開發(fā)者可以直接調(diào)用接口寫入和讀出。而對于非基本類型,需要由開發(fā)者將其拆分成基本類型然后寫入到Parcel中(讀出的時候也是一樣)。 Parcel會將所有寫入的數(shù)據(jù)進(jìn)行打包,Parcel本身可以作為一個整體在進(jìn)程間傳遞。接收方在收到Parcel之后,只要按寫入同樣的順序讀出即可。
這個過程,和我們現(xiàn)實(shí)生活中寄送包裹做法是一樣的:我們將需要寄送的包裹放到硬紙盒中交給快遞公司??爝f公司將所有的包裹進(jìn)行打包,然后集中放到運(yùn)輸車中送到目的地,到了目的地之后然后再進(jìn)行拆分。
Parcel既包含C++部分的實(shí)現(xiàn),也同時提供了Java的接口,中間通過JNI銜接。Java層的接口其實(shí)僅僅是一層包裝,真正的實(shí)現(xiàn)都是位于C++部分中,它們的關(guān)系如下圖所示:

特別需要說明一下的是,Parcel類除了可以傳遞基本數(shù)據(jù)類型,還可以傳遞Binder對象:
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
這個方法寫入的是sp<IBinder>類型的對象,而IBinder既可能是本地Binder,也可能是遠(yuǎn)程Binder,這樣我們就不可以不用關(guān)心具體細(xì)節(jié)直接進(jìn)行Binder對象的傳遞。
這也是為什么IInterface中定義了兩個asBinder的static方法,如果你不記得了,請回憶一下這兩個方法:
static sp<IBinder> asBinder(const IInterface*);
static sp<IBinder> asBinder(const sp<IInterface>&);
而對于Binder驅(qū)動,我們前面已經(jīng)講解過:Binder驅(qū)動并不是真的將對象在進(jìn)程間序列化傳遞,而是由Binder驅(qū)動完成了對于Binder對象指針的解釋和翻譯,使調(diào)用者看起來就像在進(jìn)程間傳遞對象一樣。
Framework層的線程管理
在講解Binder驅(qū)動的時候,我們就講解過驅(qū)動中對應(yīng)線程的管理。這里我們再來看看,F(xiàn)ramework層是如何與驅(qū)動層對接進(jìn)行線程管理的。
ProcessState::setThreadPoolMaxThreadCount 方法中,會通過BINDER_SET_MAX_THREADS命令設(shè)置進(jìn)程支持的最大線程數(shù)量:
#define DEFAULT_MAX_BINDER_THREADS 15
status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
status_t result = NO_ERROR;
if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) {
mMaxThreads = maxThreads;
} else {
result = -errno;
ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result));
}
return result;
}
由此驅(qū)動便知道了該Binder服務(wù)支持的最大線程數(shù)。驅(qū)動在運(yùn)行過程中,會根據(jù)需要,并在沒有超過上限的情況下,通過BR_SPAWN_LOOPER命令通知進(jìn)程創(chuàng)建線程:
IPCThreadState在收到BR_SPAWN_LOOPER請求之后,便會調(diào)用ProcessState::spawnPooledThread來創(chuàng)建線程:
status_t IPCThreadState::executeCommand(int32_t cmd)
{
...
case BR_SPAWN_LOOPER:
mProcess->spawnPooledThread(false);
break;
...
}
ProcessState::spawnPooledThread方法負(fù)責(zé)為線程設(shè)定名稱并創(chuàng)建線程:
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());
}
}
線程在run之后,會調(diào)用threadLoop將自身添加的線程池中:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
而IPCThreadState::joinThreadPool方法中,會根據(jù)當(dāng)前線程是否是主線程發(fā)送BC_ENTER_LOOPER或者BC_REGISTER_LOOPER命令告知驅(qū)動線程已經(jīng)創(chuàng)建完畢。整個調(diào)用流程如下圖所示:

C++ Binder服務(wù)舉例
單純的理論知識也許并不能讓我們非常好的理解,下面我們以一個具體的Binder服務(wù)例子來結(jié)合上文的知識進(jìn)行講解。
.../Android8-1/rk3399pro/frameworks/native/services/powermanager/IPowerManager.cpp
下面以PowerManager為例,來看看C++的Binder服務(wù)是如何實(shí)現(xiàn)的。
下圖是PowerManager C++部分的實(shí)現(xiàn)類圖(PowerManager也有Java層的接口,但我們這里就不討論了)。

圖中Binder Framework中的類我們在上文中已經(jīng)介紹過了,而PowerManager相關(guān)的四個類,便是在Framework的基礎(chǔ)上開發(fā)的。
IPowerManager定義了PowerManager所有對外提供的功能接口,其子類都繼承了這些接口。
-
BpPowerManager是提供給客戶端調(diào)用的遠(yuǎn)程接口 -
BnPowerManager中只有一個onTransact方法,該方法根據(jù)請求的code來對接每個請求,并直接調(diào)用PowerManager中對應(yīng)的方法 -
PowerManager是服務(wù)真正的實(shí)現(xiàn)
在IPowerManager.h中,通過DECLARE_META_INTERFACE(PowerManager);聲明一些Binder必要的組件。在IPowerManager.cpp中,通過IMPLEMENT_META_INTERFACE(PowerManager, "android.os.IPowerManager");宏來進(jìn)行實(shí)現(xiàn)。
本地實(shí)現(xiàn):Native端
服務(wù)的本地實(shí)現(xiàn)主要就是實(shí)現(xiàn)BnPowerManager和PowerManager兩個類,PowerManager是BnPowerManager的子類,因此在BnPowerManager中調(diào)用自身的virtual方法其實(shí)都是在子類PowerManager類中實(shí)現(xiàn)的。
BnPowerManager類要做的就是復(fù)寫onTransact方法,這個方法的職責(zé)是:根據(jù)請求的code區(qū)分具體調(diào)用的是那個接口,然后按順序從Parcel中讀出打包好的參數(shù),接著調(diào)用留待子類實(shí)現(xiàn)的虛函數(shù)。需要注意的是:這里從Parcel讀出參數(shù)的順序需要和BpPowerManager中寫入的順序完全一致,否則讀出的數(shù)據(jù)將是無效的。
電源服務(wù)包含了好幾個接口。雖然每個接口的實(shí)現(xiàn)邏輯各不一樣,但從Binder框架的角度來看,它們的實(shí)現(xiàn)結(jié)構(gòu)是一樣。而這里我們并不關(guān)心電源服務(wù)的實(shí)現(xiàn)細(xì)節(jié),因此我們?nèi)∑渲幸粋€方法看其實(shí)現(xiàn)方式即可。
首先我們來看一下BnPowerManager::onTransact中的代碼片段:
status_t BnPowerManager::onTransact(uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags) {
switch (code) {
...
case IPowerManager::REBOOT: {
CHECK_INTERFACE(IPowerManager, data, reply);
bool confirm = data.readInt32();
String16 reason = data.readString16();
bool wait = data.readInt32();
return reboot(confirm, reason, wait);
}
...
}
}
這段代碼中我們看到了實(shí)現(xiàn)中是如何根據(jù)code區(qū)分接口,并通過Parcel讀出調(diào)用參數(shù),然后調(diào)用具體服務(wù)方的。
而PowerManager這個類才真正是服務(wù)實(shí)現(xiàn)的本體,reboot方法真正實(shí)現(xiàn)了重啟的邏輯:
status_t PowerManager::reboot(bool confirm, const String16& reason, bool wait) {
const std::string reason_str(String8(reason).string());
if (!(reason_str.empty() || reason_str == kRebootReasonRecovery)) {
LOG(WARNING) << "Ignoring reboot request with invalid reason \""
<< reason_str << "\"";
return BAD_VALUE;
}
LOG(INFO) << "Rebooting with reason \"" << reason_str << "\"";
if (!property_setter_->SetProperty(ANDROID_RB_PROPERTY,
kRebootPrefix + reason_str)) {
return UNKNOWN_ERROR;
}
return OK;
}
通過這樣結(jié)構(gòu)的設(shè)計,將框架相關(guān)的邏輯(BnPowerManager中的實(shí)現(xiàn))和業(yè)務(wù)本身的邏輯(PowerManager中的實(shí)現(xiàn))徹底分離開了,保證每一個類都非常的“干凈”,這一點(diǎn)是很值得我們在做軟件設(shè)計時學(xué)習(xí)的。
服務(wù)的發(fā)布
服務(wù)實(shí)現(xiàn)完成之后,并不是立即就能讓別人使用的。上文中,我們就說到過:所有在Binder上發(fā)布的服務(wù)必須要注冊到ServiceManager中才能被其他模塊獲取和使用。而在BinderService類中,提供了publishAndJoinThreadPool方法來簡化服務(wù)的發(fā)布,其代碼如下:
static void publishAndJoinThreadPool(bool allowIsolated = false) {
publish(allowIsolated);
joinThreadPool();
}
static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
}
...
static void joinThreadPool() {
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->joinThreadPool();
}
由此可見,Binder服務(wù)的發(fā)布其實(shí)有三個步驟:
- 通過
IServiceManager::addService在ServiceManager中進(jìn)行服務(wù)的注冊 - 通過
ProcessState::startThreadPool啟動線程池 - 通過
IPCThreadState::joinThreadPool將主線程加入的Binder中
遠(yuǎn)程接口:Proxy端
Proxy類是供客戶端使用的。BpPowerManager需要實(shí)現(xiàn)IPowerManager中的所有接口。
我們還是以上文提到的reboot接口為例,來看看BpPowerManager::reboot方法是如何實(shí)現(xiàn)的:
virtual status_t reboot(bool confirm, const String16& reason, bool wait)
{
Parcel data, reply;
data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
data.writeInt32(confirm);
data.writeString16(reason);
data.writeInt32(wait);
return remote()->transact(REBOOT, data, &reply, 0);
}
這段代碼很簡單,邏輯就是:通過Parcel寫入調(diào)用參數(shù)進(jìn)行打包,然后調(diào)用remote()->transact將請求發(fā)送出去。
其實(shí)BpPowerManager中其他方法,甚至所有其他BpXXX中所有的方法,實(shí)現(xiàn)都是和這個方法一樣的套路。就是:通過Parcel打包數(shù)據(jù),通過remote()->transact發(fā)送數(shù)據(jù)。而這里的remote()返回的其實(shí)就是BpBinder對象,由此經(jīng)由IPCThreadState將數(shù)據(jù)發(fā)送到了驅(qū)動層。如果你已經(jīng)不記得,請重新看一下下面這幅圖:

另外,需要一下的是,這里的REBOOT就是請求的code,而這個code是在IPowerManager中定義好的,這樣子類可以直接使用,并保證是一致的:
enum {
ACQUIRE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION,
ACQUIRE_WAKE_LOCK_UID = IBinder::FIRST_CALL_TRANSACTION + 1,
RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 2,
UPDATE_WAKE_LOCK_UIDS = IBinder::FIRST_CALL_TRANSACTION + 3,
POWER_HINT = IBinder::FIRST_CALL_TRANSACTION + 4,
UPDATE_WAKE_LOCK_SOURCE = IBinder::FIRST_CALL_TRANSACTION + 5,
IS_WAKE_LOCK_LEVEL_SUPPORTED = IBinder::FIRST_CALL_TRANSACTION + 6,
USER_ACTIVITY = IBinder::FIRST_CALL_TRANSACTION + 7,
WAKE_UP = IBinder::FIRST_CALL_TRANSACTION + 8,
GO_TO_SLEEP = IBinder::FIRST_CALL_TRANSACTION + 9,
NAP = IBinder::FIRST_CALL_TRANSACTION + 10,
IS_INTERACTIVE = IBinder::FIRST_CALL_TRANSACTION + 11,
IS_POWER_SAVE_MODE = IBinder::FIRST_CALL_TRANSACTION + 12,
SET_POWER_SAVE_MODE = IBinder::FIRST_CALL_TRANSACTION + 13,
REBOOT = IBinder::FIRST_CALL_TRANSACTION + 14,
SHUTDOWN = IBinder::FIRST_CALL_TRANSACTION + 15,
CRASH = IBinder::FIRST_CALL_TRANSACTION + 16,
};
服務(wù)的獲取
在服務(wù)已經(jīng)發(fā)布之后,客戶端該如何獲取其服務(wù)接口然后對其發(fā)出請求調(diào)用呢?
很顯然,客戶端應(yīng)該通過BpPowerManager的對象來請求其服務(wù)。但看一眼BpPowerManager的構(gòu)造函數(shù),我們會發(fā)現(xiàn),似乎沒法直接創(chuàng)建一個這類的對象,因?yàn)檫@里需要一個sp<IBinder>類型的參數(shù)。
BpPowerManager(const sp<IBinder>& impl)
: BpInterface<IPowerManager>(impl)
{
}
那么這個sp<IBinder>參數(shù)我們該從哪里獲取呢?
回憶一下前面的內(nèi)容:Proxy其實(shí)是包含了一個指向Server的句柄,所有的請求發(fā)送出去的時候都需要包含這個句柄作為一個標(biāo)識。而想要拿到這個句柄,我們自然應(yīng)當(dāng)想到ServiceManager。我們再看一下ServiceManager的接口自然就知道這個sp<IBinder>該如何獲取了:
/**
* Retrieve an existing service, blocking for a few seconds
* if it doesn't yet exist.
*/
virtual sp<IBinder> getService( const String16& name) const = 0;
/**
* Retrieve an existing service, non-blocking.
*/
virtual sp<IBinder> checkService( const String16& name) const = 0;
這里的兩個方法都可以獲取服務(wù)對應(yīng)的sp<IBinder>對象,一個是阻塞式的,另外一個不是。傳遞的參數(shù)是一個字符串,這個就是服務(wù)在addServer時對應(yīng)的字符串,而對于PowerManager來說,這個字符串就是”power”。因此,我們可以通過下面這行代碼創(chuàng)建出BpPowerManager的對象。
sp<IBinder> bs = defaultServiceManager()->checkService(serviceName);
sp<IPowerManager> pm = new BpPowerManager(bs);
但這樣做還會存在一個問題:BpPowerManager中的方法調(diào)用是經(jīng)由驅(qū)動然后跨進(jìn)程調(diào)用的。通常情況下,當(dāng)我們的客戶端與PowerManager服務(wù)所在的進(jìn)程不是同一個進(jìn)程的時候,這樣調(diào)用是沒有問題的。那假設(shè)我們的客戶端又剛好和PowerManager服務(wù)在同一個進(jìn)程該如何處理呢?
針對這個問題,Binder Framework提供的解決方法是:通過interface_cast這個方法來獲取服務(wù)的接口對象,由這個方法本身根據(jù)是否是在同一個進(jìn)程,來自動確定返回一個本地Binder還是遠(yuǎn)程Binder。interface_cast是一個模板方法,其源碼如下:
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
調(diào)用這個方法的時候我們需要指定Binder服務(wù)的IInterface,因此對于PowerManager,我們需要這樣獲取其Binder接口對象:
const String16 serviceName("power");
sp<IBinder> bs = defaultServiceManager()->checkService(serviceName);
if (bs == NULL) {
return NAME_NOT_FOUND;
}
sp<IPowerManager> pm = interface_cast<IPowerManager>(bs);
我們再回頭看一下interface_cast這個方法體,這里是在調(diào)用INTERFACE::asInterface(obj),而對于IPowerManager來說,其實(shí)就是IPowerManager::asInterface(obj)。那么IPowerManager::asInterface這個方法是哪里定義的呢?
這個正是上文提到的DECLARE_META_INTERFACE和IMPLEMENT_META_INTERFACE兩個宏所起的作用。IMPLEMENT_META_INTERFACE宏包含了下面這段代碼:
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; \
} \
這里我們將“##INTERFACE”通過“PowerManager”代替,得到的結(jié)果就是:
android::sp<IPowerManager> IPowerManager::asInterface(
const android::sp<android::IBinder>& obj)
{
android::sp<IPowerManager> intr;
if (obj != NULL) {
intr = static_cast<IPowerManager*>(
obj->queryLocalInterface(
IPowerManager::descriptor).get());
if (intr == NULL) {
intr = new BpPowerManager(obj);
}
}
return intr;
}
這個便是IPowerManager::asInterface方法的實(shí)現(xiàn),這段邏輯的含義就是:
- 先嘗試通過
queryLocalInterface看看能夠獲得本地Binder,如果是在服務(wù)所在進(jìn)程調(diào)用,自然能獲取本地Binder,否則將返回NULL - 如果獲取不到本地Binder,則創(chuàng)建并返回一個遠(yuǎn)程Binder。
由此保證了:我們在進(jìn)程內(nèi)部的調(diào)用,是直接通過方法調(diào)用的形式。而不在同一個進(jìn)程的時候,才通過Binder進(jìn)行跨進(jìn)程的調(diào)用。
C++層的ServiceManager
前文已經(jīng)兩次介紹過ServiceManager了,我們知道這個模塊負(fù)責(zé)了所有Binder服務(wù)的管理,并且也看到了Binder驅(qū)動中對于這個模塊的實(shí)現(xiàn)??梢哉fServiceManager是整個Binder IPC的控制中心和交通樞紐。這里我們就來看一下這個模塊的具體實(shí)現(xiàn)。
ServiceManager是一個獨(dú)立的可執(zhí)行文件,在設(shè)備中的進(jìn)程名稱是/system/bin/servicemanager,這個也是其可執(zhí)行文件的路徑。
ServiceManager實(shí)現(xiàn)源碼的位于這個路徑:frameworks/native/cmds/servicemanager/,其main函數(shù)的主要內(nèi)容如下:
int main()
{
struct binder_state *bs;
bs = binder_open(128*1024);
if (!bs) {
ALOGE("failed to open binder driver\n");
return -1;
}
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
...
binder_loop(bs, svcmgr_handler);
return 0;
}
這段代碼很簡單,主要做了三件事情:
-
binder_open(128*1024);是打開Binder,并指定緩存大小為128k,由于ServiceManager提供的接口很簡單(下文會講到),因此并不需要普通進(jìn)程那么多(1M - 8K)的緩存 -
binder_become_context_manager(bs)使自己成為Context Manager。這里的Context Manager是Binder驅(qū)動里面的名稱,等同于ServiceManager。binder_become_context_manager的方法實(shí)現(xiàn)只有一行代碼:ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);看過Binder驅(qū)動部分解析的內(nèi)容,這行代碼應(yīng)該很容易理解了 -
binder_loop(bs, svcmgr_handler);是在Looper上循環(huán),等待其他模塊請求服務(wù)
service_manager.c中的實(shí)現(xiàn)與普通Binder服務(wù)的實(shí)現(xiàn)有些不一樣:并沒有通過繼承接口類來實(shí)現(xiàn),而是通過幾個c語言的函數(shù)來完成了實(shí)現(xiàn)。這個文件中的主要方法如下:
| 方法名稱 | 方法說明 |
|---|---|
| main | 可執(zhí)行文件入口函數(shù),剛剛已經(jīng)做過說明 |
| svcmgr_handler | 請求的入口函數(shù),類似于普通Binder服務(wù)的onTransact |
| do_add_service | 注冊一個Binder服務(wù) |
| do_find_service | 通過名稱查找一個已經(jīng)注冊的Binder服務(wù) |
ServiceManager中,通過svcinfo結(jié)構(gòu)體來描述已經(jīng)注冊的Binder服務(wù):
struct svcinfo
{
struct svcinfo *next;
uint32_t handle;
struct binder_death death;
int allow_isolated;
size_t len;
uint16_t name[0];
};
next是一個指針,指向下一個服務(wù),通過這個指針將所有服務(wù)串成了鏈表。handle是指向Binder服務(wù)的句柄,這個句柄是由Binder驅(qū)動翻譯,指向了Binder服務(wù)的實(shí)體(參見驅(qū)動中:Binder中的“面向?qū)ο蟆保?code>name是服務(wù)的名稱。
ServiceManager的實(shí)現(xiàn)邏輯并不復(fù)雜,這個模塊就好像在整個系統(tǒng)上提供了一個全局的HashMap而已:通過服務(wù)名稱進(jìn)行服務(wù)注冊,然后再通過服務(wù)名稱來查找。而真正復(fù)雜的邏輯其實(shí)都是在Binder驅(qū)動中實(shí)現(xiàn)了。
ServiceManager的接口
源碼路徑:
frameworks/native/include/binder/IServiceManager.h
frameworks/native/libs/binder/IServiceManager.cpp
ServiceManager的C++接口定義如下:
class IServiceManager : public IInterface
{
public:
DECLARE_META_INTERFACE(ServiceManager);
virtual sp<IBinder> getService( const String16& name) const = 0;
virtual sp<IBinder> checkService( const String16& name) const = 0;
virtual status_t addService( const String16& name,
const sp<IBinder>& service,
bool allowIsolated = false) = 0;
virtual Vector<String16> listServices() = 0;
enum {
GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION,
};
};
這里我們看到,ServiceManager提供的接口只有四個,這四個接口說明如下:
| 接口名稱 | 接口說明 |
|---|---|
| addService | 向ServiceManager中注冊一個新的Service |
| getService | 查詢Service。如果服務(wù)不存在,將阻塞數(shù)秒 |
| checkService | 查詢Service,但是不會阻塞 |
| listServices | 列出所有的服務(wù) |
這其中,最后一個接口是為了調(diào)試而提供的。通過adb shell連接到設(shè)備上之后,可以通過輸入service list 輸出所有注冊的服務(wù)列表。這里”service”可執(zhí)行文件其實(shí)就是通過調(diào)用listServices接口獲取到服務(wù)列表的。
service命令的源碼路徑在這里:frameworks/native/cmds/service
service list的輸出看起來像下面這樣(一次輸出可能有一百多個服務(wù),這里省略了):
255|angler:/ # service list
Found 125 services:
0 sip: [android.net.sip.ISipService]
1 nfc: [android.nfc.INfcAdapter]
2 carrier_config: [com.android.internal.telephony.ICarrierConfigLoader]
3 phone: [com.android.internal.telephony.ITelephony]
4 isms: [com.android.internal.telephony.ISms]
5 iphonesubinfo: [com.android.internal.telephony.IPhoneSubInfo]
6 simphonebook: [com.android.internal.telephony.IIccPhoneBook]
7 telecom: [com.android.internal.telecom.ITelecomService]
8 isub: [com.android.internal.telephony.ISub]
9 contexthub_service: [android.hardware.location.IContextHubService]
10 dns_listener: [android.net.metrics.IDnsEventListener]
11 connmetrics: [android.net.IIpConnectivityMetrics]
12 connectivity_metrics_logger: [android.net.IConnectivityMetricsLogger]
13 bluetooth_manager: [android.bluetooth.IBluetoothManager]
14 imms: [com.android.internal.telephony.IMms]
15 media_projection: [android.media.projection.IMediaProjectionManager]
16 launcherapps: [android.content.pm.ILauncherApps]
17 shortcut: [android.content.pm.IShortcutService]
18 fingerprint: [android.hardware.fingerprint.IFingerprintService]
19 trust: [android.app.trust.ITrustManager]
20 media_router: [android.media.IMediaRouterService]
...
普通的Binder服務(wù)我們需要通過ServiceManager來獲取接口才能調(diào)用,那么ServiceManager的接口有如何獲得呢?在libbinder中,提供了一個defaultServiceManager方法來獲取ServiceManager的Proxy,并且這個方法不需要傳入?yún)?shù)。原因我們在驅(qū)動篇中也已經(jīng)講過了:Binder的實(shí)現(xiàn)中,為ServiceManager留了一個特殊的位置,不需要像普通服務(wù)那樣通過標(biāo)識去查找。defaultServiceManager代碼如下:
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
結(jié)束語
本文我們詳細(xì)講解了Binder Framework C++層的實(shí)現(xiàn)。
但對于Android App開發(fā)者來說,絕大部分情況下都是在用Java語言開發(fā)。那么,在下一篇文章中,我就來詳細(xì)講解Binder Framework Java層的實(shí)現(xiàn)。并且也會講解AIDL與Binder的關(guān)系,敬請期待。
