Binder 是 Android 系統(tǒng)中非常重要的組成部分。Android 系統(tǒng)中的許多功能建立在 Binder 機(jī)制之上。在這篇文章中,我們會(huì)對(duì) Android 中的 Binder 在系統(tǒng)架構(gòu)中的作用進(jìn)行分析;然后,我們會(huì)從底層的實(shí)現(xiàn)角度簡(jiǎn)要說(shuō)明為什么 Android 要開(kāi)發(fā)出一套獨(dú)立的跨進(jìn)程通信機(jī)制;最后,我們會(huì)給出一個(gè) AIDL 的使用示例來(lái)說(shuō)明如何使用 Binder 來(lái)進(jìn)行通信。
1、什么是 Binder? 為什么說(shuō)它對(duì) Android 系統(tǒng)至關(guān)重要?
“什么是 Binder? 為什么說(shuō)它對(duì) Android 系統(tǒng)至關(guān)重要?” 在回答這個(gè)問(wèn)題之前,我們先來(lái)說(shuō)下其他的東西。
不知道你有沒(méi)有思考過(guò)這么一個(gè)問(wèn)題:為什么當(dāng)我們?cè)?Android 中啟動(dòng)一個(gè)頁(yè)面的時(shí)候需要調(diào)用 startActivity() 方法,然后還要傳入一個(gè) Intent? 如果我們不使用這種傳遞值的方式,直接寫(xiě)成靜態(tài)的變量有沒(méi)有問(wèn)題?這也是之前有人問(wèn)過(guò)我的一個(gè)問(wèn)題。
對(duì)上面的兩個(gè)問(wèn)題,我們先回答第二個(gè)。使用靜態(tài)的變量傳遞值在大部分情況下是可以的,當(dāng)然要注意在使用完了值之后要及時(shí)釋放資源,不然會(huì)占用太多內(nèi)存,甚至 OOM. 但是,在特殊的情況下它是無(wú)法適用的,即跨進(jìn)程的情況下。這是因?yàn)椋o態(tài)的變量的作用范圍只是其所在的進(jìn)程,在其他進(jìn)程訪問(wèn)的時(shí)候?qū)儆诳邕M(jìn)程訪問(wèn),當(dāng)然訪問(wèn)不到了。對(duì)于第一個(gè)問(wèn)題,Android 中的一個(gè) Activity 的啟動(dòng)過(guò)程遠(yuǎn)比我們想象的復(fù)雜,其中就涉及跨進(jìn)程的通信過(guò)程。當(dāng)我們調(diào)用 startActivity() 方法之后,我們的所有的 “意圖” 會(huì)經(jīng)過(guò)層層過(guò)濾,直到一個(gè)稱之為 AMS 的地方被處理。處理完之后,再跨進(jìn)程調(diào)用你啟動(dòng)頁(yè)面時(shí)的進(jìn)程進(jìn)行后續(xù)處理,即回調(diào) onCreate() 等生命周期方法。
一個(gè) Activity 的啟動(dòng)過(guò)程涉及 Android 中兩種重要的通信機(jī)制,Binder 和 Handler,我們會(huì)在以后的文章中對(duì)此進(jìn)行分析。
下面我們通過(guò)一個(gè)簡(jiǎn)單的圖來(lái)說(shuō)明一下 Activity 的啟動(dòng)過(guò)程:
當(dāng)我們調(diào)用 startActivity() 方法的時(shí)候,首先會(huì)從 ServiceManager 中獲取到 ActivityManagerService (就是 AMS),然后將 ApplicationThread 作為參數(shù)傳遞給 AMS,然后執(zhí)行 AMS 的方法來(lái)啟動(dòng) Activity. (在我們的應(yīng)用進(jìn)程中執(zhí)行另一個(gè)進(jìn)程的方法。)
AMS 是全局的,在系統(tǒng)啟動(dòng)的時(shí)候被啟動(dòng)。當(dāng)我們使用它的時(shí)候從 ServiceManager 中獲取這個(gè)全局的變量即可。當(dāng)我們調(diào)用它的方法的時(shí)候,方法具體的執(zhí)行邏輯將在系統(tǒng)的進(jìn)程中執(zhí)行。我們傳入的 ApplicationThread 就像一個(gè)信使一樣。當(dāng) AMS 處理完畢,決定回調(diào) Activity 的生命周期方法的時(shí)候,就直接調(diào)用 ApplicationThread 的方法(這是在另一個(gè)進(jìn)程中調(diào)用我們的應(yīng)用進(jìn)程)。這樣就實(shí)現(xiàn)了我們的 Activity 的生命周期的回調(diào)。
看了上面的過(guò)程,也許有的同學(xué)會(huì)覺(jué)得。Binder 對(duì) Android 系統(tǒng)至關(guān)重要,但是我們并沒(méi)有用到 Binder 啊。實(shí)際上,我們只是沒(méi)有直接使用 Binder. 以下圖為例,我們說(shuō)下我們實(shí)際開(kāi)發(fā)過(guò)程中是如何使用 Binder 的。
在大多數(shù)情況下,我們都在與各個(gè) Manager 進(jìn)行交互,而實(shí)際上這些 Manager 內(nèi)部是使用 Binder 來(lái)進(jìn)行跨進(jìn)程通信的。如上所示,當(dāng)我們調(diào)用 Manager 的時(shí)候,Manager 會(huì)通過(guò)代理類(lèi)來(lái)從 Binder 驅(qū)動(dòng)中得到另一個(gè)進(jìn)程的 Stub 對(duì)象,然后我們使用該 Stub 對(duì)象,遠(yuǎn)程調(diào)用另一個(gè)進(jìn)程的方法。只是這個(gè)過(guò)程被封裝了,我們沒(méi)有感知到而已,而這個(gè)跨進(jìn)程通信 (IPC) 的機(jī)制就是 Binder 機(jī)制。
至于什么是 Stub 呢?Stub 是 AIDL 規(guī)范中的一部分。AIDL 為我們使用 Binder 提供了一套模板。在 Android 系統(tǒng)中大量使用了這種定義來(lái)完成跨進(jìn)程通信。稍后我們介紹 AIDL 的時(shí)候,你將看到它是如何作用的。
2、為什么是 Binder 而不是其他通信機(jī)制?
Android 是基于 Linux 的,Linux 本身已經(jīng)具有了許多的 IPC 機(jī)制,比如:管道(Pipe)、信號(hào)(Signal)和跟蹤(Trace)、插口(Socket)、消息隊(duì)列(Message)、共享內(nèi)存(Share Memory)和信號(hào)量(Semaphore)。那么,為什么 Android 要特立獨(dú)行地搞出一套 IPC 機(jī)制呢?這當(dāng)然是有原因的:
效率上 :Socket 作為一款通用接口,其傳輸效率低,開(kāi)銷(xiāo)大,主要用在跨網(wǎng)絡(luò)的進(jìn)程間通信和本機(jī)上進(jìn)程間的低速通信。消息隊(duì)列和管道采用存儲(chǔ)-轉(zhuǎn)發(fā)方式,即數(shù)據(jù)先從發(fā)送方緩存區(qū)拷貝到內(nèi)核開(kāi)辟的緩存區(qū)中,然后再?gòu)膬?nèi)核緩存區(qū)拷貝到接收方緩存區(qū),至少有兩次拷貝過(guò)程。共享內(nèi)存雖然無(wú)需拷貝,但控制復(fù)雜,難以使用。Binder 只需要一次數(shù)據(jù)拷貝,性能上僅次于共享內(nèi)存。
穩(wěn)定性:Binder 基于 C|S 架構(gòu),客戶端(Client)有什么需求就丟給服務(wù)端(Server)去完成,架構(gòu)清晰、職責(zé)明確又相互獨(dú)立,自然穩(wěn)定性更好。 共享內(nèi)存雖然無(wú)需拷貝,但是控制負(fù)責(zé),難以使用。從穩(wěn)定性的角度講,Binder 機(jī)制是優(yōu)于內(nèi)存共享的。
安全性:Binder 通過(guò)在內(nèi)核層為客戶端添加身份標(biāo)志
UID|PID,來(lái)作為身份校驗(yàn)的標(biāo)志,保障了通信的安全性。 傳統(tǒng) IPC 訪問(wèn)接入點(diǎn)是開(kāi)放的,無(wú)法建立私有通道。比如,命名管道的名稱,SystemV 的鍵值,Socket 的 ip 地址或文件名都是開(kāi)放的,只要知道這些接入點(diǎn)的程序都可以和對(duì)端建立連接,不管怎樣都無(wú)法阻止惡意程序通過(guò)猜測(cè)接收方地址獲得連接。
除了上面的原因之外,Binder 還擁有許多其他的特性,比如:1).采用引用計(jì)數(shù),當(dāng)某個(gè) Binder 不再被任何客戶端引用的時(shí)候,會(huì)通知它的持有者可以將其釋放,這適用于 Android 這種常常因?yàn)橘Y源不足而回收資源的應(yīng)用場(chǎng)景。2).它內(nèi)部維護(hù)了一個(gè)線程池;3).可以像觸發(fā)本地方法一樣觸發(fā)遠(yuǎn)程的方法。4).支持同步和異步 (oneway) 的觸發(fā)模型;5).可以使用 AIDL 模板進(jìn)行描述和開(kāi)發(fā)。
3、Binder 模型,Binder 中的 4 個(gè)主要角色
在 Binder 模型中共有 4 個(gè)主要角色,它們分別是:Client、Server、Binder 驅(qū)動(dòng)和 ServiceManager. Binder 的整體結(jié)構(gòu)是基于 C|S 結(jié)構(gòu)的,以我們啟動(dòng) Activity 的過(guò)程為例,每個(gè)應(yīng)用都會(huì)與 AMS 進(jìn)行交互,當(dāng)它們拿到了 AMS 的 Binder 之后就像是拿到了網(wǎng)絡(luò)接口一樣可以進(jìn)行訪問(wèn)。如果我們將 Binder 和網(wǎng)絡(luò)的訪問(wèn)過(guò)程進(jìn)行類(lèi)比,那么 Server 就是服務(wù)器,Client 是客戶終端,ServiceManager 是域名服務(wù)器(DNS),驅(qū)動(dòng)是路由器。其中 Server、Client 和 ServiceManager 運(yùn)行于用戶空間,驅(qū)動(dòng)運(yùn)行于內(nèi)核空間。
當(dāng)我們的系統(tǒng)啟動(dòng)的時(shí)候,會(huì)在啟動(dòng) SystemServer 進(jìn)程的時(shí)候啟動(dòng)各個(gè)服務(wù),也包括上面的 AMS. 它們會(huì)被放進(jìn)一個(gè)哈希表中,并且哈希表的鍵是字符串。這樣我們就可以通過(guò)服務(wù)的字符串名稱來(lái)找到對(duì)應(yīng)的服務(wù)。這些服務(wù)就是一個(gè)個(gè)的 Binder 實(shí)體,對(duì)于 AMS 而言,也就是 IActivityManager.Stub 實(shí)例。這些服務(wù)被啟動(dòng)的之后就像網(wǎng)絡(luò)中的服務(wù)器一樣一直等待用戶的訪問(wèn)。
對(duì)于這里的 ServiceManager,它也是一種服務(wù),但是它比較特殊,它會(huì)在所有其他的服務(wù)之前被注冊(cè),并且只被注冊(cè)一次。它的作用是用來(lái)根據(jù)字符串的名稱從哈希表中查找服務(wù),以及在系統(tǒng)啟動(dòng)的時(shí)候向哈希表中注冊(cè)服務(wù)。
所以,我們可以使用上面的這張圖來(lái)描述整個(gè) Binder 模型:首先,在系統(tǒng)會(huì)將應(yīng)用程序所需的各種服務(wù)通過(guò) Binder 驅(qū)動(dòng)注冊(cè)到系統(tǒng)中(ServiceManager 先被注冊(cè),之后其他服務(wù)再通過(guò) ServiceManager 進(jìn)行注冊(cè)),然后當(dāng)某個(gè)客戶端需要使用某個(gè)服務(wù)的時(shí)候,也需要與 Binder 驅(qū)動(dòng)進(jìn)行交互,Binder 會(huì)通過(guò)服務(wù)的名稱到 ServiceManager 中查找指定的服務(wù),并將其返回給客戶端程序進(jìn)行使用。
4、Binder 的原理
上面我們梳理了 Binder 的模型,以及為什么系統(tǒng)設(shè)計(jì)一套通信機(jī)制的原因。那么你是否也好奇神乎其神的 Binder 究竟是怎么實(shí)現(xiàn)的呢?這里我們來(lái)梳理下 Binder 內(nèi)部實(shí)現(xiàn)的原理。
首先,Binder 的實(shí)現(xiàn)過(guò)程是非常復(fù)雜的,在《Android 系統(tǒng)源碼情景分析》一書(shū)中有 200 頁(yè)的篇幅都在講 Binder. 在這里我們不算詳細(xì)地講解它的具體的實(shí)現(xiàn)原理,我們只對(duì)其中部分內(nèi)容做簡(jiǎn)單的分析,并且不希望涉及大量的代碼。
4.1 inder 相關(guān)的系統(tǒng)源碼的結(jié)構(gòu)
然后,我們需要介紹下 Binder 相關(guān)的核心類(lèi)在源碼中的位置,
-framework
|--base
|--core
|--java--android--os
|--IInterface.java
|--IBinder.java
|--Parcel.java
|-- IServiceManager.java
|--ServiceManager.java
|--ServiceManagerNative.java
|--Binder.java
|--jni
|--android_os_Parcel.cpp
|--AndroidRuntime.cpp
|--android_util_Binder.cpp
|--native
|--libs--binder
|--IServiceManager.cpp
|--BpBinder.cpp
|--Binder.cpp // Binder 的具體實(shí)現(xiàn)
|--IPCThreadState.cpp
|--ProcessState.cpp
|--include--binder // 主要是一些頭文件
|--IServiceManager.h
|--IInterface.h
|--cmds--servicemanager
|--service_manager.c // 用來(lái)注冊(cè)服務(wù)的 ServiceManager
|--binder.c
-kernel-drivers-staging-android
|--binder.c
|--uapi-binder.h
4.2 Binder 實(shí)現(xiàn)過(guò)程中至關(guān)重要的幾個(gè)函數(shù)
當(dāng)我們查看 binder.c 的源碼的時(shí)候,或者查看與 Binder 相關(guān)的操作的時(shí)候,經(jīng)??吹綆讉€(gè)操作 ioctl, mmap 和 open. 那么這幾個(gè)操作符是什么含義呢?
首先,open 函數(shù)用來(lái)打開(kāi)文件的操作符,在使用的時(shí)候需要引入頭文件,#include <sys/types.h>、#include <sys/stat.h> 和 #include <fcntl.h>,其函數(shù)定義如下,
int open(const char * pathname, int flags);
int open(const char * pathname, int flags, mode_t mode);
這里的 pathname 表示文件路徑;flag 表示打開(kāi)方式;mode 表示打開(kāi)的模式和權(quán)限等;若所有欲核查的權(quán)限都通過(guò)了檢查則返回 0, 表示成功, 只要有一個(gè)權(quán)限被禁止則返回-1.
然后是 ioctl 指令,使用的時(shí)候需要引入 #include <sys/ioctl.h> 頭文件,ioctl 是設(shè)備驅(qū)動(dòng)程序中對(duì)設(shè)備的 I/O 通道進(jìn)行管理的函數(shù),用于向設(shè)備發(fā)控制和配置命令。其函數(shù)定義如下:
int ioctl(int fd, ind cmd, …);
其中 fd 是用戶程序打開(kāi)設(shè)備時(shí)使用 open 函數(shù)返回的文件標(biāo)示符,cmd 是用戶程序?qū)υO(shè)備的控制命令,至于后面的省略號(hào),那是一些補(bǔ)充參數(shù),一般最多一個(gè),這個(gè)參數(shù)的有無(wú)和 cmd 的意義相關(guān)。
最后是 mmap 函數(shù),它用來(lái)實(shí)現(xiàn)內(nèi)存映射。使用的時(shí)候需要引入頭文件 #include <sys/mman.h>. 與之對(duì)應(yīng)的還有 munmap 函數(shù)。它們的函數(shù)定義如下,
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
int munmap(void* start,size_t length);
這里的參數(shù)的含義是:
- start:映射區(qū)的開(kāi)始地址,設(shè)置為0時(shí)表示由系統(tǒng)決定映射區(qū)的起始地址;
- length:映射區(qū)的長(zhǎng)度。長(zhǎng)度單位是以字節(jié)為單位,不足一內(nèi)存頁(yè)按一內(nèi)存頁(yè)處理;
- prot:期望的內(nèi)存保護(hù)標(biāo)志,不能與文件的打開(kāi)模式?jīng)_突。是以下的某個(gè)值,可以通過(guò) o r運(yùn)算合理地組合在一起;
- flags:指定映射對(duì)象的類(lèi)型,映射選項(xiàng)和映射頁(yè)是否可以共享。它的值可以是一個(gè)或者多個(gè)以下位的組合體;
- fd:有效的文件描述詞。一般是由
open()函數(shù)返回,其值也可以設(shè)置為-1,此時(shí)需要指定 flags 參數(shù)中的 MAP_ANON,表明進(jìn)行的是匿名映射; - off_toffset:被映射對(duì)象內(nèi)容的起點(diǎn)。
成功執(zhí)行時(shí),mmap() 返回被映射區(qū)的指針,munmap() 返回0。失敗時(shí),mmap() 返回 MAP_FAILED[其值為(void *)-1],munmap() 返回 -1.
4.3 ServiceManger 啟動(dòng)
Binder 中的 ServiceManager 并非 Java 層的 ServiceManager,而是 Native 層的。啟動(dòng) ServiceManager 由 init 進(jìn)程通過(guò)解析 init.rc 文件而創(chuàng)建。啟動(dòng)的時(shí)候會(huì)找到上述源碼目錄中的 service_manager.c 文件中,并調(diào)用它的 main() 方法,
// platform/framework/native/cmds/servicemanager.c
int main(int argc, char** argv)
{
struct binder_state *bs;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
// 1. 打開(kāi) binder 驅(qū)動(dòng)
bs = binder_open(driver, 128*1024);
// ...
// 2. 將當(dāng)前的 ServiceManger 設(shè)置成上下文
if (binder_become_context_manager(bs)) {
return -1;
}
// ...
// 3. 啟動(dòng) binder 循環(huán),進(jìn)入不斷監(jiān)聽(tīng)狀態(tài)
binder_loop(bs, svcmgr_handler);
return 0;
}
ServcieManager 啟動(dòng)的過(guò)程就是上面三個(gè)步驟,無(wú)需過(guò)多說(shuō)明。下面我們給出這三個(gè)方法具體實(shí)現(xiàn)的。在下面的代碼中你將看到我們之前介紹的三個(gè)函數(shù)的實(shí)際應(yīng)用。相應(yīng)有了前面的鋪墊之后你理解起來(lái)不成問(wèn)題 :)
// platform/framework/native/cmds/servicemanager.c
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
bs = malloc(sizeof(*bs));
if (!bs) {
errno = ENOMEM;
return NULL;
}
// 打開(kāi)設(shè)備驅(qū)動(dòng)
bs->fd = open(driver, O_RDWR | O_CLOEXEC);
if (bs->fd < 0) {
goto fail_open;
}
// 向驅(qū)動(dòng)發(fā)送指令,獲取binder版本信息
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
goto fail_open;
}
bs->mapsize = mapsize;
// 通過(guò)系統(tǒng)調(diào)用,mmap 內(nèi)存映射,mmap 必須是 page 的整數(shù)倍
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
if (bs->mapped == MAP_FAILED) {
goto fail_map;
}
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return NULL;
}
在上面的代碼中,先使用 open() 函數(shù)打開(kāi)設(shè)備驅(qū)動(dòng)(就是一個(gè)打開(kāi)文件的操作),然后使用 ioctl() 函數(shù)向上面的設(shè)備驅(qū)動(dòng)發(fā)送指令以獲取設(shè)備信息。最后,通過(guò) mmap() 函數(shù)實(shí)現(xiàn)內(nèi)存映射,并將上述的文件描述符傳入。這里的 binder_state 是一個(gè)結(jié)構(gòu)體,定義如下。其實(shí)就是用來(lái)描述 binder 的狀態(tài)。從上面我們也能看到它的三個(gè)變量的賦值過(guò)程。
// platform/framework/native/cmds/servicemanager.c
struct binder_state
{
int fd;
void *mapped;
size_t mapsize;
};
當(dāng)然,在上面的代碼中,我們又見(jiàn)到了久違的 goto 指令。它們主要用來(lái)處理發(fā)生一些異常的情況。
打開(kāi)了驅(qū)動(dòng)之后,注冊(cè)為上下文的方法更加簡(jiǎn)單,
// platform/framework/native/cmds/servicemanager.c
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
就是一個(gè) ioctl 函數(shù),使用指令 BINDER_SET_CONTEXT_MGR 將當(dāng)前的 ServiceManager 注冊(cè)為上下文。
最后就是啟動(dòng) Binder 循環(huán)了。它的邏輯也沒(méi)有想象中得復(fù)雜,就是啟動(dòng)了 for 循環(huán),
// platform/framework/native/cmds/servicemanager.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
// 將 BC_ENTER_LOOPER 命令發(fā)送給 binder 驅(qū)動(dòng),內(nèi)部調(diào)用 ioctl 函數(shù)
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
// 使用 iotcl 函數(shù)讀取
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
break;
}
// 解析
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
if (res == 0) {
break;
}
if (res < 0) {
break;
}
}
}
從上面看出,函數(shù)將會(huì)在 binder_write() 中將命令發(fā)送給 Binder 驅(qū)動(dòng),以啟動(dòng)循環(huán)。其實(shí)內(nèi)部也是調(diào)用 ioctl 函數(shù)實(shí)現(xiàn)的。然后程序會(huì)啟動(dòng)一個(gè)循環(huán)來(lái)不斷讀取、解析。這是服務(wù)器很典型的操作了。
當(dāng)然,我們上面分析的是 ServiceManager 中向 Binder 寫(xiě)命令的過(guò)程,而驅(qū)動(dòng)如何解析呢?當(dāng)然是在驅(qū)動(dòng)中實(shí)現(xiàn)了,詳細(xì)的過(guò)程可以查看 Binder 驅(qū)動(dòng)部分的源碼。
4.4 Binder 的跨進(jìn)程通信過(guò)程
下面我們以 AMS 作為例子來(lái)講解下 Binder 跨進(jìn)程通信的實(shí)現(xiàn)過(guò)程。首先,當(dāng)我們調(diào)用 startActivity() 方法的時(shí)候,最終將會(huì)進(jìn)入 ActivityManager 以獲取 AMS,
// platform/framework/base/core/java/android/app/ActivityManager.java
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
這里會(huì)使用 ServiceManger 來(lái)按名稱查找 AMS,查找到 Binder 對(duì)象之后將其轉(zhuǎn)換成 AMS 就可以使用了。之前,我們也說(shuō)過(guò)用來(lái)查找 AMS 的 SeerviceManager 本身也是一種服務(wù)。所以,它這里的方法也是通過(guò) Binder 來(lái)實(shí)現(xiàn)的。那么,我們就從這里的 getService() 方法入手。
// platform/framework/base/core/java/android/os/ServiceManager.java
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) { /* ... */ }
return null;
}
這里會(huì)先嘗試從緩存當(dāng)中取 Binder,取不到的話就從遠(yuǎn)程進(jìn)行獲取。這里使用 rawGetService() 方法來(lái)從遠(yuǎn)程獲取 Binder,代碼如下,
// platform/framework/base/core/java/android/os/ServiceManager.java
private static IBinder rawGetService(String name) throws RemoteException {
final IBinder binder = getIServiceManager().getService(name);
// ...
return binder;
}
// platform/framework/base/core/java/android/os/ServiceManager.java
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
在 rawGetService() 方法中會(huì)使用 ServiceManagerNative 的 getService() 方法從遠(yuǎn)程獲取 Binder. 這里的 ServiceManagerNative 本質(zhì)上只是一個(gè)代理類(lèi),它實(shí)際的邏輯是由 BinderInternal.getContextObject() 返回的 Binder 實(shí)現(xiàn)的。
也許你已經(jīng)暈了,怎么那么多 Binder……我來(lái)說(shuō)明下。當(dāng)要查找 AMS 的時(shí)候?qū)嶋H上是一個(gè)跨進(jìn)程的調(diào)用過(guò)程,也就是實(shí)際的查找的邏輯是在另一個(gè)進(jìn)程實(shí)現(xiàn),因此需要 Binder 來(lái)通信。而查找 AMS 的遠(yuǎn)程對(duì)象實(shí)際上就是我們上面所說(shuō)的 ServiceManager (Native 層的而不是 Java 層的,Java 層的 ServiceManager 是一個(gè)代理類(lèi),是用來(lái)從遠(yuǎn)程獲取服務(wù)的)。
因此,按照上面的描述,BinderInternal.getContextObject() 返回的就應(yīng)該是遠(yuǎn)程的 Binder 對(duì)象。于是方法進(jìn)入 Native 層,
// platform/framework/base/core/jni/android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
這里的 ProcessState::self() 是否熟悉呢?你是否還記得在上一篇文章中,我們介紹 Android 系統(tǒng)啟動(dòng)過(guò)程的時(shí)候介紹過(guò)它。我們?cè)?jīng)使用它來(lái)開(kāi)啟 Binder 的線程池。這里的 self() 方法其實(shí)是用來(lái)獲取一個(gè)單例對(duì)象的。我們可以直接由 getContextObject() 進(jìn)入 getStrongProxyForHandle() 方法。從下面的方法中我們可以看出,這里調(diào)用了 BpBinder 的 create() 方法創(chuàng)建了一個(gè) BpBinder 實(shí)例并返回,也就是我們的 ServiceManager.
// plaftorm/framework/native/libs/binder/ProcessState.cpp
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != nullptr) {
IBinder* b = e->binder;
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
// ...
// 調(diào)用 BpBinder
b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
當(dāng)我們拿到了 ServiceManager 的 Binder 之后就可以調(diào)用它的 getService() 方法來(lái)獲取服務(wù)了,
// platform/framework/base/core/java/android/os/ServiceManagerNative.java
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
這里的 mRemote 就是之前返回的 BpBinder,這里調(diào)用它的 transact() 方法,并傳入了一個(gè)方法標(biāo)記 GET_SERVICE_TRANSACTION.
// platform/framework/native/libs/binder/BpBinder.cpp
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;
}
顯然這里會(huì)調(diào)用 IPCThreadState 的 self() 方法先獲取一個(gè)單例的對(duì)象,然后調(diào)用它的 transact() 方法繼續(xù)方法的執(zhí)行。
// platform/framework/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle, uint32_t code,
const Parcel& data, Parcel* reply, uint32_t flags)
{
status_t err;
// ...
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
// ...
if ((flags & TF_ONE_WAY) == 0) { // OneWay 類(lèi)型的調(diào)用,同步的
// ...
if (reply) {
// 等待相應(yīng)
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
if (reply) alog << indent << *reply << dedent << endl;
else alog << "(none requested)" << endl;
}
} else { // 異步的
err = waitForResponse(nullptr, nullptr);
}
return err;
}
上面會(huì)調(diào)用 writeTransactionData() 方法用來(lái)將數(shù)據(jù)寫(xiě)入到 Parcel 中。然后將會(huì)進(jìn)入 waitForResponse() 方法處理與 ServiceManager 交互的結(jié)果。而真實(shí)的交互發(fā)生的地方位于 talkWithDriver() 方法,
// platform/framework/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
// 通過(guò) ioctl 讀寫(xiě)操作,與 Binder Driver 進(jìn)行交互
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
} while (err == -EINTR);
// ...
return err;
}
binder_write_read 結(jié)構(gòu)體用來(lái)與 Binder 設(shè)備交換數(shù)據(jù)的結(jié)構(gòu), 通過(guò) ioctl 與 mDriverFD 通信,是真正與 Binder 驅(qū)動(dòng)進(jìn)行數(shù)據(jù)讀寫(xiě)交互的過(guò)程。先向service manager進(jìn)程發(fā)送查詢服務(wù)的請(qǐng)求(BR_TRANSACTION)。然后,service manager 會(huì)在之前開(kāi)啟的循環(huán)中監(jiān)聽(tīng)到,并使用 svcmgr_handler() 方法進(jìn)行處理。
// platform/framework/native/cmds/servicemanager.c
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
// ...
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);
return 0;
case SVC_MGR_ADD_SERVICE: // ...
case SVC_MGR_LIST_SERVICES: // ...
}
return 0;
}
顯然,這里會(huì)從 binder_transaction_data 中取出 code,即 SVC_MGR_GET_SERVICE,然后使用 do_find_service() 方法查找服務(wù)。然后再 binder_send_reply() 應(yīng)答發(fā)起者將結(jié)果返回即可。
4.5 Binder 高效通信的原因
上面我們梳理了 Binder 通信的過(guò)程,從上面我們似乎并沒(méi)有看到能證明 Binder 高效的證據(jù)。那么 Binder 究竟靠什么實(shí)現(xiàn)高效的呢?
實(shí)際上,Binder 之所以高效,從我們上面的代碼還真看不出來(lái)。因?yàn)?,我們上面的代碼并沒(méi)有涉及 Binder 驅(qū)動(dòng)部分。正如我們之前描述的那樣,ServiceManager、客戶端和服務(wù)器實(shí)際是靠 Binder 驅(qū)動(dòng)這個(gè)中間媒介進(jìn)行交互的。而 Binder 高效的地方就發(fā)生在 Binder 驅(qū)動(dòng)部分。
圖片來(lái)自 《寫(xiě)給 Android 應(yīng)用工程師的Binder原理剖析》
就像圖片描述的那樣,當(dāng)兩個(gè)進(jìn)程之間需要通信的時(shí)候,Binder 驅(qū)動(dòng)會(huì)在兩個(gè)進(jìn)程之間建立兩個(gè)映射關(guān)系:內(nèi)核緩存區(qū)和內(nèi)核中數(shù)據(jù)接收緩存區(qū)之間的映射關(guān)系,以及內(nèi)核中數(shù)據(jù)接收緩存區(qū)和接收進(jìn)程用戶空間地址的映射關(guān)系。這樣,當(dāng)把數(shù)據(jù)從 1 個(gè)用戶空間拷貝到內(nèi)核緩沖區(qū)的時(shí)候,就相當(dāng)于拷貝到了另一個(gè)用戶空間中。這樣只需要做一次拷貝,省去了內(nèi)核中暫存這個(gè)步驟,提升了一倍的性能。實(shí)現(xiàn)內(nèi)存映射靠的就是上面的 mmap() 函數(shù)。
4、Binder 的使用
4.1 代理模式
Binder 本質(zhì)上只是一種底層通信方式,和具體服務(wù)沒(méi)有關(guān)系。為了提供具體服務(wù),Server 必須提供一套接口函數(shù)以便 Client 通過(guò)遠(yuǎn)程訪問(wèn)使用各種服務(wù)。這時(shí)通常采用代理設(shè)計(jì)模式:將接口函數(shù)定義在一個(gè)抽象類(lèi)中,Server 和 Client 都會(huì)以該抽象類(lèi)為基類(lèi)實(shí)現(xiàn)所有接口函數(shù)。所不同的是 Server 端是真正的功能實(shí)現(xiàn),而 Client 端是對(duì)這些函數(shù)遠(yuǎn)程調(diào)用請(qǐng)求的包裝。為了簡(jiǎn)化這種設(shè)計(jì)模式,Android 中提供了 AIDL 供我們使用。下文中我們會(huì)介紹 AIDL 相關(guān)的內(nèi)容以及它的一些基本的使用方式。
4.2 AIDL
AIDL (Android Interface Definition Language,Android 接口定義語(yǔ)言) 是一種文件格式,用來(lái)簡(jiǎn)化 Binder 的使用。當(dāng)使用 Binder 的時(shí)候,只需要?jiǎng)?chuàng)建一個(gè)后綴名為 .aidl 的文件,然后像定義接口一樣定義方法。定義完畢之后,使用工具 aidl.exe 即可生成 Binder 所需要的各種文件。當(dāng)然,我們的 AS 已經(jīng)為我們集成了 aidl.exe,所以,只需要在定義了 AIDL 文件之后,編譯即可生成使用 Binder 時(shí)所需的文件。當(dāng)然,不使用 AIDL,直接編寫(xiě) Binder 所需的 java 文件也是可以的。
AIDL 是一種接口定義語(yǔ)言,它與 Java 中定義接口的方式有所區(qū)別。下面我們通過(guò)一個(gè)例子來(lái)說(shuō)明 AIDL 的使用方式。
這里我們模擬一個(gè)筆記管理的類(lèi),通過(guò)在 Activity 中與一個(gè)遠(yuǎn)程的 Service 進(jìn)行交互來(lái)實(shí)現(xiàn) IPC 的效果。這里,我們先要定義數(shù)據(jù)實(shí)體 Note,它只包含兩個(gè)字段,并且實(shí)現(xiàn)了 Parcelable。這里 Note 所在的目錄是 me.shouheng.advanced.aidl,然后,我們需要在 src/main 建立一個(gè)同樣的包路徑,然后定義所需的 AIDL 文件:
// INoteManager.aidl
package me.shouheng.advanced.aidl;
import me.shouheng.advanced.aidl.Note;
interface INoteManager {
Note getNote(long id);
void addNote(long id, String name);
}
// Note.aidl
package me.shouheng.advanced.aidl;
parcelable Note;
注意,在 INoteManager 文件中,我們定義了遠(yuǎn)程服務(wù)所需的各種方法。這里只定義了兩個(gè)方法,一個(gè)用來(lái)獲取指定 id 的筆記,一個(gè)用來(lái)向遠(yuǎn)程服務(wù)中添加一條筆記記錄。
這樣定義完了之后,我們可以對(duì)項(xiàng)目進(jìn)行編譯,這樣就可以 build 目錄下面得到為我們生成好的 INoteManager 類(lèi)文件。以后,我們就可以使用這個(gè)文件中生成類(lèi)和方法來(lái)進(jìn)行遠(yuǎn)程通信。但在使用該接口之前,我們還是先來(lái)看一下其中都生成了些什么東西:
package me.shouheng.advanced.aidl;
public interface INoteManager extends android.os.IInterface {
// 交給遠(yuǎn)程來(lái)實(shí)現(xiàn)具體的業(yè)務(wù)邏輯
public static abstract class Stub extends android.os.Binder implements me.shouheng.advanced.aidl.INoteManager {
private static final java.lang.String DESCRIPTOR = "me.shouheng.advanced.aidl.INoteManager";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
// 使用代理包裝遠(yuǎn)程對(duì)象
public static me.shouheng.advanced.aidl.INoteManager asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof me.shouheng.advanced.aidl.INoteManager))) {
return ((me.shouheng.advanced.aidl.INoteManager)iin);
}
// 返回代理對(duì)象
return new me.shouheng.advanced.aidl.INoteManager.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
// 真實(shí)地發(fā)送數(shù)據(jù)交換的地方
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getNote: {
data.enforceInterface(DESCRIPTOR);
long _arg0;
_arg0 = data.readLong();
// 使用模板方法來(lái)實(shí)現(xiàn)業(yè)務(wù)
me.shouheng.advanced.aidl.Note _result = this.getNote(_arg0);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_addNote: {
data.enforceInterface(DESCRIPTOR);
long _arg0;
_arg0 = data.readLong();
java.lang.String _arg1;
_arg1 = data.readString();
// 使用模板方法來(lái)實(shí)現(xiàn)業(yè)務(wù)
this.addNote(_arg0, _arg1);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
// 代理對(duì)象,包裝了遠(yuǎn)程對(duì)象,內(nèi)部調(diào)用遠(yuǎn)程對(duì)象獲取遠(yuǎn)程的服務(wù)信息
private static class Proxy implements me.shouheng.advanced.aidl.INoteManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public me.shouheng.advanced.aidl.Note getNote(long id) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
me.shouheng.advanced.aidl.Note _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeLong(id);
// 實(shí)際內(nèi)部調(diào)用遠(yuǎn)程對(duì)象,在另一個(gè)進(jìn)程實(shí)現(xiàn)業(yè)務(wù)邏輯
mRemote.transact(Stub.TRANSACTION_getNote, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = me.shouheng.advanced.aidl.Note.CREATOR.createFromParcel(_reply);
} else {
_result = null;
}
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addNote(long id, java.lang.String name) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeLong(id);
_data.writeString(name);
// 實(shí)際內(nèi)部調(diào)用遠(yuǎn)程對(duì)象,在另一個(gè)進(jìn)程實(shí)現(xiàn)業(yè)務(wù)邏輯
mRemote.transact(Stub.TRANSACTION_addNote, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
// 方法 id,用來(lái)標(biāo)記當(dāng)前調(diào)用的是哪個(gè)方法
static final int TRANSACTION_getNote = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addNote = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public me.shouheng.advanced.aidl.Note getNote(long id) throws android.os.RemoteException;
public void addNote(long id, java.lang.String name) throws android.os.RemoteException;
}
如果只是看這上面的生成的代碼,也許你仍然無(wú)法了解這些生成的類(lèi)究竟有什么作用。下面就讓我們通過(guò)使用上面生成的類(lèi)來(lái)說(shuō)明 AIDL 的具體工作流程。
首先,我們要定義遠(yuǎn)程的服務(wù),并在該服務(wù)中實(shí)現(xiàn)業(yè)務(wù)邏輯:
public class NoteService extends Service {
private CopyOnWriteArrayList<Note> notes = new CopyOnWriteArrayList<>();
// 當(dāng)前服務(wù)運(yùn)行于另一個(gè)進(jìn)程,這里實(shí)現(xiàn)業(yè)務(wù)邏輯
private Binder binder = new INoteManager.Stub() {
@Override
public Note getNote(long id) {
return Observable.fromIterable(notes).filter(note -> note.id == id).singleOrError().blockingGet();
}
@Override
public void addNote(long id, String name) {
notes.add(new Note(id, name));
}
};
@Override
public void onCreate() {
super.onCreate();
notes.add(new Note(100, "Note 100"));
notes.add(new Note(101, "Note 101"));
}
// 將 binder 返回,客戶端可以使用連接來(lái)獲取并調(diào)用
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
這里在 onCreate() 方法中創(chuàng)建了兩條記錄,并且創(chuàng)建了 INoteManager.Stub 的實(shí)例,并在 onBind() 方法中將其返回。然后,我們?cè)谝粋€(gè) Activity 中啟動(dòng)該遠(yuǎn)程服務(wù),并嘗試從該服務(wù)中獲取指定 id 的筆記記錄。從期望的結(jié)果來(lái)看,它的功能有些類(lèi)似于 ContentProvider,即用來(lái)向調(diào)用者提供數(shù)據(jù)。
下面是該 Activity 的實(shí)現(xiàn)。這里我們?cè)?onCreate() 方法中啟動(dòng)上述服務(wù)。并將實(shí)例化的 ServiceConnection 作為參數(shù)啟動(dòng)該服務(wù)。在 ServiceConnection 的方法中,我們調(diào)用 INoteManager.Stub 的 asInterface(IBinder) 方法來(lái)講 service 轉(zhuǎn)換成 INoteManager,然后從其中獲取指定 id 的筆記記錄即可。
// 創(chuàng)建服務(wù)連接
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 返回代理對(duì)象
INoteManager noteManager = INoteManager.Stub.asInterface(service);
try {
// 使用代理對(duì)象
Note note = noteManager.getNote(100);
LogUtils.d(note);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) { }
};
@Override
protected void doCreateView(Bundle savedInstanceState) {
Intent intent = new Intent(this, NoteService.class);
// 綁定服務(wù)
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 解綁服務(wù)
unbindService(connection);
}
}
根據(jù) INoteManager.Stub 的 asInterface() 方法的定義,該方法中會(huì)將傳入的 service 包裝成一個(gè) INoteManager.Stub.Proxy 返回,所以,我們?cè)?onServiceConnected() 方法中實(shí)際調(diào)用的是該代理類(lèi)的 getNote() 方法。而該代理類(lèi)的 getNote() 方法中又調(diào)用了傳入的 mRemote.transact() 方法。而這里的 service 正是我們?cè)?NoteService 中創(chuàng)建的 binder。也就是說(shuō),當(dāng)我們?cè)?onServiceConnected() 中調(diào)用 getNote() 方法的時(shí)候,實(shí)際上調(diào)用了 INoteManager.Stub 的 transact() 方法。
所以,從上面我們看出:
- 這里就像是在當(dāng)前進(jìn)程中調(diào)用了另一個(gè)進(jìn)程的方法一樣。這個(gè)調(diào)用的過(guò)程是通過(guò)
Binder來(lái)實(shí)現(xiàn)的。 - 當(dāng)調(diào)用
INoteManager.Stub的transact()方法的時(shí)候,通過(guò)傳入了一個(gè)整型的code來(lái)作為要觸發(fā)的方法的標(biāo)識(shí),這就是我們上面提到的方法的編號(hào)。
于是,我們可以通過(guò)下面的這張圖來(lái)總結(jié)在上面使用 AIDL 的過(guò)程中各部分扮演的角色:
也就是客戶端通過(guò) Proxy 訪問(wèn) Binder 驅(qū)動(dòng),然后 Binder 驅(qū)動(dòng)調(diào)用 Stub,而 Stub 中調(diào)用我們的業(yè)務(wù)邏輯。這里的 Proxy 和 Stub 用來(lái)統(tǒng)一接口函數(shù),Proxy 用來(lái)告訴我們遠(yuǎn)程服務(wù)中有哪些可用的方法,而具體的業(yè)務(wù)邏輯則由 Stub 來(lái)實(shí)現(xiàn)。Binder 的進(jìn)程通信就發(fā)生在 Proxy 和 Stub 之間。
總結(jié)
以上就是 Binder 的工作原理,如有疑問(wèn),歡迎評(píng)論區(qū)交流。