講Android Binder機(jī)制
的文章非常多,這篇文章主要是理一下我對(duì)Binder
的理解滨巴。本文不是一篇介紹Binder
的文章,也不是一篇探討Binder
實(shí)現(xiàn)的文章灾常。
本文會(huì)以AndroidStudio
根據(jù)aidl接口
自動(dòng)產(chǎn)生的java文件
來看Binder
,進(jìn)而來理解Binder機(jī)制
。
其實(shí)Android的Binder機(jī)制類似于:RPC(遠(yuǎn)程過程調(diào)用)发魄。如果你理解它盹牧,相信
Binder
機(jī)制就更容易理解了。
首先我們使用AndroidStudio
來定義一個(gè)aidl
接口:
interface IUserManager {
int getUserAge(in String userName);
}
然后我們來直接看一個(gè)由AndroidStudio
根據(jù)自定義的aidl
接口IUserManager
產(chǎn)生的IUserManager.java
文件励幼。
這個(gè)文件我們來分3個(gè)部分看:
IUserManager接口結(jié)構(gòu)
public interface IUserManager extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.susion.demo.aidl.IUserManager {..}
public int getUserAge(java.lang.String userName) throws android.os.RemoteException;
}
這個(gè)接口的結(jié)構(gòu)還是很簡單的:
- 它繼承自
android.os.IInterface
汰寓。 - 定義了一個(gè)待實(shí)現(xiàn)的方法
int getUserAge()
- 定義了一個(gè)
Stub
類。這個(gè)類繼承自Binder
苹粟,并實(shí)現(xiàn)了IUserManager
接口有滑。
int getUserAge()
這個(gè)方法就是我們IUserManager接口
的方法。而android.os.IInterface
是什么呢嵌削?先看一下它在源碼中的定義:
/**
* Base class for Binder interfaces. When defining a new interface,
* you must derive it from 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(); //IBinder是Binder的抽象接口
}
即他是所有Binder
都要實(shí)現(xiàn)的接口, 為什么呢毛好?舉一個(gè)我們都熟悉的場(chǎng)景 :
比如ApplicationThread
,ActivityManagerService
(運(yùn)行在服務(wù)端進(jìn)程)就可以通過它來調(diào)用我們客戶端的方法苛秕。我們會(huì)把這些方法抽象為一個(gè)接口(IApplicationThread
)肌访,這個(gè)接口可以理解為我們告訴服務(wù)端,你可以對(duì)客戶端執(zhí)行哪些操作想帅。
我們還知道ApplicationThread
其實(shí)他就是一個(gè)Binder
场靴。所以這兩者一結(jié)合就可以這么說ApplicationThread
: 客戶端提供給服務(wù)端一個(gè)Binder
,通過這個(gè)Binder
服務(wù)端可以對(duì)客戶端做一些操作,這些操作具體定義在IApplicationThread
接口中啡莉。
我們稱IApplicationThread
為ApplicationThread
這個(gè)Binder
的功能港准。 所以Binder
除了可以理解為系統(tǒng)給我們提供的一個(gè)跨進(jìn)程通信的對(duì)象。 我們?cè)谟?code>Binder通信時(shí)咧欣,還可以說Binder
是一個(gè)具有某些功能的一個(gè)對(duì)象浅缸。
那么怎么表示Binder
有功能呢? 即要繼承IInterface
魄咕。IInterface
可以表示Binder
有功能衩椒, 不然你想一個(gè),那么多Binder
都只實(shí)現(xiàn)自己的接口, 那么系統(tǒng)層就不好操作了哮兰,它總不能向下強(qiáng)轉(zhuǎn)為Binder
吧毛萌,所以Android定義了一個(gè)更高層級(jí)的接口IInterface
。描述Binder
功能的接口必須繼承自這個(gè)接口喝滞。
重點(diǎn): Binder阁将、Binder的功能(IApplicationThread)、IInterface它們都在同一個(gè)對(duì)象上 -> ApplicationThread
Stub
它是IUserManager
的內(nèi)部靜態(tài)類右遭,看一下它的具體聲明:
static abstract class Stub extends android.os.Binder implements com.susion.demo.aidl.IUserManager
即它是一個(gè)Binder
,可以用來跨進(jìn)程通信做盅。它具有IUserManager
定義的功能缤削。
看一下它的具體結(jié)構(gòu):
public static abstract class Stub extends android.os.Binder implements com.susion.demo.aidl.IUserManager {
private static final java.lang.String DESCRIPTOR = "com.susion.demo.aidl.IUserManager";
static final int TRANSACTION_userCount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static com.susion.demo.aidl.IUserManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.susion.demo.aidl.IUserManager))) {
return ((com.susion.demo.aidl.IUserManager) iin);
}
return new com.susion.demo.aidl.IUserManager.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {retun this;}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {...}
private static class Proxy implements com.susion.demo.aidl.IUserManager {...}
}
我們還是一個(gè)一個(gè)的看一下:
DESCRIPTOR
基于我們前面的解釋,我們知道在跨進(jìn)程通信中Binder
對(duì)象具有某種功能->IInterface
吹榴。但是Binder
通信機(jī)制中那么多Binder
都有IInterface
亭敢。那么系統(tǒng)怎么識(shí)別哪個(gè)Binder
是哪個(gè)Binder
呢?所以IInterface
只是一個(gè)能力的抽象图筹,DESCRIPTOR
就是來表示具體是哪一個(gè)功能IInterface
帅刀。
TRANSACTION_userCount
即功能下的哪個(gè)操作。
Stub構(gòu)造函數(shù)
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
即一個(gè)Stub
(Binder
)在構(gòu)造的時(shí)候远剩,就標(biāo)識(shí)好了自己的具體功能IInterface(IUserManager)
劝篷。來看一下attachInterface(this, DESCRIPTOR)
做了什么:
//Binder.java
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
即,Binder在內(nèi)部會(huì)用IInterface
來保存自己的功能民宿。和這個(gè)功能更對(duì)應(yīng)的唯一描述descriptor
,方便在通信的時(shí)候?qū)ふ摇?/p>
asBinder()
自己返回自己娇妓,因?yàn)樽约罕旧砭褪莻€(gè)Binder
呀。
onTransact()
當(dāng)其他進(jìn)程想跨進(jìn)程調(diào)用我這個(gè)Binder
的功能時(shí)活鹰,必須通過這個(gè)方法來溝通哈恰。這個(gè)方法我們最后再來看。
asInterface(android.os.IBinder obj)
即接收一個(gè)IBinder
(這個(gè)IBinder是系統(tǒng)傳入的), 把這個(gè)IBinder
轉(zhuǎn)化為它所具有功能接口志群。其實(shí)這里就是Binder
跨進(jìn)程通信的一個(gè)核心 着绷。那怎么轉(zhuǎn)化的呢?
- 調(diào)用者和Binder對(duì)象位于同一個(gè)進(jìn)程
那么系統(tǒng)就會(huì)直接傳給你在這個(gè)進(jìn)程創(chuàng)建的Stub
(Binder)锌云。所以 obj.queryLocalInterface(DESCRIPTOR)
:
public IInterface queryLocalInterface(String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
即如果參數(shù)descriptor
和這個(gè)Binder的功能唯一描述相同
荠医。就會(huì)返回Binder
的功能mOwner
。
- 調(diào)用者和Binder對(duì)象不在同一個(gè)進(jìn)程
這時(shí)系統(tǒng)實(shí)際傳的是一個(gè)BinderProxy
, 你可以理解為它是另一個(gè)進(jìn)程中的Binder
的替身桑涎。我們就可以把它當(dāng)成另一個(gè)進(jìn)程的Binder
彬向。我們看一下BinderProxy
的queryLocalInterface()
方法:
/**
* Retrieve a local interface - always null in case of a proxy
*/
public IInterface queryLocalInterface(String descriptor) {
return null;
}
所以此時(shí)asInterface()
返回的是: IUserManager.Stub.Proxy(obj)
, 即代理對(duì)象,它代理了BinderProxy
攻冷。
IUserManager.Stub.Proxy
它是Stub
的靜態(tài)內(nèi)部類,如果調(diào)用者和Binder
不在同一個(gè)進(jìn)程的話娃胆,調(diào)用者拿到的實(shí)際是它:
private static class Proxy implements com.didi.virtualapk.demo.aidl.IUserManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int getUserAge(java.lang.String userName) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(userName);
mRemote.transact(Stub.TRANSACTION_getUserAge, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
我們前面說了它其實(shí)是BinderProxy
的代理。為什么要對(duì)BinderProxy
加這個(gè)代理呢等曼?看一下getUserAge()
:
public int getUserAge(java.lang.String userName) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(userName);
mRemote.transact(Stub.TRANSACTION_getUserAge, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
即是調(diào)用mRemote.transact()
(BinderProxy的)方法里烦。Stub.TRANSACTION_getUserAge
是要調(diào)用的遠(yuǎn)程Binder
方法的getUserAge()
對(duì)應(yīng)的描述符。
_data
是序列化后的入?yún)ⅰ?code>_reply是序列化后的返回值禁谦⌒埠冢可以看到_data
所攜帶的參數(shù)是需要序列化的,_reply
所帶的內(nèi)容是被序列化的州泊,所以讀取要反序列化丧蘸。
所以IUserManager.Stub.Proxy
類的作用就是在跨進(jìn)程調(diào)用時(shí)對(duì)傳給mRemote(BinderProxy)
的參數(shù)做序列化,對(duì)mRemote(BinderProxy)
返回值做反序列化拥诡。參數(shù)的接受者和返回者是BinderProxy
具體調(diào)用Binder
的能力是使用BinderProxy
的transact()
方法,它是跨進(jìn)程通信的核心 , 我們來看一下這個(gè)方法:
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
...
return transactNative(code, data, reply, flags); // native 方法
}
省略了不重要的代碼触趴。即BinderProxy
是通過transactNative
來與遠(yuǎn)程Binder
跨進(jìn)程通信的氮发。具體怎么實(shí)現(xiàn),這里就不追究了冗懦。
Stub.onTransact()
我們前面沒有看這個(gè)方法爽冕,這里我們來看一下:
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getUserAge: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
int _result = this.getUserAge(_arg0);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
根據(jù)IUserManager.Stub.Proxy
我們知道,如果不在同一個(gè)進(jìn)程披蕉,那么參數(shù)是被序列化后傳過來的颈畸,所以這個(gè)方法是用來對(duì)入?yún)⒆龇葱蛄谢?duì)返回值做序列化的没讲。
最后我們用一張圖來總結(jié)Binder進(jìn)程通信機(jī)制
:
歡迎關(guān)注我的Android進(jìn)階計(jì)劃看更多干貨
參考: