Android Binder機(jī)制,共享內(nèi)存實(shí)現(xiàn)原理

導(dǎo)讀


IPC機(jī)制簡介

IPC是Inter-Process Communication的縮寫,含義就是跨進(jìn)程通信。
按操作系統(tǒng)的描述,進(jìn)程是資源分配的最小單位,而線程是CPU調(diào)度的最小單位,在Android中進(jìn)程一般是指一個(gè)應(yīng)用程序,一個(gè)進(jìn)程可以包含一個(gè)或多個(gè)線程。每個(gè)Android應(yīng)用都有一個(gè)主線程,也就是我們常說的UI線程,在主線程執(zhí)行耗時(shí)操作會(huì)ANR(Application Not Response)。

  • IPC(進(jìn)程間通信)機(jī)制不是Android系統(tǒng)所獨(dú)有的,其他系統(tǒng)也有相應(yīng)的進(jìn)程間通信機(jī)制。
  • Android系統(tǒng)架構(gòu)中,大量采用了Binder機(jī)制作為IPC,是Android系統(tǒng)中最重要的組成。
  • 當(dāng)然也存在部分其他的IPC方式,比如Zygote通信便是采用socket

Android系統(tǒng)中,每個(gè)應(yīng)用程序是由Android的Activity,Service,Broadcast,ContentProvider這四大組件的中一個(gè)或多個(gè)組合而成,這四大組件所涉及的多進(jìn)程間的通信底層都是依賴于Binder IPC機(jī)制。

我們使用多進(jìn)程的原因不外乎兩種:

第一種情況是一個(gè)應(yīng)用因?yàn)槟承┰蜃陨硇枰_啟多進(jìn)程模式,比如某些模塊需要單獨(dú)運(yùn)行在一個(gè)獨(dú)立的進(jìn)程中,又或者是為了獲取更多可使用內(nèi)存而開啟新進(jìn)程。我們不用擔(dān)心某個(gè)應(yīng)用會(huì)占用系統(tǒng)過多的內(nèi)存資源,因?yàn)锳ndroid系統(tǒng)對(duì)單個(gè)應(yīng)用能使用的最大內(nèi)存做了限制。

第二種情況是兩個(gè)不同的應(yīng)用之間需要進(jìn)行數(shù)據(jù)交互,不同的應(yīng)用本身就是兩個(gè)不同的進(jìn)程,因此就必須要使用進(jìn)程間通信方式來達(dá)到數(shù)據(jù)交換的目的。

總之,我們應(yīng)該謹(jǐn)慎地使用多進(jìn)程技術(shù),一旦我們采用了多進(jìn)程的設(shè)計(jì)方法,我們就必須要妥善地處理進(jìn)程間通信的各種問題。


IPC基礎(chǔ)概念介紹

主要包含三部分:Serialiazable,Parcelable以及 Binder

Serializable和Parcelable接口可以完成對(duì)象的序列化過程,當(dāng)我們需要通過Intent和Binder傳輸數(shù)據(jù)的時(shí)候就需要對(duì)數(shù)據(jù)進(jìn)行序列化處理。還有的時(shí)候我們需要將數(shù)據(jù)持久化保存到本地或者通過網(wǎng)絡(luò)傳輸給其他終端,我們也需要Serializable完成對(duì)象的持久化。

Serialiazable:Java提供的序列化接口(標(biāo)記接口)
Parcelable:android提供的序列化接口

Serializable 與 Parcelable對(duì)比

  • Serializable 是Java中的序列化接口,使用起來簡單;Parcelable是Android中的序列化方式,使用起來稍微復(fù)雜一些。
  • Serializable 在序列化操作的時(shí)候會(huì)產(chǎn)生大量的臨時(shí)變量,從而導(dǎo)致GC的頻繁調(diào)用(原因是使用了反射機(jī)制);Parcelable是以Ibinder作為信息載體的,在內(nèi)存上的開銷比較小,因此在內(nèi)存之間進(jìn)行數(shù)據(jù)傳遞的時(shí)候,Android推薦使用Parcelable
  • 將對(duì)象序列化到存儲(chǔ)設(shè)備上或者序列化后通過網(wǎng)絡(luò)傳輸,使用Parcelable 會(huì)稍顯復(fù)雜,因此這兩種情況建議使用Serializable

Binder

直觀的看,Binder是Android中的一個(gè)類,實(shí)現(xiàn)了IBinder接口
從不同角度理解Binder:
1 從IPC角度,Binder是跨進(jìn)程通信方式
2 從FrameWork角度,Binder是ServiceManager連接各種Manager(如am,wm
)等的橋梁
3 從應(yīng)用層角度,Binder是客戶端與服務(wù)端通信的媒介


從進(jìn)程角度來看IPC機(jī)制

IPC原理

