Binder的介紹與原理分析

介紹

1,首先進程間的通信方式:管道、消息隊列氧苍、共享內(nèi)存夜矗、信號量、信號让虐、socket套接字紊撕、信號等
2, binder 的優(yōu)勢:

  • 拷貝次數(shù):Binder數(shù)據(jù)拷貝只需要一次,而管道赡突、消息隊列对扶、Socket都需要2次,但共享內(nèi)存方式一次內(nèi)存拷貝都不需要惭缰;從性能角度看浪南,Binder性能僅次于共享內(nèi)存。
  • 穩(wěn)定性:基于C/S架構漱受,職能分工明確
  • 安全性: Android系統(tǒng)中對外只暴露Client端络凿,Client端將任務發(fā)送給Server端,Server端會根據(jù)權限控制策略昂羡,判斷UID/PID是否滿足訪問權限絮记。
  • 架構:在Zygote孵化出system_server進程后,在system_server進程中出初始化支持整個Android framework的各種各樣的Service虐先,而這些Service從大的方向來劃分怨愤,分為Java層Framework和Native Framework層(C++)的Service,幾乎都是基于BInder IPC機制蛹批。
    Java framework:作為Server端繼承(或間接繼承)于Binder類撰洗,Client端繼承(或間接繼承)于 BinderProxy類篮愉。例如 ActivityManagerService(用于控制Activity、Service差导、進程等) 這個服務作為Server端试躏,間接繼承Binder類,而相應的ActivityManager作為Client端柿汛,間接繼承于BinderProxy類冗酿。
    Native Framework層:這是C++層,作為Server端繼承(或間接繼承)于BBinder類络断,Client端繼承(或間接繼承)于BpBinder裁替。例如MediaPlayService(用于多媒體相關)作為Server端,繼承于BBinder類貌笨,而相應的MediaPlay作為Client端弱判,間接繼承于BpBinder類.

通信

跨進程通信是需要內(nèi)核空間做支持的。傳統(tǒng)的 IPC 機制如管道锥惋、Socket 都是內(nèi)核的一部分昌腰,因此通過內(nèi)核支持來實現(xiàn)進程間通信自然是沒問題的。

但是 Binder 并不是 Linux 系統(tǒng)內(nèi)核的一部分膀跌,通過 Linux 的動態(tài)內(nèi)核可加載模塊(Loadable Kernel Module遭商,LKM)的機制。

模塊是具有獨立功能的程序捅伤,它可以被單獨編譯劫流,但是不能獨立運行。它在運行時被鏈接到內(nèi)核作為內(nèi)核的一部分運行丛忆。這樣祠汇,Android 系統(tǒng)就可以通過動態(tài)添加一個內(nèi)核模塊運行在內(nèi)核空間,用戶進程之間通過這個內(nèi)核模塊作為橋梁來實現(xiàn)通信熄诡。在 Android 系統(tǒng)中可很,這個模塊就是 Binder 驅動(Binder Dirver)

Binder IPC 機制中涉及到的內(nèi)存映射通過 mmap() 來實現(xiàn),mmap() 是操作系統(tǒng)中一種內(nèi)存映射的方法凰浮。內(nèi)存映射簡單的講就是將用戶空間的一塊內(nèi)存區(qū)域映射到內(nèi)核空間我抠。映射關系建立后,用戶對這塊內(nèi)存區(qū)域的修改可以直接反應到內(nèi)核空間袜茧;反之內(nèi)核空間對這段區(qū)域的修改也能直接反應到用戶空間屿良。內(nèi)存映射能減少數(shù)據(jù)拷貝次數(shù),實現(xiàn)用戶空間和內(nèi)核空間的高效互動惫周。兩個空間各自的修改能直接反映在映射的內(nèi)存區(qū)域,從而被對方空間及時感知康栈。也正因為如此递递,內(nèi)存映射能夠提供對進程間通信的支持喷橙。

原理

進程中的用戶區(qū)域是不能直接和物理設備打交道的,如果想要把磁盤上的數(shù)據(jù)讀取到進程的用戶區(qū)域登舞,需要兩次拷貝(磁盤-->內(nèi)核空間-->用戶空間)贰逾;通常在這種場景下 mmap() 就能發(fā)揮作用,通過在物理介質(zhì)和用戶空間之間建立映射菠秒,減少數(shù)據(jù)的拷貝次數(shù)疙剑,用內(nèi)存讀寫取代I/O讀寫,提高文件讀取效率践叠。

一次完整的 Binder IPC 通信過程通常如下:
1, 首先 Binder 驅動在內(nèi)核空間創(chuàng)建一個數(shù)據(jù)接收緩存區(qū)言缤;
2, 接著在內(nèi)核空間開辟一塊內(nèi)核緩存區(qū),建立內(nèi)核緩存區(qū)數(shù)據(jù)接收緩存區(qū)之間的映射關系禁灼,以及數(shù)據(jù)接收緩存區(qū)和接收進程用戶空間地址的映射關系管挟;
3, 發(fā)送方進程通過系統(tǒng)調(diào)用 copyfromuser() 將數(shù)據(jù) copy 到內(nèi)核中的內(nèi)核緩存區(qū),由于內(nèi)核緩存區(qū)和接收進程的用戶空間存在內(nèi)存映射弄捕,因此也就相當于把數(shù)據(jù)發(fā)送到了接收進程的用戶空間僻孝,這樣便完成了一次進程間的通信。

通信過程

通信模型

Binder 是基于 C/S 架構的棺亭,由Client钦购、Server热芹、ServiceManager、Binder 驅動 四部分組成荞雏。其中 Client、Server譬猫、Service Manager 運行在用戶空間讯檐,Binder 驅動運行在內(nèi)核空間。其中 Service Manager 和 Binder 驅動由系統(tǒng)提供染服,而 Client别洪、Server 由應用程序來實現(xiàn)。Client柳刮、Server 和 ServiceManager 均是通過系統(tǒng)調(diào)用 open挖垛、mmap 和 ioctl 來訪問設備文件 /dev/binder,從而實現(xiàn)與 Binder 驅動的交互來間接的實現(xiàn)跨進程通信秉颗。


通信結構模型

Binder 驅動
Binder 驅動是整個通信的核心痢毒;驅動負責進程之間 Binder 通信的建立,Binder 在進程之間的傳遞蚕甥,Binder 引用計數(shù)管理哪替,數(shù)據(jù)包在進程之間的傳遞和交互等一系列底層支持。
ServiceManager 與 Server Binder
Server 創(chuàng)建了 Binder菇怀,并為它起一個字符形式凭舶,可讀易記得名字晌块,將這個 Binder 實體連同名字一起以數(shù)據(jù)包的形式通過 Binder 驅動發(fā)送給 ServiceManager ,通知 ServiceManager 注冊 Binder帅霜。驅動為這個穿越進程邊界的 Binder 創(chuàng)建位于內(nèi)核中的實體節(jié)點以及 ServiceManager 對實體的引用匆背,將名字以及新建的引用打包傳給 ServiceManager。ServiceManger 收到數(shù)據(jù)后從中取出名字和引用填入查找表身冀。
我們知道钝尸,ServierManager 是一個進程,Server 是另一個進程搂根,Server 向 ServiceManager 中注冊 Binder 必然涉及到進程間通信珍促。ServiceManager 和其他進程同樣采用 Binder 通信,ServiceManager 是 Server 端兄墅,有自己的 Binder 實體踢星,其他進程都是 Client。ServiceManager 提供的 Binder 比較特殊隙咸,它沒有名字也不需要注冊沐悦。當一個進程使用 BINDERSETCONTEXT_MGR 命令將自己注冊成 ServiceManager 時Binder 驅動會自動為它創(chuàng)建 Binder 實體。其次這個 Binder 實體的引用在所有 Client 中都固定為 0 而無需通過其它手段獲得五督。也就是說藏否,一個 Server 想要向 ServiceManager 注冊自己的 Binder 就必須通過這個 0 號引用和 ServiceManager 的 Binder 通信。
ServiceManager 與 Client Binder
Server 向 ServiceManager 中注冊了 Binder 以后充包, Client 就能通過名字獲得 Binder 的引用了副签。Client 也利用保留的 0 號引用向 ServiceManager 請求訪問某個 Binder,ServiceManager 收到這個請求后從請求數(shù)據(jù)包中取出 Binder 名稱基矮,在查找表里找到對應的條目淆储,取出對應的 Binder 引用作為回復發(fā)送給發(fā)起請求的 Client。從面向對象的角度看家浇,Server 中的 Binder 實體現(xiàn)在有兩個引用:一個位于 ServiceManager 中本砰,一個位于發(fā)起請求的 Client 中。如果接下來有更多的 Client 請求該 Binder钢悲,系統(tǒng)中就會有更多的引用指向該 Binder 点额。

大致總結出 Binder 通信過程:
1, 一個進程使用 BINDERSETCONTEXT_MGR 命令通過 Binder 驅動將自己注冊成為 ServiceManager;
2, Server 通過驅動向 ServiceManager 中注冊 Binder(Server 中的 Binder 實體)莺琳,表明可以對外提供服務还棱。驅動為這個 Binder 創(chuàng)建位于內(nèi)核中的實體節(jié)點以及 ServiceManager 對實體的引用,將名字以及新建的引用打包傳給 ServiceManager惭等,ServiceManger 將其填入查找表珍手。
3, Client 通過名字,在 Binder 驅動的幫助下從 ServiceManager 中獲取到對 Binder 實體的引用,通過這個引用就能實現(xiàn)和 Server 進程的通信琳要。


通信過程模型

其中是從綠色的箭頭開始料扰,server -> Binder 驅動 -> ServiceManager , Client -> Binder 驅動 -> ServiceManager -> Binder驅動 -> Client

