最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android Binder 通信原理圖文詳解

 更新時(shí)間:2022年10月24日 09:49:08   作者:小魚人愛編程  
這篇文章主要為大家介紹了Android Binder 通信原理圖文詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

Binder機(jī)制可謂是Android 知識(shí)體系里的重中之重,作為偏底層的基礎(chǔ)組件,平時(shí)我們很少關(guān)注它,而它卻是無處不在,也是Android 面試易考察的點(diǎn)之一。網(wǎng)上很多文章,要么知識(shí)點(diǎn)比較陳舊,要么源碼貼一堆,要么沒有成體系地分析,導(dǎo)致讀者一知半解,似是而非。
本篇將從流程上將Binder通信過一遍,盡量多用圖展示。
通過本篇文章,你將了解到:

Binder的作用

進(jìn)程與Binder驅(qū)動(dòng)如何通信

ServiceManager進(jìn)程的作用

進(jìn)程添加服務(wù)到ServiceManager的流程

進(jìn)程從ServiceManager獲取服務(wù)的流程

Binder服務(wù)端數(shù)據(jù)接收

Binder 通信全流程圖

1. Binder的作用

先看Linux下進(jìn)程地址映射關(guān)系:

我們知道,對(duì)象調(diào)用本身就是地址空間的訪問。

如上,進(jìn)程之間各自訪問各自的內(nèi)存地址,它們之間無法直接訪問對(duì)方的地址,也就是說微信不能直接調(diào)用支付寶提供的接口。而內(nèi)核具有訪問其它進(jìn)程地址空間的權(quán)限,因此微信可以將消息發(fā)送給內(nèi)核,讓內(nèi)核幫忙轉(zhuǎn)發(fā)給支付寶,這種方式叫做:存儲(chǔ)/轉(zhuǎn)發(fā)方式。

由此衍生的幾種IPC(進(jìn)程間通信)如:管道、消息隊(duì)列、socket等,而Android 上采用了新的機(jī)制:

Binder,相比傳統(tǒng)的方式,Binder只需要一次數(shù)據(jù)拷貝,并且Binder更安全。

Binder機(jī)制是Android 里用來做IPC的主要方式。

2. 進(jìn)程與Binder驅(qū)動(dòng)如何通信

既然得要內(nèi)核進(jìn)行消息中轉(zhuǎn),那么Binder驅(qū)動(dòng)得運(yùn)行在內(nèi)核空間,而事實(shí)上也確實(shí)如此,Binder驅(qū)動(dòng)加載后在內(nèi)核空間運(yùn)行,進(jìn)程只需要和Binder驅(qū)動(dòng)取得聯(lián)系,通過Binder驅(qū)動(dòng)聯(lián)系另一個(gè)進(jìn)程,那么一次消息的傳送過程就可以實(shí)現(xiàn)了。

內(nèi)核提供提供一系列的系統(tǒng)調(diào)用接口給用戶進(jìn)程使用,當(dāng)用戶進(jìn)程想要訪問內(nèi)核時(shí),只需要調(diào)用對(duì)應(yīng)的接口,此時(shí)代碼就會(huì)從用戶空間切換到內(nèi)核空間執(zhí)行。

常見的系統(tǒng)調(diào)用函數(shù)如:open/read/write/ioctl/close/mmap/fork 等。

與Binder驅(qū)動(dòng)通信分兩步:

打開Binder驅(qū)動(dòng):open("/dev/binder", O_RDWR | O_CLOEXEC)

通過ioctl 與Binder驅(qū)動(dòng)進(jìn)行數(shù)據(jù)通信:ioctl(mDriverFD, BINDER_WRITE_READ, &bwr)
bwr 為讀寫數(shù)據(jù)結(jié)構(gòu)

3. ServiceManager進(jìn)程的作用

Binder Client、Binder Server、ServiceManager關(guān)系

為方便起見,ServiceManager簡稱SM。

Binder 設(shè)計(jì)為C/S架構(gòu),C為Client(客戶端),S為Server(服務(wù)端),Server端提供接口(服務(wù))給Client端使用,而這個(gè)服務(wù)是以Binder引用的形式提供的。

由之前的知識(shí)可知,C和S是不同的進(jìn)程,那么C如何拿到S的Binder引用呢?

