Binder 總結(jié)

通過最近對Binder的源碼閱讀,以及拜讀了各路大神的文章后封恰,再次對自己的理解做一個小小的記錄。

Binder 是什么

Binder 是 Android 系統(tǒng)中的一中進(jìn)程間通信的機(jī)制惕味,前身是 OpenBinder扇调,Binder 是 Android 系統(tǒng)最重要的組件之一,也是整個系統(tǒng)的基石在讶。
同時(shí)煞抬,Binder 也是一個系統(tǒng)設(shè)備 /dev/binder 對應(yīng)的是 Binder 驅(qū)動,是 Binder 的核心构哺。
從實(shí)現(xiàn)機(jī)制上來說革答,Binder是一個token,用來標(biāo)識一個服務(wù)曙强,這個token可以跨進(jìn)程地傳遞残拐,拿到binder對象,就可以發(fā)起遠(yuǎn)程訪問碟嘴。

Linux 常見的進(jìn)程間通信方式及特點(diǎn)

共享內(nèi)存

無需拷貝
邏輯復(fù)雜溪食,需要應(yīng)用程序處理進(jìn)程間數(shù)據(jù)同步

信號量

適合事件通知,不適合傳遞大量數(shù)據(jù)

Socket

速度慢娜扇,兩次拷貝错沃,適合低速通信,或跨設(shè)備通信

文件共享

速度慢雀瓢,同步狀態(tài)難以維護(hù)

為什么采用 Binder

  • 效率高枢析,僅需一次拷貝
  • 封裝完善,由系統(tǒng)統(tǒng)一管理進(jìn)程間的數(shù)據(jù)同步刃麸、線程池管理等等醒叁,使用方便
  • 語法簡潔,可以以同步的方式完成ipc通信嫌蚤,使程序邏輯更簡單
  • 支持 Java 層辐益,Native 層
  • 由系統(tǒng)統(tǒng)一處理uid,方便進(jìn)行權(quán)限控制脱吱,安全性高
  • AIDL 工具支持直接生成Binder代碼智政,方便使用

Binder 主要概念

IBinder

代表一個可以遠(yuǎn)程訪問的對象,所謂遠(yuǎn)程訪問箱蝠,就是跨進(jìn)程訪問续捂。
IBinder主要有幾個方法:

  • getInterfaceDescriptor(): 獲取這個對象的名稱
  • pingBinder(): 檢查這個對象是否還存在
  • isBinderAlive():檢查提供這個Binder對象的進(jìn)程是否還存活
  • queryLocalInterface(@NonNull String descriptor): 查詢本地接口垦垂,對于同進(jìn)程使用 Binder,這個方法會直接返回 Binder 的實(shí)現(xiàn)類牙瓢,對于跨進(jìn)程的場景劫拗,這個方法返回 null
  • transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags): Binde r的核心方法,用來向遠(yuǎn)程服務(wù)發(fā)送數(shù)據(jù)
  • linkToDeath: 死亡監(jiān)聽

IInterface

Binder服務(wù)的基礎(chǔ)接口矾克,只有一個方法:asBinder页慷,用來獲取對應(yīng)的Binder對象。IInterface 主要是用來作為服務(wù)端和客戶端的一個協(xié)議規(guī)范胁附,即服務(wù)端實(shí)現(xiàn)相應(yīng)的方法酒繁,客戶端來調(diào)用,這個規(guī)范就是一個IInterface控妻。

Parcel

Parcel 是一個支持?jǐn)?shù)據(jù)序列化的組件州袒,我們知道,在進(jìn)程間傳遞消息弓候,由于進(jìn)程間對象郎哭、類型都不共用,因此必須序列化成通用的數(shù)據(jù)菇存,才能進(jìn)行傳遞夸研,Parcel就是用來做這個事情的,我們常用的Parcelable撰筷,就是基于Parcel實(shí)現(xiàn)的陈惰。在 binder transact 過程中使用。

Binder

這里我們說的是Java層的Binder類毕籽,這個類是IBinder的一個基本實(shí)現(xiàn),實(shí)現(xiàn)了 Binder 的本地調(diào)用(同進(jìn)程)井辆,即 transact 方法直接調(diào)用 onTransact 方法关筒,也是在這里引入了 onTransact方法,我們在使用 AIDL 的時(shí)候杯缺,Stub 類就是 Binder 的子類蒸播。
對于 Native 層的 Binder,作用也是一樣的萍肆,只不過是 Native 的實(shí)現(xiàn)袍榆,用來給 Native 代碼使用。

BinderInternal

這里提供一些 Binder 的內(nèi)部 API(不給app使用的)塘揣,常見的比如:
joinThreadPool: 將調(diào)用線程加入Binder線程池
getContextObject: 獲取系統(tǒng)的“全局上下文”(Global Context)包雀,其實(shí)就是 0 號 Binder,也就是 ServiceManager亲铡,這個方法在 ServiceManager 的 getIServiceManager 方法里面有使用到才写,就是用來獲取 ServiceManager 的 Binder 對象葡兑,這個后續(xù) ServiceManager 中會介紹。
setMaxThreads:

BinderProxy

很重要的一個類赞草,是 Java 層對 Native Binder 的一個代理讹堤,由于 Binder 的主要實(shí)現(xiàn)在 Native 層,如果 Java 層要使用厨疙,就要通過這個 BinderProxy洲守,這個類的對象是由 Native 的 javaObjectforIBinder 方法創(chuàng)建的,在 Java 層沾凄,不會創(chuàng)建這個對象梗醇。
BinderProxy 主要是定義了一堆的 native 方法,用來實(shí)現(xiàn) Java 層和 Native 層的調(diào)用搭独,其中最主要的是 transactNative 方法婴削,這個方法就是 Java 層 transact 的根本所在,也就是走到了 Native 層的 transact 邏輯牙肝。
對應(yīng)的 Native 實(shí)現(xiàn)唉俗,在 android_util_Binder.cpp 這個文件中。

BBinder

BBinder 就是 Binder 的 Native 實(shí)現(xiàn)配椭,也就是說虫溜,這個是在提供服務(wù)的地方創(chuàng)建的,用來處理 Binde r的邏輯股缸,這個在上面 Binder 的地方有提到過了衡楞。

BpBinder

BpBinder 是 Native 層最重要的類之一,我們知道敦姻,Binder 是一中 C/S 架構(gòu)瘾境,而 BpBinder 就是 Client 端真正做事的那個人,不管是 Java 的 BinderProxy镰惦,還是直接 Native 使用 Binder迷守,最終發(fā)送和接收數(shù)據(jù)的就是 BpBinder,transact 最終的實(shí)現(xiàn)就是在這里旺入,BpBinder 調(diào)用 IPCThreadState兑凿,實(shí)現(xiàn) IPC 請求,和結(jié)果的監(jiān)聽茵瘾±窕可以看看 transact 方法的代碼:

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

ProcessState

這個是 Binder 環(huán)境的初始化類,看名字是進(jìn)程相關(guān)的拗秘,這個類是單例的圣絮,在創(chuàng)建的時(shí)候,會打開 Binder 驅(qū)動聘殖,并完成和 Binder 驅(qū)動的關(guān)系的建立晨雳,也就是通過 mmap 來做一個內(nèi)存映射行瑞,這樣 Binder 驅(qū)動就可以對這個進(jìn)程發(fā)送 transact 數(shù)據(jù)。

IPCThreadState

這個是 Binder 線程相關(guān)的餐禁,最終和 Binder 驅(qū)動交換數(shù)據(jù)的工作是由它來完成的血久。

Binder Driver

Binder 驅(qū)動,Binder 通信機(jī)制的核心帮非,主要的工作就是

  1. 維護(hù)進(jìn)程間的 binder 對象氧吐,保存引用
  2. 在進(jìn)程間傳遞消息

ServiceManager

ServiceManager 是一個管理器,可以理解為 binder 服務(wù)的一個管理處末盔,主要是兩個作用:

  1. 注冊服務(wù)
  2. 獲取服務(wù)

對于比如 ActivityManagerService筑舅、WindowManagerService 等系統(tǒng)服務(wù),都是有在 ServiceManager 中注冊過的陨舱,因此他們叫做“實(shí)名Binder”翠拣,而未注冊的就叫“匿名Binder”
有一種說法很形象,Binder 作為一個 C/S 架構(gòu)的通信機(jī)制游盲,binder 就是 每個服務(wù)的 IP 和端口误墓,而 ServiceManager 就是一個 DNS 服務(wù)器,將 名稱 映射到對應(yīng)的binder益缎,方便客戶端通過名稱訪問服務(wù)谜慌。

Binder 一次拷貝的原理

最根本的就是使用了mmap進(jìn)行了內(nèi)存的映射,上面有提到莺奔,在ProcessState初始化的時(shí)候欣范,會進(jìn)行一個mmap,這是服務(wù)端進(jìn)程(用戶空間)到binder驅(qū)動(內(nèi)核空間)的一個映射令哟,而在binder驅(qū)動內(nèi)部恼琼,也采用mmap對不同進(jìn)程的緩沖區(qū)做了mmap,于是就相當(dāng)于從客戶端的內(nèi)核空間的一塊內(nèi)存屏富,直接映射到了服務(wù)端的用戶空間的一塊內(nèi)存驳癌,因此只需要從客戶端拷貝一次數(shù)據(jù)到內(nèi)核空間,數(shù)據(jù)就會自動到達(dá)服務(wù)端的用戶空間役听,這就是只需要一次拷貝的原因。

具體可參考此文章:https://blog.csdn.net/AndroidStudyDay/article/details/93749470

Binder 調(diào)用過程

這個問題要區(qū)分客戶端和服務(wù)端

客戶端

對于客戶端表窘,調(diào)用過程如下: 業(yè)務(wù)方法 -> BinderProxy.transact -> BpBinder.transact -> IPCThreadState.transact -> talkWithDriver -> binder_ioctl (驅(qū)動部分省略)

服務(wù)端

對于服務(wù)端典予,主要是Binder線程不停地輪詢,調(diào)用IPCThreadState.getAndExcuteCommand -> talkWithDriver -> binder_ioctl -> executeCommand -> BBinder.transact -> BBinder.onTransact
而 BBinder 是怎么調(diào)用到Java層的Binder對象的方法呢乐严,秘密在android_util_Binder的JavaBBinder中:

const char* const kBinderPathName = "android/os/Binder";

static int int_register_android_os_Binder(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, kBinderPathName);
    ...
    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
    ...
}

也就是說是通過這邊瘤袖,實(shí)現(xiàn)Native到Java層的調(diào)用的。

所以服務(wù)端的完整流程是: IPCThreadState.getAndExcuteCommand -> talkWithDriver -> binder_ioctl -> executeCommand -> BBinder.transact -> BBinder.onTransact -> JavaBBinder.onTransact -> Binder.execTrasact -> Binder.onTransact

Java Binder 和 Native Binder 聯(lián)系

Java Binder 是對 Native Binder的封裝昂验,方便Java 層使用捂敌,兩者交互的邏輯主要在 android_util_Binder.cpp 中艾扮。

實(shí)名 Binder,匿名 Binder 區(qū)別與聯(lián)系

上面有提到過占婉,在ServiceManager中登記過的泡嘴,就叫實(shí)名Binder,其他的叫匿名Binder逆济,對于匿名Binder酌予,需要有實(shí)名Binder作為媒介,才能建立通信奖慌,否則Binder無法在進(jìn)程間傳遞抛虫。

參考

http://gityuan.com/2016/09/04/binder-start-service/
https://blog.csdn.net/universus/article/details/6211589
https://blog.csdn.net/AndroidStudyDay/article/details/93749470

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市简僧,隨后出現(xiàn)的幾起案子建椰,更是在濱河造成了極大的恐慌,老刑警劉巖岛马,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棉姐,死亡現(xiàn)場離奇詭異,居然都是意外死亡蛛枚,警方通過查閱死者的電腦和手機(jī)谅海,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹦浦,“玉大人扭吁,你說我怎么就攤上這事∶は猓” “怎么了侥袜?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長溉贿。 經(jīng)常有香客問我枫吧,道長,這世上最難降的妖魔是什么宇色? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任蛮原,我火速辦了婚禮宵距,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己隘击,他們只是感情好淹辞,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布地沮。 她就那樣靜靜地躺著攀例,像睡著了一般。 火紅的嫁衣襯著肌膚如雪皿曲。 梳的紋絲不亂的頭發(fā)上唱逢,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天吴侦,我揣著相機(jī)與錄音,去河邊找鬼坞古。 笑死备韧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绸贡。 我是一名探鬼主播盯蝴,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼听怕!你這毒婦竟也來了捧挺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤尿瞭,失蹤者是張志新(化名)和其女友劉穎闽烙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體声搁,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黑竞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疏旨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片很魂。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖檐涝,靈堂內(nèi)的尸體忽然破棺而出遏匆,到底是詐尸還是另有隱情,我是刑警寧澤谁榜,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布幅聘,位于F島的核電站,受9級特大地震影響窃植,放射性物質(zhì)發(fā)生泄漏帝蒿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一巷怜、第九天 我趴在偏房一處隱蔽的房頂上張望葛超。 院中可真熱鬧,春花似錦延塑、人聲如沸巩掺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至研儒,卻和暖如春豫缨,著一層夾襖步出監(jiān)牢的瞬間独令,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工好芭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留燃箭,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓舍败,卻偏偏與公主長得像招狸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子邻薯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345