Binder 通信協(xié)議
  • Binder客戶端或者服務端向Binder Driver發(fā)送的命令都是以BC_開頭,例如本文的BC_TRANSACTION和BC_REPLY, 所有Binder Driver向Binder客戶端或者服務端發(fā)送的命令則都是以BR_開頭, 例如本文中的BR_TRANSACTION和BR_REPLY.
  • 只有當BC_TRANSACTION或者BC_REPLY時, 才調(diào)用binder_transaction()來處理事務. 并且都會回應調(diào)用者一個BINDER_WORK_TRANSACTION_COMPLETE事務, 經(jīng)過binder_thread_read()會轉變成BR_TRANSACTION_COMPLETE.
  • 在A端向B寫完數(shù)據(jù)之后,A會返回給自己一個BR_TRANSACTION_COMPLETE命令焙蹭,告知自己數(shù)據(jù)已經(jīng)成功寫入到B的Binder內(nèi)核空間中去了,如果是需要回復嫂伞,在處理完 BR_TRANSACTION_COMPLETE 命令后會繼續(xù)阻塞等待結果的返回
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){
    ...
  while (1) {
    if ((err=talkWithDriver()) < NO_ERROR) break;
     cmd = mIn.readInt32();
    switch (cmd) {
       <!--關鍵點1 -->
      case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;
     <!--關鍵點2 -->
      case BR_REPLY:
            {
                binder_transaction_data tr;
                  // free buffer孔厉,先設置數(shù)據(jù),直接
                if (reply) {
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        // 牽扯到數(shù)據(jù)利用帖努,與內(nèi)存釋放
                        reply->ipcSetDataReference(...)
            }
            goto finish;
    }
 finish:
 ...
return err;
}

客戶端通過talkWithDriver等待結果返回撰豺,如果沒有返回值,直接break拼余,否則會執(zhí)行到關鍵點2污桦,就上圖來說,就是發(fā)送了 BR_TRANSACTION匙监,而不會有 BC_REPLY凡橱。

Android 對 Binder 的支持

由于Android 的app都是從Zygote進程fork出來的,Zygote.forkAndSpecialize()用來 fork 新進程亭姥,通過RuntimeInit.nativeZygoteInit來初始化一些環(huán)境稼钩,通過 runSelectLoop來循環(huán)監(jiān)聽 socket,等待fork請求达罗。


Android對Binder支持原理

首先坝撑,ProcessState::self()函數(shù)會調(diào)用open()打開/dev/binder設備,這個時候能夠作為Client通過Binder進行遠程通信粮揉;其次巡李,proc->startThreadPool()負責新建一個binder線程,監(jiān)聽Binder設備扶认,這樣進程就具備了作為Binder服務端的資格侨拦。每個APP的進程都會通過onZygoteInit打開Binder,既能作為Client蝠引,也能作為Server阳谍,這就是Android進程天然支持Binder通信的原因。

問:Android APP有多少Binder線程螃概,是固定的么
答:Android APP上層應用的進程一般是開啟一個Binder線程矫夯,而對于SystemServer或者media服務等使用頻率高,服務復雜的進程吊洼,一般都是開啟兩個或者更多训貌。驅動會根據(jù)目標進程中是否存在足夠多的Binder線程來告訴進程是不是要新建Binder線程,所以是不固定的

int main(int argc, char** argv)
{      ...
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
 } 

參考:
https://zhuanlan.zhihu.com/p/35519585
http://gityuan.com/2014/01/01/binder-gaishu/
https://juejin.im/post/58c90816a22b9d006413f624

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子递沪,更是在濱河造成了極大的恐慌豺鼻,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件款慨,死亡現(xiàn)場離奇詭異儒飒,居然都是意外死亡,警方通過查閱死者的電腦和手機檩奠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門桩了,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人埠戳,你說我怎么就攤上這事井誉。” “怎么了整胃?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵颗圣,是天一觀的道長。 經(jīng)常有香客問我屁使,道長在岂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任屋灌,我火速辦了婚禮洁段,結果婚禮上,老公的妹妹穿的比我還像新娘共郭。我一直安慰自己祠丝,他們只是感情好,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布除嘹。 她就那樣靜靜地躺著写半,像睡著了一般。 火紅的嫁衣襯著肌膚如雪尉咕。 梳的紋絲不亂的頭發(fā)上叠蝇,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音年缎,去河邊找鬼悔捶。 笑死,一個胖子當著我的面吹牛单芜,可吹牛的內(nèi)容都是我干的蜕该。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼洲鸠,長吁一口氣:“原來是場噩夢啊……” “哼堂淡!你這毒婦竟也來了馋缅?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤绢淀,失蹤者是張志新(化名)和其女友劉穎萤悴,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體皆的,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡覆履,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了费薄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片内狗。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖义锥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情岩灭,我是刑警寧澤拌倍,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站噪径,受9級特大地震影響柱恤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜找爱,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一梗顺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧车摄,春花似錦寺谤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至意狠,卻和暖如春粟关,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背环戈。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工闷板, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人院塞。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓遮晚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親迫悠。 傳聞我的和親對象是個殘疾皇子鹏漆,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355