簡(jiǎn)單明了,徹底地理解Binder

我的CSDN博客同步發(fā)布:簡(jiǎn)單明了,徹底地理解Binder
你是不是看過(guò)很多Binder文章但是還是對(duì)Binder沒(méi)有一個(gè)深刻理解呻率?不是那些文章講得不夠好,主要是存在兩種情況呻引,一種是講的深礼仗,全C代碼,對(duì)我這種專做Java的人來(lái)說(shuō)沒(méi)有心情往下看逻悠;另一種是只講framework層元践,Binder驅(qū)動(dòng)并沒(méi)有具體提,導(dǎo)致我們會(huì)用Binder童谒,也大致能說(shuō)的出一些原理单旁,可并沒(méi)有一個(gè)完整的深刻認(rèn)知。那么接下來(lái)讓我們一起學(xué)習(xí)Binder吧饥伊,相信接下來(lái)的內(nèi)容會(huì)讓你有一定的收獲

什么是Binder

這個(gè)問(wèn)題很多文章都有解釋象浑,比如:Binder是Android跨進(jìn)程通信方式,它實(shí)現(xiàn)了IBinder接口琅豆,是ServiceManager連接各種Manager(如WindowManager愉豺、ActivityManager等)的橋梁。但是我覺(jué)得這些說(shuō)法還是過(guò)于抽象趋距。剛接觸Binder時(shí)粒氧,看到這些定義還是一頭霧水,只是內(nèi)心覺(jué)得Binder很牛逼节腐、很底層外盯,僅此而已。

那么應(yīng)該怎么去理解Binder呢翼雀?我不打算介紹這個(gè)概念饱苟,而是介紹Binder是怎么來(lái)到Android世界的。我是這樣理解的:Android團(tuán)隊(duì)想要實(shí)現(xiàn)進(jìn)程之間的通信狼渊,需要解決以下幾個(gè)問(wèn)題:

  1. 如何知道客戶端需要調(diào)用哪個(gè)進(jìn)程以及該進(jìn)程中的函數(shù)
  1. 客戶端如何將函數(shù)形參發(fā)送給遠(yuǎn)程進(jìn)程中的函數(shù)箱熬,以及如何將遠(yuǎn)程進(jìn)程函數(shù)計(jì)算結(jié)果返回客戶端
  2. 如何去屏蔽底層通信細(xì)節(jié),讓實(shí)現(xiàn)客戶端調(diào)用遠(yuǎn)程函數(shù)就像調(diào)用本地函數(shù)一樣

第一個(gè)問(wèn)題狈邑,很容易解決城须,只要給每個(gè)需要遠(yuǎn)程通信的類(lèi)唯一標(biāo)識(shí)就可以通過(guò)包名+類(lèi)名的字符串就可以做到,然后在類(lèi)里面給每個(gè)函數(shù)編號(hào)即可對(duì)函數(shù)唯一編碼米苹。第二個(gè)問(wèn)題糕伐,定義一個(gè)可打包的接口Parcelable,這個(gè)接口提供2個(gè)重要函數(shù)蘸嘶,分別是將對(duì)象中的屬性寫(xiě)入到數(shù)組和從數(shù)組中的數(shù)據(jù)還原對(duì)象良瞧,每個(gè)可以發(fā)送到遠(yuǎn)程函數(shù)作為形參的對(duì)象只需實(shí)現(xiàn)Parcelable對(duì)象即可陪汽。Parcelable具體使用不再本文討論范圍。第三個(gè)問(wèn)題褥蚯,為了屏蔽進(jìn)程之間的通信細(xì)節(jié)挚冤,那么Android團(tuán)隊(duì)肯定在想,定義一個(gè)類(lèi)赞庶,由這個(gè)類(lèi)來(lái)實(shí)現(xiàn)這些細(xì)節(jié)训挡。這個(gè)類(lèi)應(yīng)該做哪些事情呢?首先尘执,這個(gè)類(lèi)得幫用戶發(fā)送遠(yuǎn)程請(qǐng)求并將拿到返回結(jié)果提交給用戶舍哄,這是最重要的功能了宴凉,有了這個(gè)功能誊锭,媽媽再也不用擔(dān)心我的進(jìn)程通信。其次弥锄,如果我想實(shí)現(xiàn)服務(wù)端丧靡,什么時(shí)候客戶端調(diào)用我了,這些細(xì)節(jié)不用用戶操心籽暇。當(dāng)然温治,這個(gè)類(lèi)還要幫用戶封裝更多細(xì)節(jié)。既然打算定義這個(gè)類(lèi)了戒悠,那總得取個(gè)響當(dāng)當(dāng)?shù)拿Q吧熬荆,什么?你說(shuō)取名為Binder绸狐,好吧卤恳,那就叫Binder吧。Binder類(lèi)既然封裝很多功能寒矿,那該怎么用這個(gè)類(lèi)呢突琳?讓客戶端去繼承還是服務(wù)端繼承呢?答案是服務(wù)端符相。接下來(lái)有個(gè)約定拆融,本文后面所指的Binder類(lèi)都是指遠(yuǎn)程服務(wù)端的對(duì)象。服務(wù)端想要實(shí)現(xiàn)被跨進(jìn)程訪問(wèn)啊终,就必須繼承Binder類(lèi)镜豹。
首先我們看看我們的程序跨進(jìn)程調(diào)用系統(tǒng)服務(wù)的簡(jiǎn)單示例,實(shí)現(xiàn)浮動(dòng)窗口部分代碼:

