06. Android Binder圖解 小米權(quán)威系統(tǒng)專家 binder面試一網(wǎng)打盡(安卓12)

很多BAT也不一定能懂的binder機制!
因為搞懂binder需要會c,linux內(nèi)核知識。看java根本就看不懂!
我同事從小米跳槽過來,干安卓framework層10年,是小米的專家級別
然后他把binder驅(qū)動層全部和我講解了一遍,然后我這邊做個筆記分享給大家。

1642733316778-03b.png

分6篇文字講解:

  1. Android Binder圖解 小米系統(tǒng)專家 解析Service 的addService注冊過程 (安卓12)
  2. Android Binder圖解 小米系統(tǒng)專家 解析 ServiceManager和binder通信 (安卓12)
  3. Android Binder圖解 小米系統(tǒng)專家 解析binder驅(qū)動層解析binder通信過程 (安卓12)
  4. Android Binder圖解 小米系統(tǒng)專家 從binder java層解析binder整個流程 (安卓12)
  5. Android Binder圖解 小米系統(tǒng)專家 解析binder總結(jié)調(diào)用流程 (安卓12)
  6. Android Binder圖解 小米系統(tǒng)專家 解析binder面試一網(wǎng)打盡(安卓12)
1642733316778-03b.png

問題1: 描述binder通信原理

問題2:Binder Driver 如何在內(nèi)核空間中做到一次拷貝的?

問題3:簡單講講 binder 驅(qū)動吧?

從 Java 層來看就像訪問本地接口一樣,客戶端基于 BinderProxy 服務(wù)端基于 IBinder 對象,從 native 層來看來看客戶端基于 BpBinder 到 ICPThreadState 到 binder 驅(qū)動,服務(wù)端由 binder 驅(qū)動喚醒 IPCThreadSate 到 BbBinder 。跨進程通信的原理最終是要基于內(nèi)核的,所以最會會涉及到 binder_open 、binder_mmap 和 binder_ioctl這三種系統(tǒng)調(diào)用。

Binder 的完整定義

  • 從進程間通信的角度看,Binder 是一種進程間通信的機制;
  • 從 Server 進程的角度看,Binder 指的是 Server 中的 Binder 實體對象;
  • 從 Client 進程的角度看,Binder 指的是 Binder 代理對象,是 Binder 實體對象的一個遠程代理;
  • 從傳輸過程的角度看,Binder 是一個可以跨進程傳輸?shù)膶ο?;Binder 驅(qū)動會對這個跨越進程邊界的對象對一點點特殊處理,自動完成代理對象和本地對象之間的轉(zhuǎn)換。

binder驅(qū)動有什么用? 匿名內(nèi)存有什么用?

哪里過程經(jīng)過了binder驅(qū)動?有看過Binder.cc文件嗎?

binder,為什么c不能訪問a和b的進程中的信息 ?

binder機制的本質(zhì):內(nèi)存共享,不是發(fā)送數(shù)據(jù),所以要深入研究內(nèi)存

binder驅(qū)動和內(nèi)核的關(guān)系: 在 Android 系統(tǒng)中,這個運行在內(nèi)核空間,負責(zé)各個用戶進程通過 Binder 實現(xiàn)通信的內(nèi)核模塊就叫 Binder 驅(qū)動(Binder Dirver)。

Binder 驅(qū)動加載過程中有哪些重要的步驟

答:cs架構(gòu),client:

biner驅(qū)動:

server:

他們在不同進程。server會把自己的能力定義成接口,server注冊到server里面去,然后client通過server代理調(diào)用server的方法。中間都會經(jīng)過binder

問題4:Binder框架中ServiceManager的作用?

Binder框架 是基于 C/S 架構(gòu)的。由一系列的組件組成,包括 Client、Server、ServiceManager、Binder驅(qū)動,其中 Client、Server、Service Manager 運行在用戶空間,Binder 驅(qū)動運行在內(nèi)核空間。如下圖所示:

[圖片上傳失敗...(image-9fa5d4-1643251732134)]

  • Server&Client:服務(wù)器&客戶端。在Binder驅(qū)動和Service Manager提供的基礎(chǔ)設(shè)施上,進行Client-Server之間的通信。
  • ServiceManager(如同DNS域名服務(wù)器)服務(wù)的管理者,將Binder名字轉(zhuǎn)換為Client中對該Binder的引用,使得Client可以通過Binder名字獲得Server中Binder實體的引用。
  • Binder驅(qū)動(如同路由器):負責(zé)進程之間binder通信的建立,計數(shù)管理以及數(shù)據(jù)的傳遞交互等底層支持。

ServiceManager的作用是怎么樣的?

ServiceManager最核心的兩個功能為查詢和注冊服務(wù):

  • 注冊服務(wù):記錄服務(wù)名和handle信息,保存到svclist列表;
  • 查詢服務(wù):根據(jù)服務(wù)名查詢相應(yīng)的的handle信息。

首先Service會通過addService將binder實體注冊到ServiceManager中去,Client如果想要使用Servcie,就需要通過getService向ServiceManager請求該服務(wù)

問題5:binder驅(qū)動是如何和servermanager通信的?

問題6:binder相關(guān),如何實現(xiàn)binder異步調(diào)用(頭條)

Binder請求的同步與異步

如果我在子線程跨進程調(diào)用會怎么樣?如何實現(xiàn)binder異步調(diào)用?

很多人都會說,Binder是對Client端同步,而對Service端異步,其實并不完全正確,在單次Binder數(shù)據(jù)傳遞的過程中,其實都是同步的。只不過,Client在請求Server端服務(wù)的過程中,是需要返回結(jié)果的,即使是你看不到返回數(shù)據(jù),其實還是會有個成功與失敗的處理結(jié)果返回給Client,這就是所說的Client端是同步的。

問題7:****如何實現(xiàn)****binder異步調(diào)用?

客戶端進行遠程 RPC 請求時,線程會掛起,等待結(jié)果,由此也可知,AIDL 的調(diào)用過程是同步的

IDL 的調(diào)用過程是同步的,當(dāng)我們需要服務(wù)端做耗時操作時,肯定是不能使用同步調(diào)用的,否則輕者影響用戶體驗,重者直接 ANR 或者應(yīng)用崩潰。那么如何使 AIDL 的調(diào)用過程是異步的呢?

其實也很簡單,只需要把調(diào)用放到非 UI 線程即可,如果要對調(diào)用的返回做 UI 更新的話,再通過 Handler 處理即可

看完圖總結(jié):

也就是客戶端通過 Proxy 訪問 Binder 驅(qū)動,然后 Binder 驅(qū)動調(diào)用 Stub,而 Stub 中調(diào)用我們的業(yè)務(wù)邏輯。這里的 ProxyStub 用來統(tǒng)一接口函數(shù),

Proxy 用來告訴我們遠程服務(wù)中有哪些可用的方法,持有serverr端的代理對象binder

而具體的業(yè)務(wù)邏輯則由 Stub 來實現(xiàn)。

Binder 的進程通信就發(fā)生在 ProxyStub 之間。

而且所謂的服務(wù)端和客戶端都是相對而言的,服務(wù)端不僅可以接收和處理消息,而且可以定時往客戶端發(fā)送數(shù)據(jù),與此同時服務(wù)端使用Proxy類跨進程調(diào)用,相當(dāng)于充當(dāng)了”Client”。

這樣,客戶端只需要和 Proxy 打交道,服務(wù)端只需要和 Stub 打交道,調(diào)理清晰很多。圖如下:

[圖片上傳失敗...(image-af291e-1643251732134)]

問題8:****intent傳值,大小限制和什么有關(guān)?binder?binder如何限制這個大???跨進程傳遞大圖,你能想到哪些方案呢?

intent傳值,大小限制和什么有關(guān)?binder?binder如何限制這個大小?

跨進程傳遞大圖,你能想到哪些方案呢?

需求背景