你可能會(huì)說,當(dāng)然是SM了,S先將Binder引用存放在SM里,當(dāng)C需要的時(shí)候向SM查詢即可。

這么看似乎講得通了,那問題又來了,SM也是一個(gè)單獨(dú)的進(jìn)程,那S、C如何與SM進(jìn)行通信呢?這就陷入了先有雞還是先有蛋的死循環(huán)了。

實(shí)際上C、S、SM之間都是依靠Binder通信,只是SM作為特殊的Binder(handle=0)提前放入了Binder驅(qū)動(dòng)里,當(dāng)C、S想要獲取SM的Binder引用,只需要獲取handle=0的Binder即可。

這么說沒有太直觀的印象,我們一步步剖析。

ServiceManager注冊進(jìn)Binder

SM 注冊進(jìn)Binder驅(qū)動(dòng)后就會(huì)等待來自Binder驅(qū)動(dòng)的消息,這里列出了兩個(gè)最常見的處理消息的Case:

其它進(jìn)程添加服務(wù)到SM里

其它進(jìn)程向SM查詢服務(wù)

SM里維護(hù)著一個(gè)鏈表,鏈表的元素是結(jié)構(gòu)體:

主要記錄的是name和handle字段。
當(dāng)SM收到添加服務(wù)的指令后,從Binder驅(qū)動(dòng)里取出handle和name,并構(gòu)造結(jié)構(gòu)體插入到鏈表。
當(dāng)SM收到查詢服務(wù)的指令后,從Binder驅(qū)動(dòng)里取出name,并找到鏈表里相同的name,找到后取出handle,最后寫入到Binder驅(qū)動(dòng)。

4. 進(jìn)程添加服務(wù)到ServiceManager的流程

其它進(jìn)程找到SM

現(xiàn)在SM已經(jīng)翹首以盼其它進(jìn)程的請求了,接著來看看如何添加一個(gè)服務(wù)到SM里。
以Java層添加服務(wù)為例,我們選擇振動(dòng)服務(wù)作為切入點(diǎn)分析。

在system_server 進(jìn)程里構(gòu)造振動(dòng)服務(wù)(VibratorService繼承自Binder),并添加到SM里。

可以看出,分兩步:

先找到ServiceManager

往ServiceManager里添加服務(wù)

getIServiceManager()繼續(xù)往下:

BinderInternal.getContextObject() 是native方法,后續(xù)流程較多,我們用圖表示。

尋找ServiceManager的過程涉及到Java層和Native層,主要的重點(diǎn)在Native層查找 ServiceManager對(duì)應(yīng)的BpBinder對(duì)象,沒有找到的話則創(chuàng)建新的并存入緩存里以備下次直接獲取。

ProcessState里維護(hù)了一個(gè)單例,每個(gè)進(jìn)程只有一個(gè)ProcessState對(duì)象,創(chuàng)建ProcessState時(shí)候就會(huì)去打開Binder驅(qū)動(dòng),同時(shí)會(huì)設(shè)置Binder線程池里線程個(gè)數(shù)等其它參數(shù)

Native層構(gòu)造BpBinder(handle=0表示該BpBinder是ServiceManager在客戶端的引用),再構(gòu)造BinderProxyNativeData持有BpBinder。

構(gòu)造BinderProxy對(duì)象并持有BinderProxyNativeData,也就是間接持有BpBinder

最后構(gòu)造了ServiceManagerProxy對(duì)象,它實(shí)現(xiàn)了IServiceManager接口,它的成員變量mRemote指向了BinderProxy

可以看出,獲取ServiceManager的過程并不是真正去獲取ServiceManager的Binder對(duì)象,而是獲取它在當(dāng)前進(jìn)程的代理:BpBinder

添加服務(wù)到ServiceManager

既然找到了SM的Binder代理,接下來看看如何使用它給SM添加服務(wù)。

    #ServiceManagerNative.ServiceManagerProxy
    public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
            throws RemoteException {
        //構(gòu)造Parcel
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        //寫入Binder
        data.writeStrongBinder(service);
        data.writeInt(allowIsolated ? 1 : 0);
        data.writeInt(dumpPriority);
        //通過BinderProxy發(fā)送
        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
        reply.recycle();
        data.recycle();
    }