//獲取WindowManager服務(wù)引用
WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);  
//布局參數(shù)layoutParams相關(guān)設(shè)置略...
View view=LayoutInflater.from(getApplication()).inflate(R.layout.float_layout, null);  
//添加view
wm.addView(view, layoutParams);  

系統(tǒng)服務(wù)都是運(yùn)行在systemServer進(jìn)程中蓝牲,因此我們調(diào)用系統(tǒng)服務(wù)都是跨進(jìn)程的調(diào)用趟脂。第2行代碼中,得到的wm是WindowManager對(duì)象的引用搞旭,第6行調(diào)用WindowManager的addView函數(shù)散怖,將觸發(fā)遠(yuǎn)程調(diào)用菇绵,調(diào)用的是運(yùn)行在systemServer進(jìn)程中的WindowManager的addView函數(shù)。是不是很想知道addView發(fā)生了什么镇眷?我們先看看Binder機(jī)制吧咬最!看完Binder原理,再解釋欠动!

Binder機(jī)制

先看看一般執(zhí)行過(guò)程

代碼執(zhí)行過(guò)程

假設(shè)你已經(jīng)創(chuàng)建好服務(wù)端類(lèi)MyService永乌、客戶端類(lèi)MyClient。在客戶端持有MyService的引用具伍,并且調(diào)用了MyService的func函數(shù)翅雏,那么Android內(nèi)部調(diào)用過(guò)程如下:

代碼調(diào)用過(guò)程

看了這個(gè)圖以后,相信你對(duì)你的代碼在調(diào)用遠(yuǎn)程進(jìn)程函數(shù)時(shí)有個(gè)全局的認(rèn)識(shí)人芽。這張圖有一點(diǎn)很重要望几,就是客戶端當(dāng)前線程會(huì)被掛起!因此萤厅,如果遠(yuǎn)程進(jìn)程是執(zhí)行長(zhǎng)時(shí)間的運(yùn)算橄抹,請(qǐng)不要使用主線程去調(diào)用遠(yuǎn)程函數(shù),以防止ANR惕味。

Binder的C/S架構(gòu)