項目中有個需求是這樣的,在主進程Activity 中選擇或者編輯一張背景圖產(chǎn)生一個bitmap 對象,要傳遞給 B進程(推流進程)作為推流引擎的背景圖,這個bitmap 有可能比較大,因為要盡量保證清晰度,所以這個bitmap還有可能比較大,所以必然會涉及到跨進程傳輸大型bitmap 的問題。

第一種方式:傳遞路徑,通過文件寫入。contentProvider封裝,然后可以

第二種方式,如果是startActivity。通過putbinder

之前小數(shù)據(jù):開辟一個ashmem保存,這個數(shù)據(jù)有大小限制的

用putbinder話:會parcel的緩沖區(qū)里分配一塊空間來保存這個數(shù)據(jù)

第三種方式,AIDL:有什么辦法解決嗎?

源碼分析:

https://blog.csdn.net/ylyg050518/article/details/97671874

1M-8k=1024-8k=1M-pageSIze4k。這個值在c代碼里面。多少個頁*

https://blog.csdn.net/u011033906/article/details/89316543

(frameworks/native/libs/binder/****ProcessState****.cpp)

ProcessState.cpp

define DEFAULT_BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)#define DEFAULT_MAX_BINDER_THREADS 0

如果是異步的話,大小又是多少呢?

是上面的大小除以2。可以看源碼

https://blog.csdn.net/ylyg050518/article/details/97671874

問題9:aidl實現(xiàn)原理,如何實現(xiàn)回調(diào)?

onconnect之后會得到ibinder對象,這個過程是怎么樣的?

<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-size: 0.8rem;">private ServiceConnection mStepConnect = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mServiceAutoStepInterface = IServiceAutoStepInterface.Stub.asInterface(service);
try {
mServiceAutoStepInterface.registerListener(mStepCountListener);
} catch (Throwable e) {
}
}
</pre>

源碼:從binderserver------AMS----ActivityThrad.可以看到

問題10:****講講AIDL?如何優(yōu)化多模塊都使用AIDL的情況?

AIDL(Android Interface Definition Language,Android接口定義語言):如果在一個進程中要調(diào)用另一個進程中對象的方法,可使用AIDL生成可序列化的參數(shù),AIDL會生成一個服務(wù)端對象的代理類,通過它客戶端可以實現(xiàn)間接調(diào)用服務(wù)端對象的方法。

AIDL的本質(zhì)是系統(tǒng)提供了一套可快速實現(xiàn)Binder的工具。關(guān)鍵類和方法:

  • AIDL接口:繼承IInterface。
  • Stub類:Binder的實現(xiàn)類,服務(wù)端通過這個類來提供服務(wù)。
  • Proxy類:服務(wù)端的本地代理,客戶端通過這個類調(diào)用服務(wù)端的方法。
  • asInterface():客戶端調(diào)用,將服務(wù)端返回的Binder對象,轉(zhuǎn)換成客戶端所需要的AIDL接口類型的對象。如果客戶端和服務(wù)端位于同一進程,則直接返回Stub對象本身,否則返回系統(tǒng)封裝后的Stub.proxy對象。
  • asBinder():根據(jù)當(dāng)前調(diào)用情況返回代理Proxy的Binder對象。
  • onTransact():運行在服務(wù)端的Binder線程池中,當(dāng)客戶端發(fā)起跨進程請求時,遠程請求會通過系統(tǒng)底層封裝后交由此方法來處理。
  • transact():運行在客戶端,當(dāng)客戶端發(fā)起遠程請求的同時將當(dāng)前線程掛起。之后調(diào)用服務(wù)端的onTransact()直到遠程請求返回,當(dāng)前線程才繼續(xù)執(zhí)行。

當(dāng)有多個業(yè)務(wù)模塊都需要AIDL來進行IPC,此時需要為每個模塊創(chuàng)建特定的aidl文件,那么相應(yīng)的Service就會很多。必然會出現(xiàn)系統(tǒng)資源耗費嚴(yán)重、應(yīng)用過度重量級的問題。解決辦法是建立Binder連接池,即將每個業(yè)務(wù)模塊的Binder請求統(tǒng)一轉(zhuǎn)發(fā)到一個遠程Service中去執(zhí)行,從而避免重復(fù)創(chuàng)建Service。

工作原理:每個業(yè)務(wù)模塊創(chuàng)建自己的AIDL接口并實現(xiàn)此接口,然后向服務(wù)端提供自己的唯一標(biāo)識和其對應(yīng)的Binder對象。服務(wù)端只需要一個Service并提供一個queryBinder接口,它會根據(jù)業(yè)務(wù)模塊的特征來返回相應(yīng)的Binder對象,不同的業(yè)務(wù)模塊拿到所需的Binder對象后就可以進行遠程方法的調(diào)用了。

問題11:binder 復(fù)習(xí)stub proxy代表的含義?如何得到服務(wù)端的代理和客戶端的代理

答:它們是生成的java里面的2個類

stub :Stub是用于在服務(wù)端進程創(chuàng)建的對象 。得到代理,調(diào)用remote的onTranslAct方法

proxy:是用于在客戶端進程創(chuàng)建的代理對象 。代理,先序列化。在里面調(diào)用translact方法

是服務(wù)端的Stub對象在客戶端進程的代理對象,客戶端進程通過Proxy對象發(fā)出方法調(diào)用然后通過Binder驅(qū)動后最終調(diào)用服務(wù)端進程的Stub對象的方法。每一個Stub遠程對象都在客戶端進程中對應(yīng)有一個本地代理對象Proxy。

問題12:.binder進程間通信可以調(diào)用原進程方法嗎?

答:可以,通過代理的形式調(diào)用

[圖片上傳失敗...(image-9f1d00-1643251732122)]

在使用 Binder 時基本都是調(diào)用 framework 層封裝好的方法,AIDL 就是 framework 層提供的傻瓜式是使用方式。假設(shè)服務(wù)已經(jīng)注冊完,客戶端怎么執(zhí)行服務(wù)端的方法:

首先通過 ServiceManager 獲取到服務(wù)端的 BinderProxy 代理對象,通過調(diào)用 BinderProxy 將參數(shù),方法標(biāo)識(例如:TRANSACTION_test,AIDL中自動生成)傳給 ServiceManager,同時客戶端線程進入等待狀態(tài)。

ServiceManager 將用戶空間的參數(shù)等請求數(shù)據(jù)復(fù)制到內(nèi)核空間,并向服務(wù)端插入一條執(zhí)行執(zhí)行方法的事務(wù)。事務(wù)執(zhí)行完通知 ServiceManager 將執(zhí)行結(jié)果從內(nèi)核空間復(fù)制到用戶空間,并喚醒等待的線程,響應(yīng)結(jié)果,通訊結(jié)束

問題13:AIDL的in和out的了解么

AIDL平時開發(fā)過程中用的還真是少,網(wǎng)上找的一個解釋:

  • in、out、inout表示跨進程通信中數(shù)據(jù)的流向(基本數(shù)據(jù)類型默認是in,非基本數(shù)據(jù)類型可以使用其它數(shù)據(jù)流向out、inout)。
  • in 表示數(shù)據(jù)只能由客戶端流向服務(wù)端。(表現(xiàn)為服務(wù)端修改此參數(shù),不會影響客戶端的對象)
  • out 表示數(shù)據(jù)只能由服務(wù)端流向客戶端。(表現(xiàn)為服務(wù)端收到的參數(shù)是空對象,并且服務(wù)端修改對象后客戶端會同步變動)
  • inout 則表示數(shù)據(jù)可在服務(wù)端與客戶端之間雙向流通。(表現(xiàn)為服務(wù)端能接收到客戶端傳來的完整對象,并且服務(wù)端修改對象后客戶端會同步變動)
    詳細解釋可以看看:AIDL參數(shù)中in、out、inout的區(qū)別

AIDL中的定向 tag 表示了在跨進程通信中數(shù)據(jù)的流向

  • in、out、inout表示跨進程通信中數(shù)據(jù)的流向(基本數(shù)據(jù)類型默認是in,非基本數(shù)據(jù)類型可以使用其它數(shù)據(jù)流向out、inout)。
  • in 表示數(shù)據(jù)只能由客戶端流向服務(wù)端。(表現(xiàn)為服務(wù)端修改此參數(shù),不會影響客戶端的對象)
  • out 表示數(shù)據(jù)只能由服務(wù)端流向客戶端。(表現(xiàn)為服務(wù)端收到的參數(shù)是空對象,并且服務(wù)端修改對象后客戶端會同步變動)
  • inout 則表示數(shù)據(jù)可在服務(wù)端與客戶端之間雙向流通。(表現(xiàn)為服務(wù)端能接收到客戶端傳來的完整對象,并且服務(wù)端修改對象后客戶端會同步變動)
    詳細解釋可以看看:AIDL參數(shù)中in、out、inout的區(qū)別
  • [圖片上傳失敗...(image-306fe8-1643251732134)]

問題14:系統(tǒng)服務(wù)與bindService等啟動的服務(wù)的區(qū)別

使用系統(tǒng)服務(wù)一般都是通過ServiceManager的getService得到服務(wù)的句柄,這個過程其實就是去ServiceManager中查詢注冊系統(tǒng)服務(wù)。而bindService啟動的服務(wù),主要是去ActivityManagerService中去查找相應(yīng)的Service組件,最終會將Service內(nèi)部Binder的句柄傳給Client。

問題15:binder怎么驗證pid?

pid與uid的區(qū)別

答:pid是進程ID,PID是進程的身份標(biāo)志,系統(tǒng)給每個應(yīng)用分配獨一無二的PID(一個應(yīng)用可能有多個進程,每個進程有唯一的PID)

進程終止后PID會被系統(tǒng)回收,再次打開應(yīng)用會重新分配一個PID。

UID在linux中是用戶的ID,用于權(quán)限的管理。在android中,由于android是單用戶系統(tǒng),所以uid被用于實現(xiàn)數(shù)據(jù)共享。

通過Activity的啟動流程會驗證PID的!

https://blog.csdn.net/windskier/article/details/6921672

問題16:****權(quán)限驗證

就算是公交車,上車也得嘀卡對不,如果希望我們的服務(wù)進程不想像公交車一樣誰想上就上,那么我們可以加入權(quán)限驗證。

介紹兩種常用驗證方法:

  1. 在服務(wù)端的onBind中校驗自定義permission,如果通過了我們的校驗,正常返回Binder對象,校驗不通過返回null,返回null的情況下客戶端無法綁定到我們的服務(wù);

    代碼如下:

[圖片上傳失敗...(image-f041fd-1643251732133)]

  1. 在服務(wù)端的onTransact方法校驗客戶端包名****,不通過校驗直接return false,校驗通過執(zhí)行正常的流程。

[圖片上傳失敗...(image-d4ab05-1643251732134)]

<pre style="margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace; font-size: 0.817rem;">private Binder mBinder = new IImageManager.Stub() {
@Override
public void doTask(int count) throws RemoteException {
Log.d("ImageManagerService", "doTask");
Thread thread = new Thread() {
@Override
public void run() {
Log.e(TAG, "startImageScanner:size-->");
}
};
thread.start();
}

@Override

public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
return super.onTransact(code, data, reply, flags);
}

@Override

public IBinder asBinder() {
return super.asBinder();
}
};</pre>

跨進程文件寫入如何保證安全

和sp一樣,通過contentProvider。用openFile方法!

https://blog.csdn.net/fan380485838/article/details/80937414

問題17:.主進程和子進程間的通信,通過哪塊內(nèi)存區(qū)域?

Android匿名共享內(nèi)存(Ashmem)原理

Android匿名共享內(nèi)存(Ashmem)原理 - 簡書 (jianshu.com)問題18:**** 客戶端如何將函數(shù)形參發(fā)送給遠程進程中的函數(shù),以及如何將遠程進程函數(shù)計算結(jié)果返回客戶端

  1. 定義接口Parcelable,這個接口提供2個重要函數(shù),分別是將對象中的屬性寫入到數(shù)組和從數(shù)組中的數(shù)據(jù)還原對象,每個可以發(fā)送到遠程函數(shù)作為形參的對象只需實現(xiàn)Parcelable對象即可

[圖片上傳失敗...(image-ba85bd-1643251732134)]

[圖片上傳失敗...(image-e6a77d-1643251732134)]

從上面的Binder 的使用流程我們可以知道幾個事情:

1).服務(wù)端和客戶端是兩個進程,客戶端調(diào)用transact(),服務(wù)端實現(xiàn)onTransact()

  1. . Binder的調(diào)用,在客戶端看來是同步的,transact()從調(diào)用到獲取結(jié)果的過程。

3). Binder的被調(diào)用,在服務(wù)端看來是異步,支持多個客戶端調(diào)用,服務(wù)端底層是線程池。所以可能需要注意同步的問題。

4). 如果服務(wù)端和客戶端在同一個進程,是不會發(fā)生Binder通信的,而是在asInterface返回服務(wù)端的對象。

5). onTransact可以做權(quán)限驗證,拒絕調(diào)用。

6). 客戶端在調(diào)用add的時候,內(nèi)部是調(diào)用transact,在等待回應(yīng)的時候?qū)粧炱?,所以若是耗時操作的話需要開啟子線程。

問題19:****怎么理解頁框和頁?

???:頁框是指一塊實際的物理內(nèi)存,頁是指程序的一塊內(nèi)存數(shù)據(jù)單元。內(nèi)存數(shù)據(jù)一定是存儲在實際的物理內(nèi)存上,即頁必然對應(yīng)于一個頁框,頁數(shù)據(jù)實際是存儲在頁框上的。

頁框和頁一樣大,都是內(nèi)核對內(nèi)存的分塊單位。一個頁框可以映射給多個頁,也就是說一塊實際的物理存儲空間可以映射給多個進程的多個虛擬內(nèi)存空間,這也是 mmap 機制依賴的基礎(chǔ)規(guī)則

linux使用MMU的機器都采用分頁機制。虛擬地址空間以為單位進行劃分,而相應(yīng)的物理地址空間也被劃分,其使用的單位稱為頁幀,頁幀和頁必須保持相同,因為內(nèi)存與外部存儲器之間的傳輸是以頁為單位進行傳輸?shù)?/strong>。

例如,MMU可以通過一個映射項將VA的一頁0xb70010000xb7001fff映射到PA的一頁0x20000x2fff,如果CPU執(zhí)行單元要訪問虛擬地址0xb7001008,則實際訪問到的物理地址是0x2008。

虛擬內(nèi)存的哪個頁面映射到物理內(nèi)存的哪個頁幀是通過頁表(Page Table)來描述的,頁表保存在物理內(nèi)存中,MMU會查找頁表來確定一個VA應(yīng)該映射到什么PA。

問題20:.mmap沒調(diào)用msync時候,落盤時機。.MMKV原理

問題21:.linux有哪些多進程方案?

實際的問題:

1.A 進程想要 B 進程中某個對象(object)是如何實現(xiàn)的呢?

應(yīng)該是不行吧??梢?,通過接口返回一個類。AIDL,獲取代理。我發(fā)現(xiàn)不對,拿到的是接口。如何獲取另外一個進程的對象!可以通過接口返回一個對象就可以

客戶端持有遠程進程的某個對象引用,然后調(diào)用引用類中的函數(shù),遠程進程的函數(shù)就執(zhí)行了。我在想,憑什么?學(xué)過操作系統(tǒng)都知道,不同的進程之間是不共享資源的。也就是說,客戶端持有的這個對象跟遠程進程中的實際對象完全是兩個不同的對象。客戶端調(diào)用引用的對象跟遠程進程半毛錢關(guān)系都沒有,憑啥遠程進程就調(diào)用了執(zhí)行了?

————————————————

我們所持有的Binder引用(即服務(wù)端的類引用)并不是實際真實的遠程Binder對象,我們的引用在Binder驅(qū)動里還要做一次映射。也就是說,設(shè)備驅(qū)動根據(jù)我們的引用對象找到對應(yīng)的遠程進程。客戶端要調(diào)用遠程對象函數(shù)時,只需把數(shù)據(jù)寫入到Parcel,在調(diào)用所持有的Binder引用的transact()函數(shù),transact函數(shù)執(zhí)行過程中會把參數(shù)、標(biāo)識符(標(biāo)記遠程對象及其函數(shù))等數(shù)據(jù)放入到Client的共享內(nèi)存,Binder驅(qū)動從Client的共享內(nèi)存中讀取數(shù)據(jù),根據(jù)這些數(shù)據(jù)找到對應(yīng)的遠程進程的共享內(nèi)存,把數(shù)據(jù)拷貝到遠程進程的共享內(nèi)存中,并通知遠程進程執(zhí)行onTransact()函數(shù),這個函數(shù)也是屬于Binder類。遠程進程Binder對象執(zhí)行完成后,將得到的寫入自己的共享內(nèi)存中,Binder驅(qū)動再將遠程進程的共享內(nèi)存數(shù)據(jù)拷貝到客戶端的共享內(nèi)存,并喚醒客戶端線程。

————————————————--------

比較好的回答:

我們已經(jīng)解釋清楚 Client、Server 借助 Binder 驅(qū)動完成跨進程通信的實現(xiàn)機制了,但是還有個問題會讓我們困惑。A 進程想要 B 進程中某個對象(object)是如何實現(xiàn)的呢?畢竟它們分屬不同的進程,A 進程 沒法直接使用 B 進程中的 object。

前面我們介紹過跨進程通信的過程都有 Binder 驅(qū)動的參與,因此在數(shù)據(jù)流經(jīng) Binder 驅(qū)動的時候驅(qū)動會對數(shù)據(jù)做一層轉(zhuǎn)換。當(dāng) A 進程想要獲取 B 進程中的 object 時,驅(qū)動并不會真的把 object 返回給 A,而是返回了一個跟 object 看起來一模一樣的代理對象 objectProxy,這個 objectProxy 具有和 object 一摸一樣的方法,但是這些方法并沒有 B 進程中 object 對象那些方法的能力,這些方法只需要把把請求參數(shù)交給驅(qū)動即可。對于 A 進程來說和直接調(diào)用 object 中的方法是一樣的。

當(dāng) Binder 驅(qū)動接收到 A 進程的消息后,發(fā)現(xiàn)這是個 objectProxy 就去查詢自己維護的表單,一查發(fā)現(xiàn)這是 B 進程 object 的代理對象。于是就會去通知 B 進程調(diào)用 object 的方法,并要求 B 進程把返回結(jié)果發(fā)給自己。當(dāng)驅(qū)動拿到 B 進程的返回結(jié)果后就會轉(zhuǎn)發(fā)給 A 進程,一次通信就完成了。

[圖片上傳失敗...(image-83ef79-1643251732136)]

————————————————

2.A 進程想要 B 進程中方法怎么實現(xiàn)的呢

那么請問:在調(diào)用2個數(shù)相加的方法中,哪里經(jīng)過了一次拷貝?

這個過程就是一次拷貝,不僅僅說的是數(shù)據(jù)的拷貝

同上,先獲取代理,然后調(diào)用方法,也就是接口

3.A 進程想要 B 進程中變量值

和MMKV一樣,進行內(nèi)存映射

4.Binder線程、Binder主線程、Client請求線程的概念與區(qū)別(網(wǎng)易)

拿ServerManager進程來說,其主線就是Binder線程

最后來看一下普通Client的binder請求線程,比如我們APP的主線程,在startActivity請求AMS的時候,APP的主線程成其實就是Binder請求線程,在進行Binder通信的過程中,Client的Binder請求線程會一直阻塞

binder線程:

  • 一個進程的Binder線程數(shù)默認最大是16,超過的請求會被阻塞等待空閑的Binder線程。

    所以,在進程間通信時處理并發(fā)問題時,如使用ContentProvider時,它的CRUD(創(chuàng)建、檢索、更新和刪除)方法只能同時有16個線程同時工作

好像是15個。和傳的大小在同一個源碼里面。

binder線程池的最大線程個數(shù);binder線程池中如果滿了,對待新來的任務(wù),會如何處理?此時client端會是什么效果?

阻塞,等待空閑的binder線程

4.Server端的binder都是運行在同一個線程里面么?

不是

binder里面的進程和線程關(guān)系:

對于底層Binder驅(qū)動,通過 binder_procs 鏈表記錄所有創(chuàng)建的 binder_proc 結(jié)構(gòu)體,binder 驅(qū)動層的每一個 binder_proc 結(jié)構(gòu)體都與用戶空間的一個用于 binder 通信的進程一一對應(yīng),且每個進程有且只有一個 ProcessState 對象,這是通過單例模式來保證的。在每個進程中可以有很多個線程,每個線程對應(yīng)一個 IPCThreadState 對象,IPCThreadState 對象也是單例模式,即一個線程對應(yīng)一個 IPCThreadState 對象,在 Binder 驅(qū)動層也有與之相對應(yīng)的結(jié)構(gòu),那就是 Binder_thread 結(jié)構(gòu)體。在 binder_proc 結(jié)構(gòu)體中通過成員變量 rb_root threads,來記錄當(dāng)前進程內(nèi)所有的 binder_thread。

Binder 線程池:每個 Server 進程在啟動時創(chuàng)建一個 binder 線程池,并向其中注冊一個 Binder 線程;之后 Server 進程也可以向 binder 線程池注冊新的線程,或者 Binder 驅(qū)動在探測到?jīng)]有空閑 binder 線程時主動向 Server 進程注冊新的的 binder 線程。對于一個 Server 進程有一個最大 Binder 線程數(shù)限制,默認為16個 binder 線程,例如 Android 的 system_server 進程就存在16個線程。對于所有 Client 端進程的 binder 請求都是交由 Server 端進程的 binder 線程來處理的。

————————————————

線程和進程的區(qū)別?

1、進程是一段正在執(zhí)行的程序,是資源分配的基本單元,而線程是CPU調(diào)度的基本單元。
2、進程間相互獨立進程,進程之間不能共享資源,一個進程至少有一個線程,同一進程的各線程共享整個進程的資源(寄存器、堆棧、上下文)。
3、線程的創(chuàng)建和切換開銷比進程小。

4. 多進程的使用場景:打電話,加載圖片,webview,推送。

5.服務(wù)端進程Crash了,而客戶端進程想要調(diào)用服務(wù)端方法,這樣就調(diào)用不到了

此時我們可以給Binder設(shè)置一個DeathRecipient對象,當(dāng)Binder意外掛了的時候,我們可以在DeathRecipient接口的回調(diào)方法中收到通知,并作出相應(yīng)的操作,比如重連服務(wù)等等。

6.一般來說,使用多進程通信會造成如下幾方面的問題:

  • 靜態(tài)成員和單例模式完全失效:獨立的虛擬機造成。
  • 線程同步機制完全失效:獨立的虛擬機造成。
  • SharedPreferences的可靠性下降:這是因為Sp不支持兩個進程并發(fā)進行讀寫,有一定幾率導(dǎo)致數(shù)據(jù)丟失。
  • Application會多次創(chuàng)建:Android系統(tǒng)在創(chuàng)建新的進程時會分配獨立的虛擬機,所以這個過程其實就是啟動一個應(yīng)用的過程,自然也會創(chuàng)建新的Application。

binder面試題:

https://juejin.cn/post/6870447920911646734

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容