Android開發之漫漫長途 Ⅷ——Android Binder(也許是最容易理解的)
該文章是一個系列文章,是本人在Android開發的漫漫長途上的一點感想和記錄,我會盡量按照先易後難的順序進行編寫該系列。該系列引用了《Android開發藝術探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相關知識,另外也借鑒了其他的優質博客,在此向各位大神表示感謝,膜拜!!!另外,本系列文章知識可能需要有一定Android開發基礎和項目經驗的同學才能更好理解,也就是說該系列文章面向的是Android中高級開發工程師。
前言
我們在上一篇中比較詳盡的介紹了Android的消息機制,不過有一些內容我們在不理解Android Binder的話是無法講解清楚的。對於初學Android的朋友而言,最難卻又最想掌握的恐怕就是Binder機制了,因為Android系統基本上可以看作是一個基於Binder通信的C/S架構。 Binder就像網絡一樣,把系統的各個部分連接在了一起,因此它是非常重要的。我們下面會Android Binder機制進行從上到下從易到難的分層次講解,從而既能讓初學者對Binder有一定認識,也能讓有一定Android基礎的人獲得收獲。
註:下文中的源碼均出自android-6.0.0_r5
Binder概述
對於初學者來說,深入Android Binder機制是非常不明智的。Android Binder機制大都涉及Java層、Native層、驅動層這三三個方面,對於初學者來說想啃這三塊硬骨頭很容易磕著牙。我們這這一節概述從以下幾個方面讓你從比較宏觀的角度理解Android Binder。
進程
在該系列博客中的第一章我們就說起了Android進程相關問題,Android故意弱化了進程的概念,而用相對容易理解的四大組件。可是我們在稍微深入Android的時候,那麽進程是繞不過的。默認情況下,同一個應用程序中的所有組件運行在同一個進程中,而且絕大多數的應用程序也都是這樣的。這個默認進程是用這個應用的包名來命名的。
進程間通信
我們在運行App的時候經常需要使用一些系統服務,比如剪切板服務,而剪切板服務是運行在SystemServer進程中的。那我們的App是怎麽使用剪切板服務的呢,我們都知道進程是相互獨立的,靜態變量等等都無法共用。這就涉及到進程間的通信了,即IPC。我們都知道Android是基於Linux內核的,那我們簡單介紹下Linux下的幾種IPC機制。
管道(Pipe)
管道是由內核管理的一個緩沖區,相當於我們放入內存中的一個紙條。管道的一端連接一個進程的輸出。這個進程會向管道中放入信息。管道的另一端連接一個進程的輸入,這個進程取出被放入管道的信息。
- 管道是半雙工的,數據只能向一個方向流動;需要雙方通信時,需要建立起兩個管道
- 只能用於父子進程或者兄弟進程之間(具有親緣關系的進程)。比如fork或exec創建的新進程,在使用exec創建新進程時,需要將管道的文件描述符作為參數傳遞給exec創建的新進程。當父進程與使用fork創建的子進程直接通信時,發送數據的進程關閉讀端,接受數據的進程關閉寫端。
- 管道只能在本地計算機中使用,而不可用於網絡間的通信。
命名管道(FIFO)
命名管道是一種特殊類型的文件,它在系統中以文件形式存在。這樣克服了管道的弊端,他可以允許沒有親緣關系的進程間通信。
共享內存(Share Memory)
共享內存是在多個進程之間共享內存區域的一種進程間的通信方式,由IPC為進程創建的一個特殊地址範圍,它將出現在該進程的地址空間中。其他進程可以將同一段共享內存連接到自己的地址空間中。所有進程都可以訪問共享內存中的地址,如果一個進程向共享內存中寫入了數據,所做的改動將立刻被其他進程看到。
- 共享內存是IPC最快捷的方式,共享內存方式直接將某段內存段進行映射,多個進程間的共享內存是同一塊的物理空間,僅僅映射到各進程的地址不同而已,因此不需要進行復制,可以直接使用此段空間。
共享內存本身並沒有同步機制,需要程序員自己控制。
內存映射(Memory Map)
內存映射是由一個文件到一塊內存的映射,在此之後進程操作文件,就像操作進程空間裏的內存地址一樣了。
套接字(Socket)
套接字機制不但可以單機的不同進程通信,而且使得跨網機器間進程可以通信。
套接字的創建和使用與管道是有區別的,套接字明確地將客戶端與服務器區分開來,可以實現多個客戶端連到同一服務器。
Binder
作為Android系統下的一種IPC機制,其本質上與上面羅列出的IPC機制並無本質上的不同,都是作為進程間通信的一種手段。並且在Android系統中也不是只存在Binder這一種進程間通信的方式,在有些地方也使用了Socket。既然Linux已經提供了眾多IPC機制,那麽Android 為何還要使用Binder作為主要的進程間通信的方式呢,那麽當然有他的優點存在。
- 采用C/S的通信模式。而在linux通信機制中,目前只有socket支持C/S的通信模式,但socket有其劣勢,具體參看第二條。
- 有更好的傳輸性能。對比於Linux的通信機制,socket:是一個通用接口,導致其傳輸效率低,開銷大;管道和消息隊列:因為采用存儲轉發方式,所以至少需要拷貝2次數據,效率低;共享內存:雖然在傳輸時沒有拷貝數據,但其控制機制復雜(比如跨進程通信時,需獲取對方進程的pid,得多種機制協同操作)。
- 安全性更高。Linux的IPC機制在本身的實現中,並沒有安全措施,得依賴上層協議來進行安全控制。而Binder機制的UID/PID是由Binder機制本身在內核空間添加身份標識,安全性高;並且Binder可以建立私有通道,這是linux的通信機制所無法實現的(Linux訪問的接入點是開放的)。
- 對用戶來說,通過binder屏蔽了client的調用server的隔閡,client端函數的名字、參數和返回值和server的方法一模一樣,對用戶來說猶如就在本地(也可以做得不一樣),這樣的體驗或許其他ipc方式也可以實現,但binder出生那天就是為此而生。
Java層Binder
Java層Binder的功能,依賴於Native層Binder來實現,可以認為Java層Binder架構是Native層Binder架構的一個鏡像。但是這並不影響我們分析Android Java層Binder的功能。我們用一個例子來說明這個過程。
我們在第一篇中就講解了SystemServer這個進程,這個進程和zygote進程一起撐起了Android 世界,他們之中有一個崩潰,Android世界就會砰然倒塌。Android許多的重要的系統服務如AMS、PMS等都運行在SystemServer進程中。但是還有一個比較重要的進程ServiceManager進程(簡稱SM)跟zygote是兄弟進程。這個進程的作用是用來統一管理服務,如AMS。它們之間的關系如下。
我們的AMS需要向SM進程中註冊信息,其他進程如果想使用AMS,那麽先和ServiceManager進程進行通信查詢,接著再和AMS所在SystemServer進程通信。這部分關系圖如下
我們這裏僅上圖分析①②③中的一條道路,我們來分析③,即我們的應用進程(Client)如何與服務進程(Server)交互。
Java層的Binder,我們來看涉及的類的結構圖
[IBinder.java]
public interface IBinder {
//交互函數
public boolean transact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException;
}
我們接著來看Binder和BinderProxy 他們都聲明在Binder.java中
[Binder.java]
/**
Binder類
*/
public class Binder implements IBinder {
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
......
//這裏調用了onTransact函數進行處理,一般情況下這個函數都會被它的子類重寫
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
}
/**
BinderProxy類
*/
final class BinderProxy implements IBinder {
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//直接以JNI的方式調用Native層的transact函數
return transactNative(code, data, reply, flags);
}
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
}
通用的IPC流程如下
現在假設下面一個場景,我們的應用進程即我們的App想要使用ActivityManagerService的startActivity函數(這種場景肯定有的,當我們拿到手機的時候,手機已經預裝了許多App,其中Launcher App(桌面管理App)是在Android系統啟動完成之後啟動的第一個App,我們安裝好一個應用後,點擊應用圖標即發出Intent,想要啟動另一個App中的Activity,我們在AndroidManifest.xml中註冊了Main Activity)。Launcher App所在的進程要與AMS所在的進程SystemServer進程交互。
我們來看這個例子。按照上面的通用流程我們猜測Launcher進程與SystemServer進程交互過程也如上圖所示,那麽按照這個思路我們來看。分為3點:
是否存在業務函數的統一聲明?
這一部分是我們的上圖中的test函數所聲明的類或者接口,我們的Client端代理和Server端服務都要實現這個函數。果然有
[IActivityManager.java]
public interface IActivityManager extends IInterface {
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
......
}
這裏聲明了我們將要調用的業務函數startActivity,那麽接著第二點
是否存在Server端服務代理?
ActivityManagerProxy是在ActivityManagerNative.java中聲明的內部類
class ActivityManagerProxy implements IActivityManager
{
public ActivityManagerProxy(IBinder remote)
{
mRemote = remote;
}
public IBinder asBinder()
{
return mRemote;
}
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
//看這裏果然是通過mRemote.transact函數,這裏的mRemote是BinderProxy類,關於這一點我們在Native層分析的時候再給出
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
......
}
是否存在Server端服務
ActivityManagerNative是繼承於Binder的抽象類,並重寫了onTransact方法
public abstract class ActivityManagerNative extends Binder implements IActivityManager{
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
//根據code處理相應的業務邏輯,我們這裏是START_ACTIVITY_TRANSACTION
switch (code) {
case START_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String callingPackage = data.readString();
Intent intent = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
IBinder resultTo = data.readStrongBinder();
String resultWho = data.readString();
int requestCode = data.readInt();
int startFlags = data.readInt();
ProfilerInfo profilerInfo = data.readInt() != 0
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
Bundle options = data.readInt() != 0
? Bundle.CREATOR.createFromParcel(data) : null;
int result = startActivity(app, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
reply.writeNoException();
reply.writeInt(result);
return true;
}
}
}
既然ActivityManagerNative是個抽象類,那麽誰真正實現了呢
[ActivityManagerService.java]
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
//重寫了onTransact函數
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
......
try {
//調用父類即ActivityManagerNative的onTransact函數
return super.onTransact(code, data, reply, flags);
} catch (RuntimeException e) {
throw e;
}
}
}
Launcher進程與SystemServer進程交互過程如下
本節小結
關於Java層的Binder機制,我們只需要理解以BinderProxy代表的代理端和Binder代表的服務端的概念即可,例如我們本例中的AMS,AMS是運行在SystemServer進程中的服務端,它間接繼承於Binder,在得到相關請求後,會調用AMS重寫的onTransact函數進行邏輯處理。那麽這個請求就是是AMS的客戶端ActivityManagerProxy通過Binder的方式發給它的,ActivityManagerProxy發送這個請求的方式,是通過調用其內部的成員變量mRemote,這個mRemote其實是BinderProxy的對象,然後BinderProxy通過JNI調用Native層對應函數,最終通過Binder驅動達到與SystemServer交互的目的。
那麽還遺留下以下幾個問題:
1. 服務器端的代理怎麽獲得的
2. 位於代理類中的mRemote這個變量
要想理解好上面的個問題,我們必須向Native層進軍。
Native層Binder
我們依然以AMS分析,我們先來想一下我們在用戶進程中即我們的App中想使用AMS或者其他剪切板之類的系統服務函數了怎麽辦??按照上面的分析我們要獲得AMS的代理ActivityManagerProxy
[ActivityManagerNative.java]
//這裏我們的App進程從SM進程得到AMS服務對應的客戶端代理BinderProxy
IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
//以BinderProxy為參數得到我們ActivityManagerProxy,並把BinderProxy對象存儲在mRemote變量中
IActivityManager am = asInterface(b);
return am;
到這裏我們就有以下問題,本小節分析1,2
1. 既然可以通過SM獲得對應的客戶端代理,那麽AMS必定已經註冊在SM中了,那麽怎麽註冊的呢?
2. AMS代理是如何獲得的?
3. AMS代理是如何與Binder通信的?
我們來一一分析,在分析問題之前我們先做一個假設,這個假設至關重要,那就是不管我們的SystemServer進程與SM進程交互也好還是我們的App進程與SM進程也好,SM的代理已經事先創建完畢,即不管我們在SystemServer端還是App端,在與SM進程交互的時候不用考慮代理怎麽獲得的。為什麽會有如此假設,因為我自己深受其害,由於上述三個過程均是通過Binder,很容易陷入思維混亂。
AMS是如何註冊的?
我們SystemServer進程中的AMS通過"Socket"與SM進程交互,並把自己註冊在SM中
SystemServer創建出ActivityManagerService後,最終將調用其setSystemProcess方法:
[SystemServer.java]
public void setSystemProcess() {
try {
//註冊服務,第二個參數為this,這裏通過“socket”與SM交互
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
..........
} catch (PackageManager.NameNotFoundException e) {
........
}
}
上面的請求最終是通過SM服務代理發送的()
[ServiceManagerNative.java]
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException {
//將數據打包寫入Parcel對象
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
//註意這個地方,後文分析,此時的service為ActivityManagerService
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
//調用BindProxy的transact函數
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
上面的過程已經分析過了, 這裏我們主要看一下哪個對應的native層的transact函數
[android_ util_Binder.cpp]
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags)
{
........
//將java對象轉化為native對象
Parcel* data = parcelForJavaObject(env, dataObj);
.........
Parcel* reply = parcelForJavaObject(env, replyObj);
........
//得到native層的BpBinder
IBinder* target = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
........
//通過BpBinder利用IPCThreadState,將請求通過Binder驅動發送給SM進程
status_t err = target->transact(code, *data, reply, flags);
........
}
SM進程收到信息後便處理這個消息(這個說法並不準確,準確的說法是,SM進程中主線程一直在與binder設備交互,想必讀者也猜到了for(;;)),有消息時便通過預先定義好的函數進行處理
[service_manager.c]
switch(txn->code) {
case SVC_MGR_ADD_SERVICE:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
handle = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
//do_add_service
if (do_add_service(bs, s, len, handle, txn->sender_euid,
allow_isolated, txn->sender_pid))
return -1;
break;
}
int do_add_service(struct binder_state *bs,
const uint16_t *s, size_t len,
uint32_t handle, uid_t uid, int allow_isolated,
pid_t spid)
{
//結構體si,用來存儲服務信息
struct svcinfo *si;
//判斷服務有沒有權限註冊,並不是所有的服務都能註冊
if (!svc_can_register(s, len, spid)) {
return -1;
}
//查詢服務有沒有註冊過
si = find_svc(s, len);
if (si) {//已經註冊過
if (si->handle) {
ALOGE("add_service(‘%s‘,%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
str8(s, len), handle, uid);
svcinfo_death(bs, si);
}
si->handle = handle;
} else {//還沒有註冊過,我們進入這個分支
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) {
ALOGE("add_service(‘%s‘,%x) uid=%d - OUT OF MEMORY\n",
str8(s, len), handle, uid);
return -1;
}
//保存一些handle等信息
si->handle = handle;
si->len = len;
memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
si->name[len] = ‘\0‘;
si->death.func = (void*) svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
si->next = svclist;
svclist = si;
}
binder_acquire(bs, handle);
binder_link_to_death(bs, handle, &si->death);
return 0;
}
看到這裏SM貌似只保留了一些AMS的信息而已,實際上並不只是如此,我們來看一下上面的保留問題
[Parcel.java]
data.writeStrongBinder(service);
public final void writeStrongBinder(IBinder val) {
//調用了native函數
nativeWriteStrongBinder(mNativePtr, val);
}
跟進[android_os_Parcel.cpp]
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
//native層的parcel
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
//obj為Binder類
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
//調用了JavaBBinderHolder的get方法
return jbh != NULL ? jbh->get(env, obj) : NULL;
}
//obj為BinderProxy類
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
}
ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}
跟進[Pacel.cpp]
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != NULL) {//binder不為空
IBinder *local = binder->localBinder();//是不是本地binder,本地的意思是同一個進程中的調用
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don‘t pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = 0;
} else {//我們這裏明顯不是
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {//錯誤信息
obj.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
}
return finish_flatten_binder(binder, obj, out);
}
通過上面的代碼,我們可以看到當一個服務進行註冊時,會將Java層的Binder對象和Native層的BBinder關聯起來,於是服務端綁定到了Native層的Binder架構。
此外,addService中打包傳入的其實不是ActivityManagerService本身,而是對應的JavaBBinder對象。
這裏對應的結構如下圖所示:
AMS代理是如何獲得的?
我們上面SystemServer中的AMS已經在SM中準備好了,那我們ServiceManager.getService(Context.ACTIVITY_SERVICE);
一樣的過程,我們知道最終會在service_manager.c中處理
switch(txn->code) {
//這裏有個case穿透,,好吧
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
//查詢AMS保存在SM中對應的的那個handle
handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);
return 0;
}
把寫入數據後的reply返回
bio_put_uint32(reply, 0);
回到我們的調用處
[ServiceManagerNative.java]
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
//看這裏readStrongBinder,是不是感覺跟我們上面的writeStrongBinder感覺是一對的
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
Parcel的readStrongBinder還是個JNI調用
[android_ os_Parcel.cpp]
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
//這裏我們看到了什麽,,看函數名字應該是為Binder生成一個java對象吧
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
我們先看Pacel的readStrongBinder方法
[Parcel.cpp]
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
//看到這裏,還記得writeStrongBinder中的flatten_binder,這裏是unflatten_binder
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
//到這裏我們也清楚了進入這個分支
//調用ProcessState的getStrongProxyForHandle函數
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
繼續跟進[ProcessState.cpp]
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {//這裏handle為0的情況是為SM準備的,
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
//我們的不為0,在這裏創建了BpBinder
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
好了剩下最後一個了javaObjectForIBinder
[android_ util_Binder.cpp]
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) {
if (val == NULL) return NULL;
//如果val是Binder對象,進入下面分支,此時val是BpBinder
if (val->checkSubclass(&gBinderOffsets)) {
// One of our own!
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it‘s our own %p!\n", val.get(), object);
return object;
}
.........
//調用BpBinder的findObject函數
//在Native層的BpBinder中有一個ObjectManager,它用來管理在Native BpBinder上創建的Java BinderProxy對象
//findObject用於判斷gBinderProxyOffsets中,是否存儲了已經被ObjectManager管理的Java BinderProxy對象
jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
if (object != NULL) {
jobject res = jniGetReferent(env, object);
............
//如果該Java BinderProxy已經被管理,則刪除這個舊的BinderProxy
android_atomic_dec(&gNumProxyRefs);
val->detachObject(&gBinderProxyOffsets);
env->DeleteGlobalRef(object);
}
//創建一個新的BinderProxy對象
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL) {
// The proxy holds a reference to the native object.
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
val->incStrong((void*)javaObjectForIBinder);
// The native object needs to hold a weak reference back to the
// proxy, so we can retrieve the same proxy if it is still active.
jobject refObject = env->NewGlobalRef(
env->GetObjectField(object, gBinderProxyOffsets.mSelf));
//新創建的BinderProxy對象註冊到BpBinder的ObjectManager中,同時註冊一個回收函數proxy_cleanup
//當BinderProxy對象detach時,proxy_cleanup函數將被調用,以釋放一些資源
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
// Also remember the death recipients registered on this proxy
sp<DeathRecipientList> drl = new DeathRecipientList;
drl->incStrong((void*)javaObjectForIBinder);
//將死亡通知list和BinderProxy聯系起來
env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));
// Note that a new object reference has been created.
android_atomic_inc(&gNumProxyRefs);
//垃圾回收相關;利用gNumRefsCreated記錄創建出的BinderProxy數量
//當創建出的BinderProxy數量大於200時,該函數將利用BinderInternal的ForceGc函數進行一個垃圾回收
incRefsCreated(env);
return object;
}
}
到這裏總算都打通了總體流程如下
驅動層Binder
還剩下遺留下的兩個問題
AMS代理是如何與Binder通信的?
通過Java層的服務端代理最終調用到BpBinder.transact函數
[BpBinder.cpp]
status_t BpBinder:transact(uint32_t code,const Parcel&data,Parcel*reply,uint32_t flags){
if(mAlive){
//BpBinder把transact工作交給了IPCThreadState。
status_t status=IPCThreadState:self()->transact(
mHandle,code,data,reply,flags);//mHandle也是參數
if(status==DEAD_OBJECT)mAlive=0;
return status;
}
return DEAD_OBJECT;
}
[IPCThreadState.cpp]
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mMyThreadId(gettid()),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0)
{
pthread_setspecific(gTLS, this);
clearCaller();
//mIn和mOut是兩個Parcel。 把它看成是發送和接收命令的緩沖區即可。
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
......
/*
註意這裏的第一個參數BC_TRANSACTION,它是應用程序向binder設備發送消息的消
息碼,而binder設備向應用程序回復消息的消息碼以BR_開頭。 消息碼的定義在
binder_module.h中,請求消息碼和回應消息碼的對應關系,需要查看Binder驅動的實
現才能將其理清楚,我們這裏暫時用不上。
*/
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
......
err = waitForResponse(NULL, NULL);
......
return err;
}
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
//binder_transaction_data是和binder設備通信的數據結構。
binder_transaction_data tr;
//果然,handle的值傳遞給了target,用來標識目的端,其中0是ServiceManager的標誌。
tr.target.handle=handle;
//code是消息碼,是用來switch/case的!
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
tr.offsets_size = 0;
tr.data.ptr.offsets = 0;
} else {
return (mLastError = err);
}
//把命令寫到mOut中,而不是直接發出去,可見這個函數有點名不副實。
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) <NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
//看見沒?這裏開始操作mIn了,看來talkWithDriver中
//把mOut發出去,然後從driver中讀到數據放到mIn中了。
cmd = mIn.readInt32();
}
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
binder_write_read bwr;
//中間東西太復雜了,不就是把mOut數據和mIn接收數據的處理後賦值給bwr嗎?
status_t err;
do {
//用ioctl來讀寫
if (ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
} while (err == -EINTR);
//到這裏,回復數據就在bwr中了,bmr接收回復數據的buffer就是mIn提供的
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
returnNO_ERROR;
}
本篇總結
我們本篇詳細分析了Binder機制,從概述->Java層Binder->Native層Binder->Binder驅動,位於各層次的讀者都能獲得收獲。
下篇預告
不好意思各位,下周有個比較重要的面試,所以暫時不會更新該系列的博客,但是也會更新其他博客。記錄準備面試的過程中需要用到的比較容易錯誤的知識。
此致,敬禮
Android開發之漫漫長途 Ⅷ——Android Binder(也許是最容易理解的)