每個(gè)Android的進(jìn)程,只能運(yùn)行在自己進(jìn)程所擁有的虛擬地址空間。對(duì)于用戶空間,不同進(jìn)程之間彼此是不能共享的,而內(nèi)核空間卻是可共享的。Client進(jìn)程向Server進(jìn)程通信,就是利用進(jìn)程間可共享的內(nèi)核內(nèi)存空間來完成底層通信工作的,Client端與Server端進(jìn)程往往采用ioctl等方法跟內(nèi)核空間的驅(qū)動(dòng)進(jìn)行交互。


Android中的幾種IPC方式

  • 使用Bundle
  • 使用文件共享
  • 報(bào)文隊(duì)列(Messenger)
  • 使用AIDL
  • 使用ContentProvide

使用Bundle

在Android開發(fā)中,我們通常會(huì)使用Bundle在不同的組件中傳遞一些數(shù)據(jù),由于Bundle 本身已經(jīng)實(shí)現(xiàn)了Parcelable 接口,所以它可以很方便地在進(jìn)程間傳輸。當(dāng)我們?cè)谝粋€(gè)進(jìn)程中啟動(dòng)了另一個(gè)進(jìn)程的Activity、Service和Receiver,我們可以將需要傳輸?shù)臄?shù)據(jù)放入Bundle中并通過Intent傳遞出去。使用示例:

private void startMain() {
    Intent intent = new Intent(FirstActivity.this, MainActivity.class);
    Bundle bundle = new Bundle();
    bundle.putString("key", "value");
    ……
    intent.putExtra("bundle", bundle);
}

我們必須要知道,我們傳輸?shù)臄?shù)據(jù)必須是可序列化的,比如基本類型、實(shí)現(xiàn)了Serializable 或Parcelable接口的對(duì)象以及一些Android支持的特殊對(duì)象,具體可以查看Bundle 這類中的一系列put 方法。Bundle 不支持的數(shù)據(jù)類型我們無法通過它在進(jìn)程間傳遞。

使用文件共享

兩個(gè)進(jìn)程可以通過讀/寫同一個(gè)文件來交換數(shù)據(jù),也就是說A進(jìn)程把數(shù)據(jù)寫入到共享文件中,B進(jìn)程通過讀取共享文件獲取A進(jìn)程共享的數(shù)據(jù)。

由于Android系統(tǒng)是基于Linux的,使得并發(fā)讀寫可以沒有限制地進(jìn)行,甚至兩個(gè)線程對(duì)同一個(gè)文件進(jìn)行寫操作都是可以的,盡管這樣可能會(huì)使數(shù)據(jù)變得雜亂。除了交換一些文本信息,我們還可以序列化一個(gè)對(duì)象到文件系統(tǒng)中,之后在另一個(gè)進(jìn)程中恢復(fù)這個(gè)對(duì)象,雖然兩個(gè)對(duì)象內(nèi)容完全相同,但是得到的對(duì)象和之前的對(duì)象本質(zhì)上是兩個(gè)不同的對(duì)象。

通過文件共享實(shí)現(xiàn)進(jìn)程間通信的局限性也是比較明顯的:當(dāng)多個(gè)線程并發(fā)讀寫文件,那么我們得到的數(shù)據(jù)就可能不是正確的。所以在使用這項(xiàng)技術(shù)的時(shí)候,我們應(yīng)該盡量避免并發(fā)讀寫這種情況的發(fā)生,或者只在對(duì)數(shù)據(jù)同步要求不高的情況下使用文件共享來實(shí)現(xiàn)進(jìn)程間通信,并且妥善處理并發(fā)讀寫問題。

使用Messenger

使用AIDL

使用ContentProvider

ContentProvider 是Android中提供的專門用于不同進(jìn)程間數(shù)據(jù)共享的方式,ContentProvider作為Android中的四大組件之一,可見它在Android中是比較重要的。它的底層實(shí)現(xiàn)同樣是Binder,但是它的使用過程比AIDL方便得多,因?yàn)橄到y(tǒng)為我們做了封裝,使得我們不需要關(guān)心底層細(xì)節(jié)就可以輕松實(shí)現(xiàn)進(jìn)程間通信。

系統(tǒng)也為開發(fā)者提供了很多內(nèi)置的ContentProvider ,例如通訊錄、相冊(cè)信息等,要跨進(jìn)程訪問這些數(shù)據(jù),我們就必須先了解ContentProvider 的創(chuàng)建以及使用規(guī)則。

總結(jié)
IPC是什么?是跨進(jìn)程通信
AIDL是什么?是IPC方式的一種
IPC為什么會(huì)導(dǎo)致那么多問題?內(nèi)存獨(dú)立
我們?cè)谑裁磿r(shí)候需要IPC?某功能需要運(yùn)行在獨(dú)立進(jìn)行;提升應(yīng)用分配內(nèi)存;應(yīng)用間交互

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容