IPC是個(gè)啥
IPC 即 Inter-Process Communication (進(jìn)程間通信)。
Android 基于 Linux,而 Linux 出于安全考慮,不同進(jìn)程間不能之間操作對(duì)方的數(shù)據(jù),這叫做“進(jìn)程隔離”。
在 Linux 系統(tǒng)中,虛擬內(nèi)存機(jī)制為每個(gè)進(jìn)程分配了線性連續(xù)的內(nèi)存空間,操作系統(tǒng)將這種虛擬內(nèi)存空間映射到物理內(nèi)存空間,每個(gè)進(jìn)程有自己的虛擬內(nèi)存空間,進(jìn)而不能操作其他進(jìn)程的內(nèi)存空間,只有操作系統(tǒng)才有權(quán)限操作物理內(nèi)存空間。 進(jìn)程隔離保證了每個(gè)進(jìn)程的內(nèi)存安全。
Android中的進(jìn)程通信方式
叮叮叮
我們先來(lái)思考一個(gè)問(wèn)題,Linux系統(tǒng)本身有許多IPC手段,為什么Android要重新設(shè)計(jì)一套Binder機(jī)制呢?
Android也是基于Linux內(nèi)核,Linux現(xiàn)有的進(jìn)程通信手段有以下幾種:
- 管道:在創(chuàng)建時(shí)分配一個(gè)page大小的內(nèi)存,緩存區(qū)大小比較有限;
- 消息隊(duì)列:信息復(fù)制兩次,額外的CPU消耗;不合適頻繁或信息量大的通信;
- 共享內(nèi)存:無(wú)須復(fù)制,共享緩沖區(qū)直接付附加到進(jìn)程虛擬地址空間,速度快;但進(jìn)程間的同步問(wèn)題操作系統(tǒng)無(wú)法實(shí)現(xiàn),必須各進(jìn)程利用同步工具解決;
- 套接字:作為更通用的接口,傳輸效率低,主要用于不通機(jī)器或跨網(wǎng)絡(luò)的通信;
- 信號(hào)量:常作為一種鎖機(jī)制,防止某進(jìn)程正在訪問(wèn)共享資源時(shí),其他進(jìn)程也訪問(wèn)該資源。因此,主要作為進(jìn)程間以及同一進(jìn)程內(nèi)不同線程之間的同步手段。
- 信號(hào): 不適用于信息交換,更適用于進(jìn)程中斷控制,比如非法內(nèi)存訪問(wèn),殺死某個(gè)進(jìn)程等;
既然有現(xiàn)有的IPC方式,為什么重新設(shè)計(jì)一套Binder機(jī)制呢?
- 高性能:從數(shù)據(jù)拷貝次數(shù)來(lái)看Binder只需要進(jìn)行一次內(nèi)存拷貝,而管道、消息隊(duì)列、Socket都需要兩次,共享內(nèi)存不需要拷貝,Binder的性能僅次于共享內(nèi)存。
- 穩(wěn)定性:上面說(shuō)到共享內(nèi)存的性能優(yōu)于Binder,那為什么不適用共享內(nèi)存呢,因?yàn)楣蚕韮?nèi)存需要處理并發(fā)同步問(wèn)題,控制負(fù)責(zé),容易出現(xiàn)死鎖和資源競(jìng)爭(zhēng),穩(wěn)定性較差。而B(niǎo)inder基于C/S架構(gòu),客戶端與服務(wù)端彼此獨(dú)立,穩(wěn)定性較好。
- 安全性:我們知道Android為每個(gè)應(yīng)用分配了UID,用來(lái)作為鑒別進(jìn)程的重要標(biāo)志,Android內(nèi)部也依賴這個(gè)UID進(jìn)行權(quán)限管理,包括6.0以前的固定權(quán)限和6.0以后的動(dòng)態(tài)權(quán)限,傳榮IPC只能由用戶在數(shù)據(jù)包里填入U(xiǎn)ID/PID,這個(gè)標(biāo)記完全 是在用戶空間控制的,沒(méi)有放在內(nèi)核空間,因此有被惡意篡改的可能,因此Binder的安全性更高。
關(guān)于在android下的進(jìn)程通信的方式,Android開(kāi)發(fā)藝術(shù)探索這本書(shū)上已經(jīng)總結(jié)了,相信大家都有看過(guò)。

這里再對(duì)比總結(jié)一下:
- 只有允許不同應(yīng)用的客戶端用 IPC 方式調(diào)用遠(yuǎn)程方法,并且想要在服務(wù)中處理多線程時(shí),才有必要使用 AIDL
- 如果需要調(diào)用遠(yuǎn)程方法,但不需要處理并發(fā) IPC,就應(yīng)該通過(guò)實(shí)現(xiàn)一個(gè) Binder 創(chuàng)建接口
- 如果您想執(zhí)行 IPC,但只是傳遞數(shù)據(jù),不涉及方法調(diào)用,也不需要高并發(fā),就使用 Messenger 來(lái)實(shí)現(xiàn)接口
- 如果需要處理一對(duì)多的進(jìn)程間數(shù)據(jù)共享(主要是數(shù)據(jù)的 CRUD),就使用 ContentProvider
- 如果要實(shí)現(xiàn)一對(duì)多的并發(fā)實(shí)時(shí)通信,就使用 Socket
bundle、messenger、contentprovider這些都是基于Binder實(shí)現(xiàn)的。
理解Binder
我們知道每一個(gè)Android應(yīng)用都是一個(gè)獨(dú)立的Android進(jìn)程,它們擁有自己獨(dú)立的虛擬地址空間,應(yīng)用進(jìn)程處于用戶空間之中,彼此之間相互獨(dú)立,不能共享。但是內(nèi)核空間卻是可以共享的,Client 進(jìn)程向Server進(jìn)程通信,就是利用進(jìn)程間可以共享的內(nèi)核地址空間來(lái)完成底層的通信的工作的。Client進(jìn)程與Server端進(jìn)程往往采用ioctl等方法跟內(nèi)核空間的驅(qū)動(dòng)進(jìn)行交互。

整個(gè)流程也如下所示:
- Server進(jìn)程將服務(wù)注冊(cè)到ServiceManager。
- Client進(jìn)程向ServiceManager獲取服務(wù)。
- Client進(jìn)程得到的Service信息后,建立與Server進(jìn)程的通信通道,然后就可以與Server進(jìn)程進(jìn)行交互了。
Binder是客戶端和服務(wù)端進(jìn)行通信的橋梁,當(dāng) bindService的時(shí)候,服務(wù)端就會(huì)返回一個(gè)包含了服務(wù)端業(yè)務(wù)調(diào)用的Binder對(duì)象,通過(guò)這個(gè)Binder對(duì)象,客戶端就可以獲取服務(wù)端提供的服務(wù)(包含普通服務(wù)和基于AIDL的服務(wù))或者數(shù)據(jù)。
到這里為止,我們對(duì)binder已經(jīng)有了一個(gè)大體的認(rèn)識(shí)。接下去也不會(huì)很深入的分析,為什么呢?發(fā)育的資源不夠呀,還要在野區(qū)發(fā)育下托后期啊。