前言
寫完IPC的第一篇我就有點(diǎn)后悔了系宫。。因?yàn)閎inder的水太深了建车,老羅寫binder寫了十幾萬字。如果深入學(xué)習(xí)會大量涉及到系統(tǒng)層的知識腾降,甚至SM,Binder驅(qū)動(dòng)都是用c語言寫的犀盟。而晒。最近也是看了很多大牛關(guān)于binder的文章,可以說對binder的認(rèn)識又提升了一步且蓬。雖然我學(xué)的很淺欣硼,但是我盡量保證自己寫的都是對的! 來一波binder的最新認(rèn)識總結(jié)吧恶阴!~
上一篇文章主要是介紹一些簡單的linux知識,通過AIDL中的生成代碼來理解binder實(shí)現(xiàn)跨進(jìn)程的原理豹障。
任務(wù):
- 補(bǔ)充一些Linux知識冯事。
- binder實(shí)現(xiàn)跨進(jìn)程通信的實(shí)現(xiàn)流程是怎樣的
- 簡單介紹binder機(jī)制
一些補(bǔ)充知識
1.UserSpace, KernelSpace ,用戶態(tài),內(nèi)核態(tài)
用戶空間和內(nèi)核空間血公。內(nèi)核空間是linux系統(tǒng)的核心昵仅,可以訪問受保護(hù)資源和所有的硬件設(shè)備的權(quán)限。內(nèi)核獨(dú)立于應(yīng)用程序累魔,看起來是系統(tǒng)內(nèi)部的一個(gè)應(yīng)用摔笤。kernel有自己的保護(hù)措施,告知其他應(yīng)用程序他擁有什么權(quán)限垦写。所以在邏輯上吕世,將kernal和應(yīng)用程序抽離成兩塊空間。
當(dāng)某個(gè)應(yīng)用程序需要訪問內(nèi)核資源的時(shí)候梯投,可以通過系統(tǒng)調(diào)用來接入內(nèi)核命辖。然后內(nèi)核會來控制這個(gè)應(yīng)用程序?qū)Y源的訪問况毅,防止這個(gè)程序破壞系統(tǒng)資源,保證安全尔艇。這時(shí)候就會稱這個(gè)進(jìn)程處于內(nèi)核態(tài) 尔许。當(dāng)應(yīng)用程序在跑自己的代碼的時(shí)候,就稱為用戶態(tài)终娃。
2.Binder驅(qū)動(dòng)
Linux系統(tǒng)內(nèi)部是支持socket味廊,信號量等進(jìn)程通信的,但是安卓系統(tǒng)在性能和安全兩個(gè)方面設(shè)計(jì)了自己的進(jìn)程通信方式:Binder棠耕。兩個(gè)用戶空間想要通信余佛,必須通過內(nèi)核空間來支持。所以安卓就是將binder驅(qū)動(dòng)作為內(nèi)核模塊添加到Linux Kernel昧辽。Binder驅(qū)動(dòng)運(yùn)行在kernel空間衙熔,支持用戶空間的通信,可以堪稱一個(gè)橋梁搅荞,所有包含binder的數(shù)據(jù)包傳輸都會通過binder驅(qū)動(dòng)來完成红氯,無一例外!在binder驅(qū)動(dòng)里面咕痛,binder的實(shí)體和引用是以節(jié)點(diǎn)(struct)的形式存在的痢甘,包括server的binder實(shí)體,clinet里面擁有的binder引用茉贡,內(nèi)核的0號應(yīng)用以及SM的binder實(shí)體(后兩者后面會提到)塞栅。
驅(qū)動(dòng)是Binder通信的核心,系統(tǒng)中所有的Binder實(shí)體以及每個(gè)實(shí)體在各個(gè)進(jìn)程中的引用都登記在驅(qū)動(dòng)中腔丧;驅(qū)動(dòng)需要記錄Binder引用->實(shí)體之間多對一的關(guān)系放椰;為引用找到對應(yīng)的實(shí)體;在某個(gè)進(jìn)程中為實(shí)體創(chuàng)建或查找到對應(yīng)的引用愉粤;記錄Binder的歸屬地(位于哪個(gè)進(jìn)程中)砾医;通過管理Binder的強(qiáng)/弱引用創(chuàng)建/銷毀Binder實(shí)體等等。
3.ServiceManager, Binder,Clinet, Server
在Binder的機(jī)制中衣厘,SM, Clinet, Server以及上面提到的Binder驅(qū)動(dòng)是很重要的四個(gè)部分如蚜,而binder就可以看成是這四個(gè)部件之間溝通的管道。但是binder在每個(gè)部件里面的形態(tài)影暴,功能是完全不同的错邦。宏觀來看,binder可以看成是安卓跨進(jìn)程通信的方式型宙,工具撬呢,協(xié)議。微觀的來看早歇,binder可以看成各個(gè)部件里面重要的結(jié)構(gòu)倾芝,類讨勤,binder可以看成binder驅(qū)動(dòng)里面的紅黑樹數(shù)據(jù)結(jié)構(gòu),binder可以看成進(jìn)程之間傳輸?shù)臄?shù)據(jù)包晨另。binder作為膠水潭千,將不同的進(jìn)程粘合在一起,模糊了進(jìn)程隔離借尿。
ServiceManager是獨(dú)立于client, server的系統(tǒng)進(jìn)程刨晴。是由zygote進(jìn)程fork出來的。它在IPC通信中的作用是作為"通訊錄"路翻。所有的server里面的binder實(shí)體會先在SM里面注冊自己的信息狈癞,key是binder的名字(獨(dú)一無二),在AIDL的生成代碼里面你會看到這個(gè)玩意:
private static final java.lang.String DESCRIPTOR ="com.example.zane.ipc_test.IBookManager";
value就是這個(gè)binder的引用茂契,這樣就把這個(gè)binder的信息保存下來了蝶桶。也就是說client需要通過SM,以名字來去得到server的binder引用掉冶。然后通過這個(gè)引用去操作server端的binder真竖。這里也體現(xiàn)了binder中面向?qū)ο蟮脑O(shè)計(jì)理念。clinet自己并不知道自己獲得的這個(gè)binder引用是真的實(shí)體還是什么假的實(shí)體厌小,它只會去拿著自己獲得的引用去操作恢共。并且server中binder實(shí)體的引用會在SM,和所有需要跟自己通信的clinet里面存在。在這里璧亚,你可以把引用看成指針讨韭,或者代理對象。
client和server就是客戶端和服務(wù)端癣蟋。
在服務(wù)端:如果你熟悉AIDL進(jìn)行進(jìn)程間通信的流程或者看過我上篇博客透硝,你應(yīng)該對binder的存在形式有所體會。首先是一個(gè)aidl類型的接口疯搅,定義了binder的所有功能函數(shù)蹬铺。并且這些功能函數(shù)需要被編號,因?yàn)榉?wù)端是通過解析客戶端傳遞過來的數(shù)據(jù)包中的函數(shù)編號來知道自己應(yīng)該去調(diào)用什么函數(shù)秉撇。在Stub類中有這么幾行代碼(函數(shù)編號):
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
我們知道Stub就是Binder在Server的實(shí)體,里面實(shí)現(xiàn)了很多函數(shù)秋泄,onTransact()就是來分析客戶端的請求類型的函數(shù)琐馆,然后調(diào)用相應(yīng)的函數(shù),并且將返回結(jié)果放在數(shù)據(jù)包中返回給客戶端恒序。
在客戶端:同樣的瘦麸,我們在客戶端也需要去實(shí)現(xiàn)Binder,只不過這個(gè)binder是SM轉(zhuǎn)發(fā)給我們的歧胁,如果客戶端和服務(wù)端在同一個(gè)進(jìn)程滋饲,那么就會返回binder實(shí)體厉碟,如果不在同一個(gè)進(jìn)程就會返回binder的代理。由于binder代理和binder實(shí)體都是實(shí)現(xiàn)了AIDL接口的類屠缭。所以客戶端看不出來這個(gè)binder是實(shí)體或是引用箍鼓。如果你做過IPC通信,你會知道以上的過程是通過asInterface(IBiner binder)這個(gè)方法實(shí)現(xiàn)的呵曹。
實(shí)現(xiàn)流程
直接上一張我自己畫的簡介圖款咖!
可以很清楚的看出,binder驅(qū)動(dòng)是整個(gè)流程的核心奄喂!
1.Server將自己的binder通過binder驅(qū)動(dòng)在SM中進(jìn)行注冊铐殃。
2.binder驅(qū)動(dòng)會建立一個(gè)binder實(shí)體的數(shù)據(jù)節(jié)點(diǎn)和實(shí)體的引用。
3.Binder驅(qū)動(dòng)再把名字和引用打包發(fā)給SM跨新。
4.Client通過binder驅(qū)動(dòng)拿著他所需要的binder名字向SM請求binder富腊。
5.SM在自己的查找表里面找到對應(yīng)的引用之后再通過binder驅(qū)動(dòng)返回給client。
所有的系統(tǒng)服務(wù)在SystemServer進(jìn)程深沉之后就會被建立并且注冊在ServiceManager里面域帐,開發(fā)者也可以開發(fā)自定義的服務(wù)并且注冊在ServiceManager里面成為系統(tǒng)級別的服務(wù)赘被,前提是這個(gè)包含服務(wù)的應(yīng)用必須是system用戶并且?guī)Я藄ystem簽名(系統(tǒng)安全),否則是不能隨意注冊的俯树!
好了帘腹,再來一張我在一位大牛博客里面截下來的圖片,這個(gè)流程描述就更具體了:
其實(shí)就是多了binder驅(qū)動(dòng)里面的一些數(shù)據(jù)結(jié)構(gòu)節(jié)點(diǎn)和一個(gè)叫0號引用的東西许饿。那么這個(gè)0號引用是什么呢阳欲?我們知道SM, Client, Server都是運(yùn)行在三個(gè)不同的進(jìn)程的。那么第一步Server要向SM注冊自己binder的信息陋率,那么這里已經(jīng)涉及到了跨進(jìn)程通信了球化。那么這個(gè)進(jìn)程通信是怎么實(shí)現(xiàn)的呢?通過上圖可以看到瓦糟,所有的Client里面的0號引用都指向了SM里面的binder筒愚。也就是說SM和其他所有Server通信的過程都是SM先通過特殊的命令在biner驅(qū)動(dòng)中建立了自己binder的實(shí)體節(jié)點(diǎn),并且其他所有地方的0號引用都默認(rèn)留給SM的binder實(shí)體引用菩浙。
結(jié)束語
上一篇文章講的AIDL生成代碼的分析巢掺,本來準(zhǔn)備第二篇總結(jié)一下AIDL的使用。后來通過不斷的學(xué)習(xí)覺得這篇文章講的東西更值得總結(jié)劲蜻!
總之陆淀,binder要學(xué)習(xí)的東西還是很多。比如binder協(xié)議先嬉,binder傳輸數(shù)據(jù)包類型轧苫,binder在驅(qū)動(dòng)里面的數(shù)據(jù)結(jié)構(gòu),緩存和線程池管理等等…Binder在安全性疫蔓,效率性都優(yōu)于Linux系統(tǒng)默認(rèn)支持的IPC通信方式,擁有面向?qū)ο蟮脑O(shè)計(jì)原理含懊。
未經(jīng)博主同意身冬,不得轉(zhuǎn)載該篇文章