上面一節(jié)我們對(duì)遠(yuǎn)程進(jìn)程調(diào)用代碼執(zhí)行過(guò)程有個(gè)初步了解楼誓,在Android開(kāi)發(fā)中,我們大量使用到了系統(tǒng)Service名挥,比如媒體播放疟羹、各種傳感器以及WindowManagerService等等等等(太多了~)。那么Android是怎么管理這些服務(wù)禀倔,并且讓用戶跨進(jìn)程調(diào)用這些服務(wù)呢榄融?首先我們看看調(diào)用系統(tǒng)服務(wù)的過(guò)程。在Android開(kāi)機(jī)啟動(dòng)過(guò)程中蹋艺,Android會(huì)初始化系統(tǒng)的各種Service剃袍,并將這些Service向ServiceManager注冊(cè)(即讓ServiceManager管理)∩咏鳎客戶端想要得到具體的Service直接向ServiceManager要即可民效。客戶端首先向ServiceManager查詢得到具體的Service引用涛救,然后通過(guò)這個(gè)引用向具體的服務(wù)端發(fā)送請(qǐng)求畏邢,服務(wù)端執(zhí)行完成后就返回。

客戶端調(diào)用系統(tǒng)服務(wù)過(guò)程

Binder驅(qū)動(dòng)實(shí)現(xiàn)原理

一直以來(lái)检吆,我有個(gè)困惑J嫖!蹭沛!這個(gè)困惑讓我迷茫了很久:客戶端持有遠(yuǎn)程進(jìn)程的某個(gè)對(duì)象引用臂寝,然后調(diào)用引用類(lèi)中的函數(shù)章鲤,遠(yuǎn)程進(jìn)程的函數(shù)就執(zhí)行了。我在想咆贬,憑什么败徊?學(xué)過(guò)操作系統(tǒng)都知道,不同的進(jìn)程之間是不共享資源的掏缎。也就是說(shuō)皱蹦,客戶端持有的這個(gè)對(duì)象跟遠(yuǎn)程進(jìn)程中的實(shí)際對(duì)象完全是兩個(gè)不同的對(duì)象【祢冢客戶端調(diào)用引用的對(duì)象跟遠(yuǎn)程進(jìn)程半毛錢(qián)關(guān)系都沒(méi)有沪哺,憑啥遠(yuǎn)程進(jìn)程就調(diào)用了執(zhí)行了?相信也有一部分人跟我有同樣的困惑酌儒!仔細(xì)研讀一下下面這張圖辜妓,相信你會(huì)豁然開(kāi)朗!

Binder驅(qū)動(dòng)實(shí)現(xiàn)原理

服務(wù)端跨進(jìn)程的類(lèi)都要繼承Binder類(lèi)今豆。我們所持有的Binder引用(即服務(wù)端的類(lèi)引用)并不是實(shí)際真實(shí)的遠(yuǎn)程Binder對(duì)象嫌拣,我們的引用在Binder驅(qū)動(dòng)里還要做一次映射。也就是說(shuō)呆躲,設(shè)備驅(qū)動(dòng)根據(jù)我們的引用對(duì)象找到對(duì)應(yīng)的遠(yuǎn)程進(jìn)程〈匪鳎客戶端要調(diào)用遠(yuǎn)程對(duì)象函數(shù)時(shí)插掂,只需把數(shù)據(jù)寫(xiě)入到Parcel,在調(diào)用所持有的Binder引用的transact()函數(shù)腥例,transact函數(shù)執(zhí)行過(guò)程中會(huì)把參數(shù)辅甥、標(biāo)識(shí)符(標(biāo)記遠(yuǎn)程對(duì)象及其函數(shù))等數(shù)據(jù)放入到Client的共享內(nèi)存,Binder驅(qū)動(dòng)從Client的共享內(nèi)存中讀取數(shù)據(jù)燎竖,根據(jù)這些數(shù)據(jù)找到對(duì)應(yīng)的遠(yuǎn)程進(jìn)程的共享內(nèi)存璃弄,把數(shù)據(jù)拷貝到遠(yuǎn)程進(jìn)程的共享內(nèi)存中,并通知遠(yuǎn)程進(jìn)程執(zhí)行onTransact()函數(shù)构回,這個(gè)函數(shù)也是屬于Binder類(lèi)夏块。遠(yuǎn)程進(jìn)程Binder對(duì)象執(zhí)行完成后,將得到的寫(xiě)入自己的共享內(nèi)存中纤掸,Binder驅(qū)動(dòng)再將遠(yuǎn)程進(jìn)程的共享內(nèi)存數(shù)據(jù)拷貝到客戶端的共享內(nèi)存脐供,并喚醒客戶端線程。

