邢臺(tái)建設(shè)網(wǎng)站如何做百度關(guān)鍵詞推廣
讀完本文你將了解:
-
- IBinder
- Binder
- Binder 通信機(jī)制
- Binder 驅(qū)動(dòng)
- Service Manager
- Binder 機(jī)制跨進(jìn)程通信流程
- Binder 機(jī)制的優(yōu)點(diǎn)
- 總結(jié)
- Thanks
上篇文章 Android 進(jìn)階7:進(jìn)程通信之 AIDL 中我們雖然跨進(jìn)程通信成功,但是還是有很多疑問的,比如:
- AIDL 幫我們做了什么?
- 為什么要這么寫?
- 什么是 Binder?
知其然還要知其所以然,一切都要從 Binder 講起。
IBinder
Binder
繼承自 IBinder
,所以我們先來了解下它。
public class Binder implements IBinder {...}
public interface IBinder {...}
IBinder 是一個(gè)接口,它代表了一種跨進(jìn)程傳輸?shù)哪芰ΑV灰獙?shí)現(xiàn)了這個(gè)接口,就能將這個(gè)對(duì)象進(jìn)行跨進(jìn)程傳遞。
IBinder 是高性能、輕量級(jí)遠(yuǎn)程調(diào)用機(jī)制的核心部分,它定義了遠(yuǎn)程操作對(duì)象的基本接口。
這些方法中最關(guān)鍵的一個(gè)是 transact()
:
public boolean transact(int code, Parcel data, Parcel reply, int flags)throws RemoteException;
與它對(duì)應(yīng)的是 Binder.onTransact()
protected boolean onTransact(int code, Parcel data, Parcel reply,int flags) throws RemoteException {...}
可以看到這兩個(gè)方法非常相似,介紹一下方法中的各個(gè)參數(shù):
code
:要執(zhí)行的動(dòng)作,類似 Handler 的 msg.what,IBinder 中定義了以下幾個(gè) code
PING_TRANSACTION
,表示要調(diào)用pingBinder()
方法DUMP_TRANSACTION
,表示要獲取 Binder 內(nèi)部狀態(tài)SHELL_COMMAND_TRANSACTION
,執(zhí)行一個(gè) shell 命令INTERFACE_TRANSACTION
,詢問被調(diào)用方的接口描述符號(hào)TWEET_TRANSACTION
LIKE_TRANSACTION
- 如果我們需要自定義 code,code 的值范圍需要在
FIRST_CALL_TRANSACTION
(0x00000001) 和LAST_CALL_TRANSACTION
(0x00ffffff) 之間
data
,reply
:傳入的參數(shù)和返回的值flags
:表示是否需要阻塞等待返回值,有兩個(gè)值
- 0
FLAG_ONEWAY
(0x00000001),表示 Client 的transact()
是單向調(diào)用,執(zhí)行后立即返回
①經(jīng)常的場景是,我們調(diào)用 IBinder.transact()
給一個(gè) IBinder 對(duì)象發(fā)送請(qǐng)求,然后經(jīng)過 Binder Binder.onTransact()
得到調(diào)用,接著遠(yuǎn)程操作的目標(biāo)得到對(duì)應(yīng)的調(diào)用。
這個(gè)過程不僅在同一進(jìn)程中可以進(jìn)行,在跨進(jìn)程(IPC)間也可以完成。
IBinder.transact()
方法是同步的,它被調(diào)用后一直到Binder.onTransact()
調(diào)用完成后才返回。
②通過 IBinder.transact()
方法傳輸?shù)臄?shù)據(jù)被保存為一個(gè) Parcel
對(duì)象,Parcel
中保存了數(shù)據(jù)以及描述數(shù)據(jù)的元數(shù)據(jù),元數(shù)據(jù)在緩存區(qū)中保持了 IBinder 對(duì)象的引用,這樣不同進(jìn)程都可以訪問同一個(gè)數(shù)據(jù)。
因此在一個(gè) IBinder 對(duì)象寫入 Parcel 對(duì)象然后發(fā)送到另一個(gè)進(jìn)程時(shí),另外那進(jìn)程將這個(gè) IBinder 對(duì)象發(fā)送回去時(shí),原本進(jìn)程接收到的 IBinder 對(duì)象和開始發(fā)送出去的是同一個(gè)引用。
在跨進(jìn)程傳輸后引用沒有改變,這是非常關(guān)鍵的一點(diǎn),這就使得 IBinder/Binder
對(duì)象在跨進(jìn)程通信時(shí)可以作為唯一的標(biāo)識(shí)(比如作為 token 什么的)。
③系統(tǒng)在每個(gè)進(jìn)程中都有一個(gè)處理事物的線程池,這些線程用于調(diào)度其他進(jìn)程對(duì)當(dāng)前進(jìn)程的跨進(jìn)程訪問。
比如說進(jìn)程 A 對(duì)進(jìn)程 B 發(fā)起 IPC 時(shí),A 中調(diào)用 transact()
的線程會(huì)阻塞。B 中的事物線程池收到 A 的 IPC,調(diào)用目標(biāo)對(duì)象的 Binder.onTransact()
方法,然后返回帶結(jié)果的 Parcel。一旦接收到結(jié)果,A 中阻塞的線程得以繼續(xù)執(zhí)行。
這個(gè)過程和線程通信非常相似吧。
④Binder 機(jī)制還支持進(jìn)程間的遞歸調(diào)用。
比如,進(jìn)程 A 向進(jìn)程 B 發(fā)起 IPC,而進(jìn)程 B 在其 Binder.onTransact()
中又用 transact()
向進(jìn)程 A 發(fā)起 IPC,那么進(jìn)程 A 在等待它發(fā)出的調(diào)用返回的同時(shí),也會(huì)響應(yīng) B 的調(diào)用,對(duì)調(diào)用的對(duì)象執(zhí)行 Binder.onTransact() 方法。
這種機(jī)制可以讓我們覺得到跨進(jìn)程的調(diào)用與進(jìn)程內(nèi)的調(diào)用沒什么區(qū)別,這是非常重要的。
⑤在跨進(jìn)程通信時(shí),我們常常想要知道另外進(jìn)程是否可用,IBinder 提供了三個(gè)檢查的方法:
transact()
- 當(dāng)你調(diào)用的 IBinder 所在進(jìn)程不存在時(shí),會(huì)拋出
RemoteException
異常
- 當(dāng)你調(diào)用的 IBinder 所在進(jìn)程不存在時(shí),會(huì)拋出
pingBinder()
- 當(dāng)遠(yuǎn)程進(jìn)程不存在時(shí)該方法返回 false
linkToDeath()
- 這個(gè)方法可以向 IBinder 中注冊(cè)一個(gè)
IBinder.DeathRecipient
,它將在 IBinder 所在的進(jìn)程退出時(shí)被調(diào)用
- 這個(gè)方法可以向 IBinder 中注冊(cè)一個(gè)
/*** 檢查遠(yuǎn)程 Binder 對(duì)象是否存在* * 當(dāng)不存在時(shí)返回 false*/
public boolean pingBinder();
/*** 注冊(cè)一個(gè) Binder 銷毀的監(jiān)聽如果一個(gè) Binder 被銷毀(通常是它所在的進(jìn)程被關(guān)閉),會(huì)回調(diào) DeathRecipient 的 BinderDied 方法* 注意,只會(huì)監(jiān)聽遠(yuǎn)程的 Binder,本地 Binder 一般不會(huì)銷毀,除非當(dāng)前進(jìn)程退出* * 如果要注冊(cè)的 Binder 進(jìn)程已經(jīng)銷毀,就拋出 RemoteException */
public void linkToDeath(DeathRecipient recipient, int flags)throws RemoteException;/*** linkToDeath 注冊(cè)監(jiān)聽回調(diào)的接口*/
public interface DeathRecipient {public void binderDied();
}
Binder
官方文檔中建議:
日常開發(fā)中一般不需要我們?cè)賹?shí)現(xiàn) IBinder,直接使用系統(tǒng)提供的 Binder 即可。
Binder 實(shí)現(xiàn)了 IBinder 定義的操作,它是 Android IPC 的基礎(chǔ),平常接觸到的各種 Manager(ActivityManager, ServiceManager 等),以及綁定 Service 時(shí)都在使用它進(jìn)行跨進(jìn)程操作。
它的存在不會(huì)影響一個(gè)應(yīng)用的生命周期,只要?jiǎng)?chuàng)建它的進(jìn)程在運(yùn)行它就一直可用。
通常我們需要在頂級(jí)的組件(Service, Activity, ContentProvider)中使用它,這樣系統(tǒng)才知道你的進(jìn)程應(yīng)該一直被保留。
下面介紹 Binder 的幾個(gè)關(guān)鍵方法:
實(shí)現(xiàn) IBinder
的 transact()
方法:
public final boolean transact(int code, Parcel data, Parcel reply,int flags) throws RemoteException {if (false) Log.v("Binder", "Transact: " + code + " to " + this);if (data != null) {data.setDataPosition(0);}boolean r = onTransact(code, data, reply, flags);if (reply != null) {reply.setDataPosition(0);}return r;
}
可以看到,這個(gè)方法就是調(diào)用 onTransact()
,然后將返回的結(jié)果再返回回去。
接著看看 onTransact()
方法:
protected boolean onTransact(int code, Parcel data, Parcel reply,int flags) throws RemoteException {if (code == INTERFACE_TRANSACTION) { //獲取接口描述reply.writeString(getInterfaceDescriptor());return true;} else if (code == DUMP_TRANSACTION) { //獲取當(dāng)前狀態(tài)ParcelFileDescriptor fd = data.readFileDescriptor();String[] args = data.readStringArray();if (fd != null) {try {dump(fd.getFileDescriptor(), args);} finally {IoUtils.closeQuietly(fd);}}// Write the StrictMode header.if (reply != null) {reply.writeNoException();} else {StrictMode.clearGatheredViolations();}return true;} else if (code == SHELL_COMMAND_TRANSACTION) { //執(zhí)行 shell 腳本ParcelFileDescriptor in = data.readFileDescriptor();ParcelFileDescriptor out = data.readFileDescriptor();ParcelFileDescriptor err = data.readFileDescriptor();String[] args = data.readStringArray();ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);try {if (out != null) {shellCommand(in != null ? in.getFileDescriptor() : null,out.getFileDescriptor(),err != null ? err.getFileDescriptor() : out.getFileDescriptor(),args, resultReceiver);}} finally {IoUtils.closeQuietly(in);IoUtils.closeQuietly(out);IoUtils.closeQuietly(err);// Write the StrictMode header.if (reply != null) {reply.writeNoException();} else {StrictMode.clearGatheredViolations();}}return true;}return false;
}
也沒看出什么特別的,系統(tǒng)的 Binder.onTransact()
方法只定義了系統(tǒng)要進(jìn)行的操作,我們?nèi)绻麆?chuàng)建自己的 Binder 時(shí),就需要重寫這個(gè)方法,根據(jù) code
對(duì)傳入的參數(shù) data
做相應(yīng)的處理,然后寫入 reply
,這樣就能返回操作后的數(shù)據(jù)。
另外一個(gè)關(guān)鍵的方法 attachInterface
:
public void attachInterface(IInterface owner, String descriptor) {mOwner = owner;mDescriptor = descriptor;
}
/* mObject is used by native code, do not remove or rename */
private long mObject;
private IInterface mOwner;
private String mDescriptor;
這個(gè)方法的作用是將一個(gè)描述符、特定的 IInterface
與當(dāng)前 Binder 綁定起來,這樣后續(xù)調(diào)用 queryLocalInterface
就可以拿到這個(gè) IInterface
,那 IInterface
又是什么呢?
public interface IInterface
{/*** Retrieve the Binder object associated with this interface.* You must use this instead of a plain cast, so that proxy objects* can return the correct result.*/public IBinder asBinder();
}
其實(shí)看名字就可以大概猜出來,IInterface
應(yīng)該就是進(jìn)程間通信定義的通用接口,我們通過定義接口,然后再服務(wù)端實(shí)現(xiàn)接口、客戶端調(diào)用接口,就可以實(shí)現(xiàn)跨進(jìn)程通信。
IInterface
里只定義了一個(gè) asBinder()
方法,這個(gè)方法可以返回當(dāng)前接口關(guān)聯(lián)的 Binder 對(duì)象。
Binder 通信機(jī)制
上面介紹了 Binder 類以及相關(guān)的方法,但是這只是 Binder 機(jī)制的最基礎(chǔ)部分。
我們平??吹奈恼禄蛘呙嬖嚂r(shí),說的 Binder 其實(shí)是范圍更大的整個(gè) “Binder 消息通信機(jī)制”。
借用老羅的 Android進(jìn)程間通信(IPC)機(jī)制Binder簡要介紹和學(xué)習(xí)計(jì)劃 中對(duì) Binder 通信機(jī)制的介紹:
在 Android 系統(tǒng)的 Binder 機(jī)制中,由四個(gè)組件組成,分別是:
- Client
- Server
- ServiceManager:提供輔助管理 Server 的功能
- Binder 驅(qū)動(dòng)程序:整個(gè)機(jī)制的核心
Binder 驅(qū)動(dòng)
驅(qū)動(dòng)程序一般指的是設(shè)備驅(qū)動(dòng)程序(Device Driver),是一種可以使計(jì)算機(jī)和設(shè)備通信的特殊程序。相當(dāng)于硬件的接口,操作系統(tǒng)只有通過這個(gè)接口,才能控制硬件設(shè)備的工作。
我們知道,在 Linux 系統(tǒng)中,內(nèi)存空間分為兩部分:
- 用戶空間:運(yùn)行著應(yīng)用程序
- 內(nèi)核空間:運(yùn)行著系統(tǒng)內(nèi)核和驅(qū)動(dòng)
用戶空間中的進(jìn)程無法直接訪問內(nèi)核空間,需要通過上圖中的 System Call Interface (系統(tǒng)調(diào)用接口),通過這個(gè)統(tǒng)一入口,所有資源訪問都是在內(nèi)核的控制下執(zhí)行,這樣可以避免用戶程序?qū)ο到y(tǒng)資源的越權(quán)訪問,從而保障了系統(tǒng)的安全和穩(wěn)定。
同樣的,用戶空間中的進(jìn)程直接也不可以直接訪問數(shù)據(jù),需要通過內(nèi)核空間進(jìn)行中轉(zhuǎn)。
在 Binder 機(jī)制中,由 Binder 驅(qū)動(dòng)負(fù)責(zé)完成這個(gè)中轉(zhuǎn)操作,主要過程如下:
- 當(dāng) Client 向 Server 發(fā)起 IPC 請(qǐng)求時(shí),Client 會(huì)先將請(qǐng)求數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間
- 數(shù)據(jù)被拷貝到內(nèi)核空間之后,驅(qū)動(dòng)程序?qū)?nèi)核空間中的數(shù)據(jù)拷貝到 Server 位于用戶空間的緩存中
這樣,就成功的將 Client 進(jìn)程中的請(qǐng)求數(shù)據(jù)傳遞到了 Server 進(jìn)程中。
實(shí)際上,Binder 驅(qū)動(dòng)是整個(gè) Binder 機(jī)制的核心。除了實(shí)現(xiàn)數(shù)據(jù)傳輸之外,Binder 驅(qū)動(dòng)還是實(shí)現(xiàn)線程控制(通過中斷等待隊(duì)列實(shí)現(xiàn)線程的等待/喚醒),以及 UID/PID 等安全機(jī)制的保證。
http://wangkuiwu.github.io/2014/09/01/Binder-Introduce/
Service Manager
ServiceManager
運(yùn)行在用戶空間,它負(fù)責(zé)管理 Service 注冊(cè)與查詢。
看下 ServiceManager
的代碼:
public final class ServiceManager {private static final String TAG = "ServiceManager";private static IServiceManager sServiceManager;private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();private static IServiceManager getIServiceManager() {if (sServiceManager != null) {return sServiceManager;}// Find the service managersServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());return sServiceManager;}/*** 根據(jù) Service 名稱獲取 Service*/public static IBinder getService(String name) {try {IBinder service = sCache.get(name);if (service != null) {return service;} else {//如果不存在就去 IServiceManager 中找,這時(shí)可能會(huì)阻塞return getIServiceManager().getService(name);}} catch (RemoteException e) {Log.e(TAG, "error in getService", e);}return null;}/*** 添加一個(gè) Service 到 Manager 中*/public static void addService(String name, IBinder service) {try {getIServiceManager().addService(name, service, false);} catch (RemoteException e) {Log.e(TAG, "error in addService", e);}}/*** 添加一個(gè) Service 到 Manager 中,如果 allowIsolated 為 true 表示運(yùn)行在沙盒中的進(jìn)程也可以訪問這個(gè) Service*/public static void addService(String name, IBinder service, boolean allowIsolated) {try {getIServiceManager().addService(name, service, allowIsolated);} catch (RemoteException e) {Log.e(TAG, "error in addService", e);}}/*** Retrieve an existing service called @a name from the* service manager. Non-blocking.*/public static IBinder checkService(String name) {try {IBinder service = sCache.get(name);if (service != null) {return service;} else {return getIServiceManager().checkService(name);}} catch (RemoteException e) {Log.e(TAG, "error in checkService", e);return null;}}/*** 獲取 Service 列表*/public static String[] listServices() {try {return getIServiceManager().listServices();} catch (RemoteException e) {Log.e(TAG, "error in listServices", e);return null;}}/*** 當(dāng)前進(jìn)程首次被 activity manager 創(chuàng)建時(shí)調(diào)用這個(gè)方法 */public static void initServiceCache(Map<String, IBinder> cache) {if (sCache.size() != 0) {throw new IllegalStateException("setServiceCache may only be called once");}sCache.putAll(cache);}
}
可以看到 ServiceManager 提供了 Service 的添加和查詢,其中主要操作都是通過 IServiceManager
,它是何方神圣?
public interface IServiceManager extends IInterface
{/*** 獲取一個(gè) Service,不存在就會(huì)阻塞幾秒*/public IBinder getService(String name) throws RemoteException;/*** 不阻塞的獲取 Service*/public IBinder checkService(String name) throws RemoteException;public void addService(String name, IBinder service, boolean allowIsolated)throws RemoteException;public String[] listServices() throws RemoteException;/*** 為 Service Manager 添加權(quán)限,具體作用暫不追究*/public void setPermissionController(IPermissionController controller)throws RemoteException;static final String descriptor = "android.os.IServiceManager";//定義了一些用于調(diào)用 transact() 方法的 codeint GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;
}
可以看到 IServiceManager
是一個(gè)接口,它定義了管理 Service 的一些方法,同時(shí)繼承了 IInterface
。最常見的實(shí)現(xiàn)是 BnServiceManager.getDefault()
。
Binder 機(jī)制跨進(jìn)程通信流程
上面兩節(jié)簡單介紹了 Binder 機(jī)制中非常重要的兩部分,ServiceManager 和 Binder 驅(qū)動(dòng)。
在 Binder 機(jī)制的四個(gè)部分中, Client、Server 和 ServiceManager 運(yùn)行在用戶空間,Binder 驅(qū)動(dòng)程序運(yùn)行內(nèi)核空間。
Binder 就是一種把這四個(gè)組件粘合在一起的粘結(jié)劑。
這個(gè)流程是如何進(jìn)行的呢?
借用 Android Binder機(jī)制(一) Binder的設(shè)計(jì)和框架 的圖片:
上圖簡單介紹(節(jié)選自 http://wangkuiwu.github.io/2014/09/01/Binder-Introduce/):
- Binder實(shí)體
- Binder 實(shí)體實(shí)際上是內(nèi)核中
binder_node
結(jié)構(gòu)體的對(duì)象,它的作用是在內(nèi)核中保存 Server 和ServiceManager 的信息(例如,Binder 實(shí)體中保存了 Server 對(duì)象在用戶空間的地址) - Binder 實(shí)體是 Server 在 Binder 驅(qū)動(dòng)中的存在形式,內(nèi)核通過 Binder 實(shí)體可以找到用戶空間的Server對(duì)象
- 在上圖中,Server 和 ServiceManager 在 Binder 驅(qū)動(dòng)中都對(duì)應(yīng)的存在一個(gè) Binder 實(shí)體
- Binder 實(shí)體實(shí)際上是內(nèi)核中
- Binder 引用
- Binder引用實(shí)際上是內(nèi)核中
binder_ref
結(jié)構(gòu)體的對(duì)象,是某一個(gè) Binder 實(shí)體的引用,通過Binder 引用可以在內(nèi)核中找到對(duì)應(yīng)的 Binder 實(shí)體 - 如果將 Server 看作是 Binder 實(shí)體的話,那么 Client 就好比 Binder 引用,Client 通過保存一個(gè)Server 對(duì)象的 Binder 引用,再通過該 Binder 引用在內(nèi)核中找到對(duì)應(yīng)的 Binder 實(shí)體,進(jìn)而找到Server 對(duì)象,然后將通信內(nèi)容發(fā)送給 Server 對(duì)象
- Binder引用實(shí)際上是內(nèi)核中
- 遠(yuǎn)程服務(wù)
- 本地服務(wù)的代理,通過調(diào)用遠(yuǎn)程服務(wù)可以間接調(diào)用本地服務(wù)
1.Client、Server 和 ServiceManager 處于用戶空間的不同進(jìn)程。
2.Binder 實(shí)體和 Binder 引用都是內(nèi)核(即 Binder 驅(qū)動(dòng))中的數(shù)據(jù)結(jié)構(gòu)。
它們的關(guān)系如下:
每一個(gè) Server 在內(nèi)核中就表現(xiàn)為一個(gè) Binder 實(shí)體,而每一個(gè) Client 則表現(xiàn)為一個(gè) Binder 引用。這樣,每個(gè) Binder 引用都對(duì)應(yīng)一個(gè) Binder 實(shí)體,而每個(gè) Binder 實(shí)體則可以多個(gè) Binder 引用。
Binder 跨進(jìn)程通訊流程主要為如下 4 步:
- ServiceManager 初始化
- 當(dāng)該應(yīng)用程序啟動(dòng)時(shí),ServiceManager 會(huì)和 Binder 驅(qū)動(dòng)進(jìn)行通信,告訴 Binder 驅(qū)動(dòng)它是服務(wù)管理者
- Binder 驅(qū)動(dòng)新建 ServiceManager 對(duì)應(yīng)的 Binder 實(shí)體
- Server 向 ServiceManager 注冊(cè)自己
- Server 向 Binder 驅(qū)動(dòng)發(fā)起注冊(cè)請(qǐng)求,Binder 為它創(chuàng)建 Binder 實(shí)體
- 然后如果 ServiceManager 中沒有這個(gè) Server 時(shí)就添加 Server 名稱與 Binder 引用到它的 Binder 引用表
- Client 獲取遠(yuǎn)程服務(wù)
- Client 首先會(huì)向 Binder 驅(qū)動(dòng)發(fā)起獲取服務(wù)的請(qǐng)求,傳遞要獲取的服務(wù)名稱
- Binder 驅(qū)動(dòng)將該請(qǐng)求轉(zhuǎn)發(fā)給 ServiceManager 進(jìn)程
- ServiceManager 查找到 Client 需要的 Server 對(duì)應(yīng)的 Binder 實(shí)體的 Binder 引用信息,然后通過 Binder 驅(qū)動(dòng)反饋給 Client
- Client 收到 Server 對(duì)應(yīng)的 Binder 引用后,會(huì)創(chuàng)建一個(gè) Server 對(duì)應(yīng)的遠(yuǎn)程服務(wù)(即 Server 在當(dāng)前進(jìn)程的代理)
- Client 通過代理調(diào)用 Server
- Client 調(diào)用遠(yuǎn)程服務(wù),遠(yuǎn)程服務(wù)收到 Client 請(qǐng)求之后,會(huì)和 Binder 驅(qū)動(dòng)通信
- 因?yàn)檫h(yuǎn)程服務(wù)中有 Server 的 Binder 引用信息,因此驅(qū)動(dòng)就能輕易的找到對(duì)應(yīng)的 Server,進(jìn)而將Client 的請(qǐng)求內(nèi)容發(fā)送 Server
Binder 機(jī)制的優(yōu)點(diǎn)
對(duì)比 Linux 上的其他進(jìn)程通信方式(管道/消息隊(duì)列/共享內(nèi)存/信號(hào)量/Socket),Binder 機(jī)制的優(yōu)點(diǎn)有以下幾點(diǎn):
高效簡單
- 通過驅(qū)動(dòng)在內(nèi)核空間拷貝數(shù)據(jù),不需要額外的同步處理
- 對(duì)比 Socket 等傳輸效率高
安全
- Binder 機(jī)制為每個(gè)進(jìn)程分配了 UID/PID 來作為鑒別身份的標(biāo)示,并且在 Binder 通信時(shí)會(huì)根據(jù)UID/PID 進(jìn)行有效性檢測
Client/Server 架構(gòu)
- 這種架構(gòu)使得通訊更為簡單
總結(jié)
Binder 機(jī)制的學(xué)習(xí)過程是痛苦的 T.T,即使光看 Java 層也費(fèi)了不少功夫,這可能是由于我實(shí)戰(zhàn)中沒有遇到,光看源碼和抽象概念掌握太慢的原因吧。
本文簡單介紹了 Binder 機(jī)制,參考了很多優(yōu)秀的文章,真佩服他們!
借用《Android 開發(fā)藝術(shù)探索》對(duì) Binder 的概括:
- 從代碼角度來看,Binder 是一個(gè)類,實(shí)現(xiàn)了 IBinder 接口;
- 從來源看,Binder 來自于 OpenBinder,是 Android IPC 機(jī)制中的一種,Binder 還可以理解成一個(gè)虛擬物理設(shè)備,設(shè)備驅(qū)動(dòng)是dev/binder;
- 從 Framework 層看,Binder 是 Service Manager 連接各種Manager(ActivityManager,PackageManager…) 和相應(yīng)Service (ActivityManagerService, PackageManagerService…) 的橋梁;
- 從客戶端看,Binder 是客戶端服務(wù)器通訊的媒介
在對(duì) Binder 有了一定理解后,下篇文章我們就去看看 AIDL 幫我們做了什么。
Thanks
《Android 開發(fā)藝術(shù)探索》
https://developer.android.com/reference/android/os/IBinder.html
http://blog.csdn.net/luoshengyang/article/details/6618363
http://blog.csdn.net/luoshengyang/article/details/6642463
http://weishu.me/2016/01/12/binder-index-for-newer/
http://wangkuiwu.github.io/2014/09/01/Binder-Introduce/
http://blog.csdn.net/u010132993/article/details/72582655