其中IPCThreadState與線程相關(guān),不同的線程會(huì)維護(hù)一個(gè)單例。

由此可見,最終還是通過BpBinder發(fā)送消息,進(jìn)而發(fā)送到Binder驅(qū)動(dòng)。

此時(shí)驅(qū)動(dòng)收到的信息包括不限于:

服務(wù)的名字

ServiceManager的handle

BBinder對(duì)象指針

驅(qū)動(dòng)建立服務(wù)handle和BBinder對(duì)象指針的映射關(guān)系,并將服務(wù)的名字和服務(wù)的handle傳遞給ServiceManager(通過ServiceManager handle查找)。

ServiceManager拿到消息后建立映射關(guān)系,等待其它進(jìn)程的請求。

至此,進(jìn)程添加服務(wù)到ServiceManager過程已經(jīng)分析完畢,用圖表示如下:

BBinder作用

Java層傳遞的是Binder對(duì)象,如何與Native的BBinder關(guān)聯(lián)起來呢?
重點(diǎn)在:

Parcel.writeStrongBinder(Binder)

也即是說Server端的Java Binder對(duì)象在Native層的代表是BBinder。
Binder驅(qū)動(dòng)記錄了BBinder的地址,當(dāng)有消息過來時(shí)通過找到BBinder對(duì)象進(jìn)而找到Java層的Binder對(duì)象,最終調(diào)用Binder.onTransact()。

5. 進(jìn)程從ServiceManager獲取服務(wù)的流程

其它進(jìn)程找到SM

振動(dòng)服務(wù)添加完成后,某些進(jìn)程想要獲取振動(dòng)服務(wù)進(jìn)行振動(dòng),比如微信收到消息后需要振動(dòng)用以提示用戶。
接著來看看如何獲取振動(dòng)服務(wù)。

    private void vibrate() {
        //獲取振動(dòng)服務(wù)
        Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
        //開始振動(dòng)
        vibrator.vibrate(1000);
    }

與添加服務(wù)類似,想要獲取服務(wù)先要找到SM,找SM的過程上邊分析過了,此處不再細(xì)說。

從ServiceManager獲取服務(wù)

    #ServiceManagerNative.ServiceManagerProxy
    public IBinder getService(String name) throws RemoteException {
        //構(gòu)造Parcel
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        //寫入名字
        data.writeString(name);
        //通過BinderProxy發(fā)送
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }

由此可見,最終還是通過BpBinder發(fā)送消息,進(jìn)而發(fā)送到Binder驅(qū)動(dòng)。
此時(shí)驅(qū)動(dòng)收到的信息包括不限于:

服務(wù)的名字

ServiceManager的handle

Binder驅(qū)動(dòng)收到消息后,找到SM,并將服務(wù)的名字傳給SM,SM從自己維護(hù)的鏈表里找到服務(wù)名相同的節(jié)點(diǎn),最終取出該服務(wù)的handle,發(fā)送給Binder驅(qū)動(dòng)。

用圖表示如下:

對(duì)比添加服務(wù)流程和獲取服務(wù)流程,兩者前半部分都很相似,都是先拿到SM的BpBinder引用,然后寫入驅(qū)動(dòng),最后由SM進(jìn)程處理。只是對(duì)于獲取服務(wù)流程來說,還需要將查詢的結(jié)果(handle)寫入驅(qū)動(dòng)返回給調(diào)用方(對(duì)應(yīng)圖上紅色部分)。

到這,大家可能會(huì)有疑惑了:"handle是整形值,而微信獲取的振動(dòng)服務(wù)是一個(gè)Binder對(duì)象,這兩者是怎么結(jié)合起來的呢?"

handle轉(zhuǎn)換為Binder對(duì)象

handle表示的即是Binder服務(wù)端在客戶端的索引句柄,只要客戶端拿到了handle,它就能通過Binder驅(qū)動(dòng)調(diào)用到服務(wù)端。

        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();

再回過頭看看獲取服務(wù)的代碼,當(dāng)微信進(jìn)程將查詢命令發(fā)給Binder驅(qū)動(dòng)后就等待驅(qū)動(dòng)回復(fù)的結(jié)果,SM查詢到結(jié)果后將handle寫入驅(qū)動(dòng),而后微信進(jìn)程從驅(qū)動(dòng)將結(jié)果讀出并將結(jié)果存入reply字段。
最后通過reply拿到Binder引用,也就是說重點(diǎn)在reply.readStrongBinder()方法。
直接看圖:

如上,通過驅(qū)動(dòng)返回的handle構(gòu)造BpBinder,最終封裝為Java層的BinderProxy。

至此,獲取服務(wù)流程就結(jié)束了,用圖展示簡化的流程

6. Binder服務(wù)端數(shù)據(jù)接收

微信進(jìn)程拿到振動(dòng)服務(wù)(在system_server進(jìn)程里)的Binder(BinderProxy)后,就可以調(diào)用振動(dòng)方法了,而后指令發(fā)送給驅(qū)動(dòng),驅(qū)動(dòng)通過振動(dòng)服務(wù)的handle找到對(duì)應(yīng)的服務(wù)BBinder指針,從而調(diào)用服務(wù)的接收方法。
微信進(jìn)程發(fā)送指令給Binder驅(qū)動(dòng)前面已經(jīng)分析過,重點(diǎn)來看看system_server進(jìn)程是如何接收并處理指令的。

system_server進(jìn)程啟動(dòng)的時(shí)候就會(huì)開啟Binder線程池,并等待驅(qū)動(dòng)數(shù)據(jù)到來。
當(dāng)system_server進(jìn)程添加振動(dòng)服務(wù)到SM時(shí),會(huì)將Java層的Binder轉(zhuǎn)為Native層的BBinder,并將BBinder對(duì)象指針寫入Binder驅(qū)動(dòng)。
當(dāng)微信進(jìn)程調(diào)用system_server接口時(shí):

微信進(jìn)程調(diào)用BpBinder.transact()將handle和數(shù)據(jù)寫入Binder驅(qū)動(dòng)

Binder驅(qū)動(dòng)根據(jù)handle找到system_server進(jìn)程

system_server進(jìn)程從驅(qū)動(dòng)拿到數(shù)據(jù),并取出BBinder指針,最終調(diào)用到system_server進(jìn)程Java層的Binder.onTransact()

如此一來,微信成功調(diào)用了振動(dòng)服務(wù),也就是說一次Client到Server端的通信就完成了。

7. Binder 通信全流程圖

縱觀Binder機(jī)制設(shè)計(jì),最核心的點(diǎn)是handle。

通過handle構(gòu)造Client端的BpBinder(Native層),與此對(duì)應(yīng)的是Java層的BinderProxy

通過handle,驅(qū)動(dòng)找到Server端進(jìn)程,進(jìn)而調(diào)用BBinder(Native層),與此對(duì)應(yīng)的是Java層的Binder

通過handle的一系列中轉(zhuǎn),Client.transact()成功調(diào)用了Server.onTransact(),一次Binder通信就過程就完成了

最后,用一張圖總結(jié)Binder機(jī)制的全過程:

以上就是整個(gè)Binder機(jī)制的梳理過程,此間省略了Binder驅(qū)動(dòng)里的映射邏輯,可以將Binder驅(qū)動(dòng)當(dāng)做一個(gè)黑盒,而更重要的是Binder客戶端和服務(wù)端是如何進(jìn)行映射的。
Binder流程比較繞,尤其是IPCThreadStsate作為客戶端的發(fā)送和服務(wù)端的數(shù)據(jù)接收的實(shí)體,需要區(qū)分不同的場景。
當(dāng)然,jni基礎(chǔ)知識(shí)必不可少。

本文基于Android 10

以上就是Android Binder 通信原理圖文詳解的詳細(xì)內(nèi)容,更多關(guān)于Android Binder 通信原理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

乡城县| 开阳县| 南投市| 阿合奇县| 开封市| 江达县| 汉寿县| 和田市| 华宁县| 灵丘县| 南昌市| 利辛县| 昌邑市| 株洲县| 绥宁县| 榆社县| 石台县| 郯城县| 乌鲁木齐县| 云阳县| 临猗县| 留坝县| 奉新县| 南投县| 新巴尔虎右旗| 江津市| 湾仔区| 乌什县| 祁阳县| 佛冈县| 资中县| 鄢陵县| 静海县| 剑河县| 姚安县| 彭山县| 南通市| 漳州市| 宁乡县| 天津市| 罗江县|