欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android Binder 通信原理圖文詳解

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

前言

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

Binder的作用

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

ServiceManager進(jìn)程的作用

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

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

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

Binder 通信全流程圖

1. Binder的作用

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

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

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

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

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

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

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

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

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

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

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

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

通過ioctl 與Binder驅(qū)動進(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è)計為C/S架構(gòu),C為Client(客戶端),S為Server(服務(wù)端),Server端提供接口(服務(wù))給Client端使用,而這個服務(wù)是以Binder引用的形式提供的。

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

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

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

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

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

ServiceManager注冊進(jìn)Binder

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

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

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

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

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

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

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

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

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

可以看出,分兩步:

先找到ServiceManager

往ServiceManager里添加服務(wù)

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

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

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

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

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

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

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

可以看出,獲取ServiceManager的過程并不是真正去獲取ServiceManager的Binder對象,而是獲取它在當(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),不同的線程會維護(hù)一個單例。

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

此時驅(qū)動收到的信息包括不限于:

服務(wù)的名字

ServiceManager的handle

BBinder對象指針

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

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

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

BBinder作用

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

Parcel.writeStrongBinder(Binder)

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

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

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

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

    private void vibrate() {
        //獲取振動服務(wù)
        Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
        //開始振動
        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ū)動。
此時驅(qū)動收到的信息包括不限于:

服務(wù)的名字

ServiceManager的handle

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

用圖表示如下:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

7. Binder 通信全流程圖

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

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

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

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

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

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

本文基于Android 10

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

相關(guān)文章

最新評論