Binder機(jī)制運(yùn)用

好了借跪,現(xiàn)在對(duì)Binder機(jī)制已經(jīng)理解了政己,我們?cè)倏纯碅ndroid是怎么運(yùn)用Binder的。再現(xiàn)前面代碼:

//獲取WindowManager服務(wù)引用
WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);  
//布局參數(shù)layoutParams相關(guān)設(shè)置略...
View view=LayoutInflater.from(getApplication()).inflate(R.layout.float_layout, null);  
//添加view
wm.addView(view, layoutParams);  

這段代碼前面已經(jīng)出現(xiàn)過(guò)掏愁。getSystemService(getApplication().WINDOW_SERVICE);函數(shù)內(nèi)部原理就是向ServiceManager查詢標(biāo)識(shí)符為getApplication().WINDOW_SERVICE的遠(yuǎn)程對(duì)象的引用歇由。即WindowManager對(duì)象的引用卵牍,這個(gè)引用的真正實(shí)現(xiàn)是WindowManager的某個(gè)代理。得到這個(gè)引用后沦泌,在調(diào)用addView時(shí)辽慕,真正的實(shí)現(xiàn)是在代理里面,代理把參數(shù)打包到Parcel對(duì)象中赦肃,然后調(diào)用transact函數(shù)(該函數(shù)繼承自Binder)溅蛉,再觸發(fā)Binder驅(qū)動(dòng)的一系列調(diào)用過(guò)程,在Binder驅(qū)動(dòng)實(shí)現(xiàn)原理一節(jié)中有具體介紹他宛,忘記了的同學(xué)可以返回繼續(xù)看船侧。關(guān)于Binder的代理對(duì)象,可以參考AIDL工具生成的代碼厅各,這里不再具體介紹镜撩。

相信到現(xiàn)在,你收獲不少吧如果你喜歡就給我一個(gè)贊吧有疑問(wèn)歡迎評(píng)論~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末队塘,一起剝皮案震驚了整個(gè)濱河市袁梗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌憔古,老刑警劉巖遮怜,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鸿市,居然都是意外死亡锯梁,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)焰情,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)陌凳,“玉大人,你說(shuō)我怎么就攤上這事内舟『隙兀” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵验游,是天一觀的道長(zhǎng)充岛。 經(jīng)常有香客問(wèn)我,道長(zhǎng)批狱,這世上最難降的妖魔是什么裸准? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮赔硫,結(jié)果婚禮上炒俱,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好权悟,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布砸王。 她就那樣靜靜地躺著,像睡著了一般峦阁。 火紅的嫁衣襯著肌膚如雪谦铃。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,246評(píng)論 1 308
  • 那天榔昔,我揣著相機(jī)與錄音驹闰,去河邊找鬼。 笑死撒会,一個(gè)胖子當(dāng)著我的面吹牛嘹朗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诵肛,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼屹培,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了怔檩?” 一聲冷哼從身側(cè)響起褪秀,我...
    開(kāi)封第一講書(shū)人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎薛训,沒(méi)想到半個(gè)月后媒吗,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡许蓖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年蝴猪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膊爪。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嚎莉,靈堂內(nèi)的尸體忽然破棺而出米酬,到底是詐尸還是另有隱情,我是刑警寧澤趋箩,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布赃额,位于F島的核電站,受9級(jí)特大地震影響叫确,放射性物質(zhì)發(fā)生泄漏跳芳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一竹勉、第九天 我趴在偏房一處隱蔽的房頂上張望飞盆。 院中可真熱鬧,春花似錦、人聲如沸吓歇。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)城看。三九已至女气,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間测柠,已是汗流浹背炼鞠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留轰胁,地道東北人谒主。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像软吐,于是被迫代替她去往敵國(guó)和親瘩将。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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