前言:Binder 是什么?從類的角度來說,它是實現了 IBinder 接口的 Binder 類;從機制角度來說,它是 Android 的 IPC(進程間通信) 機制。
官方文檔:
https://developer.android.google.cn/reference/android/os/Binder
注:本文以 API 30 的 Binder 源碼進行解析。
Binder 與傳統 IPC 對比:
| Binder | 共享內存 | Socket | 管道 | |
|---|---|---|---|---|
| 性能 | 需要拷貝一次 | 無需拷貝 | 需要拷貝兩次 | 需要拷貝兩次 |
| 特點 | 基于 C/S 架構,易用性高 | 控制復雜,易用性差 | 基于 C/S 架構,易用性差 | 易用性差 |
| 安全性 | 為每個 APP 分配 UID,同時支持實名和匿名 | 依賴上層協議,訪問接入點是開放的,不安全 | 依賴上層協議,訪問接入點是開放的,不安全 | 依賴上層協議,訪問接入點是開放的,不安全 |
了解 Binder 源碼之前首先來了解一下 AIDL,因為 APP 主要是通過 AIDL 與 Binder 機制進行通信。
一、AIDL 源碼解析
寫一個 AIDL 接口IMyAidlInterface.aidl:
interface IMyAidlInterface {
void testAidl();
}
Rebuild Project,就會在build文件夾下看到 Android Studio 為我們自動生成的代碼:
// AIDL 繼承自 IInterface,也就是說所有的 AIDL 接口都是 IInterface 的組成類。
public interface IMyAidlInterface extends android.os.IInterface {
...
}
看一下這個自動生成的 AIDL 的組成結構:

首先看Stub:
public static abstract class Stub extends android.os.Binder implements com.tyhoowu.myapplication.IMyAidlInterface
根據源碼可知 Stub 是一個抽象類,這也就是為什么我們在寫服務端的時候需要實現 Stub 類。Stub 繼承自 Binder,實現我們自定義的 AIDL 接口。
再來看Proxy:
private static class Proxy implements com.tyhoowu.myapplication.IMyAidlInterface
根據源碼可知 Proxy 直接就實現了我們自定義的 AIDL 接口。
問:兩個進程要進行通信的話,Stub 和 Proxy 哪個是負責發(fā)送,哪個負責是接收?
答:Proxy 向 Binder 發(fā)送數據,Stub 接收 Binder 發(fā)送過來的數據。
從客戶端發(fā)送到服務端,再從服務端返回的流程
1.定義唯一的類名:
private static final java.lang.String DESCRIPTOR = "com.tyhoowu.myapplication.IMyAidlInterface";
2.通過attachInterface把Stub和DESCRIPTOR傳進去:
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
3.在attachInterface里,把Stub和DESCRIPTOR進行保存:
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
4.asInterface:
public static com.tyhoowu.myapplication.IMyAidlInterface asInterface(android.os.IBinder obj) {
// 判斷 IBinder 是否為 null
if ((obj == null)) {
return null;
}
// 調用 queryLocalInterface
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
// 當前在同一個進程
if (((iin != null) && (iin instanceof com.tyhoowu.myapplication.IMyAidlInterface))) {
return ((com.tyhoowu.myapplication.IMyAidlInterface) iin);
}
// 服務端在本地保存 descriptor,如果客戶端和服務端不在一個進程的話,那么返回的 iin 就為空,那么此時就會 new 一個 Proxy。
return new com.tyhoowu.myapplication.IMyAidlInterface.Stub.Proxy(obj);
}
5.queryLocalInterface:
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
// 將傳入的 descriptor 和 mDescriptor 進行比較,
// 因為兩個應用有可能在同一個進程里面(自己調用自己的服務)
if (mDescriptor != null && mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
6.Proxy:
private android.os.IBinder mRemote;
// 將傳入的 remote 保存到 IBinder
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
7.testAidl
@Override
public void testAidl() throws android.os.RemoteException {
// 通過 “池” obtain 創(chuàng)建了 _data 和 _reply
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
// 校驗
_data.writeInterfaceToken(DESCRIPTOR);
// 發(fā)送到 Binder,然后通知給服務端
// 參數1:int 型,因為通信傳 String 的話會導致包過大,影響性能,客戶端傳一個數,服務端就知道這個數對應的方法。
// 參數2:要處理的數據
// 參數3:接收服務端返回給客戶端的數據
// 參數4:標志位,如果是0,就表示服務端能返回數據,如果是1,就表示服務端不能返回數據。
boolean _status = mRemote.transact(Stub.TRANSACTION_testAidl, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().testAidl();
return;
}
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
8.通過Binder的一系列處理就會調用到onTransact:
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
// 通過 switch (code) 找到對應的方法
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_testAidl: {
// 進行校驗
data.enforceInterface(descriptor);
this.testAidl();
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
二、Binder 源碼解析
創(chuàng)建服務的一種做法是調用bindService,以bindService流程為例來走進Binder。
bindService是Context的抽象方法:
public abstract boolean bindService(@RequiresPermission Intent service, @NonNull ServiceConnection conn, @BindServiceFlags int flags);
根據 Android 基礎,Context 下面有兩個類:
- ContextWrapper
- ContextImpl(Context 的實現類)
所以實際上就是調用ContextImpl的bindService:
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null, getUser());
}
ContextImpl的bindServiceCommon:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// 這塊實際上就是 ServiceConnection,
// 然后會回調 ServiceConnection 的 onServiceConnected,
// 通過 onServiceConnected,進程與服務就進行了綁定。
IServiceConnection sd;
...
try {
...
// 閱讀源碼 ActivityManager.getService() 實際上返回的就是 Proxy
// 閱讀源碼 bindIsolatedService 實際上就是調用 Proxy
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
...
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
A進程訪問B進程時的狀態(tài):
- 進程B有沒有啟動
- 進程B啟動了,但是里面的Service沒創(chuàng)建出來
- 進程B啟動了,里面的Service也創(chuàng)建了,但是Service沒有被綁定過,回調onBind()
- 進程B啟動了,里面的Service也創(chuàng)建了,但是Service已經被綁定過,回調onRebind()
總結
| AIDL 接口 | Stub 抽象類 | Proxy 類 | Stub 的實現類 |
|---|---|---|---|
| IMyAidlInterface | Stub | Proxy | new IMyAidlInterface.Stub |
| IActivityManager | ActivityManagerNative | ActivityManagerProxy | ActivityManagerService |
? 2020 Tyhoo Wu, All rights reserved.