# 第2章 深入理解Java Binder和MessageQueue
本章主要內容:
+ 介紹Binder系統的Java層框架
+ 介紹MessageQueue
本章所涉及的源代碼文件名及位置:
+ IBinder.java
frameworks/base/core/java/android/os/IBinder.java
+ Binder.java
frameworks/base/core/java/android/os/Binder.java
+ BinderInternal.java
frameworks/base/core/java/com/android/intenal/os/BinderInternal.java
+ android_util_Binder.cpp
frameworks/base/core/jni/android_util_Binder.cpp
+ SystemServer.java
frameworks/base/services/java/com/android/servers/SystemServer.java
+ ActivityManagerService.java
frameworks/base/services/java/com/android/servers/ActivityManagerService.java
+ ServiceManager.java
frameworks/base/core/java/android/os/ServiceManager.java
+ ServcieManagerNative.java
frameworks/base/core/java/android/os/ServcieManagerNative.java
+ MessageQueue.java
frameworks/base/core/java/android/os/MessageQueue.java
+ android_os_MessageQueue.cpp
frameworks/base/core/jni/android_os_MessageQueue.cpp
+ Looper.cpp
frameworks/base/native/android/Looper.cpp
+ Looper.h
frameworks/base/include/utils/Looper.h
+ android_app_NativeActivity.cpp
frameworks/base/core/jni/android_app_NativeActivity.cpp
## 2.1 概述
由于本書所介紹的內容主要是以Java層的系統服務為主,因此Binder相關的應用在本書中比比皆是。而MessageQueue作為Android中重要的任務調度工具,它的使用也是隨處可見。所以本書有必要對這兩個工具有所介紹。根據鄧凡平的同意與推薦,本章由卷II第2章升級到4.2.2而來,并且增加了對AIDL相關的知識點的分析。
以本章作為本書Android分析之旅的開篇,將重點關注兩個基礎知識點,它們是:
+ Binder系統在Java世界是如何布局和工作的。
+ MessageQueue的新職責。
先來分析Java層中的Binder。
建議 讀者先閱讀《深入理解Android:卷I》(以下簡稱“卷I”)的第6章“深入理解Binder”。網上有樣章可下載。
## 2.2 Java層中的Binder分析
### 2.2.1 Binder架構總覽
如果讀者讀過卷I第6章“深入理解Binder”,相信就不會對Binder架構中代表Client的Bp端及代表Server的Bn端感到陌生。Java層中Binder實際上也是一個C/S架構,而且其在類的命名上盡量保持與Native層一致,因此可認為,Java層的Binder架構是Native層Binder架構的一個鏡像。Java層的Binder架構中的成員如圖2-1所示。

圖 2 - 1 Java層中的Binder家族
由圖2-1可知:
+ 系統定義了一個IBinder接口類以及DeathRecepient接口。
+ Binder類和BinderProxy類分別實現了IBinder接口。其中Binder類作為服務端的Bn的代表,而BinderProxy作為客戶端的Bp的代表。
+ 系統中還定義一個BinderInternal類。該類是一個僅供Binder框架使用的類。它內部有一個GcWatcher類,該類專門用于處理和Binder相關的垃圾回收。
+ Java層同樣提供一個用于承載通信數據的Parcel類。
注意 IBinder接口類中定義了一個叫FLAG_ONEWAY的整型,該變量的意義非常重要。當客戶端利用Binder機制發起一個跨進程的函數調用時,調用方(即客戶端)一般會阻塞,直到服務端返回結果。這種方式和普通的函數調用是一樣的。但是在調用Binder函數時,在指明了FLAG_ONEWAY標志后,調用方只要把請求發送到Binder驅動即可返回,而不用等待服務端的結果,這就是一種所謂的非阻塞方式。在Native層中,涉及的Binder調用基本都是阻塞的,但是在Java層的framework中,使用FLAG_ONEWAY進行Binder調用的情況非常多,以后經常會碰到。
思考 使用FLAG_ONEWAY進行函數調用的程序在設計上有什么特點?這里簡單分析一下:對于使用FLAG_ONEWAY的函數來說,客戶端僅向服務端發出了請求,但是并不能確定服務端是否處理了該請求。所以,客戶端一般會向服務端注冊一個回調(同樣是跨進程的Binder調用),一旦服務端處理了該請求,就會調用此回調來通知客戶端處理結果。當然,這種回調函數也大多采用FLAG_ONEWAY的方式。
### 2.2.2 初始化Java層Binder框架
雖然Java層Binder系統是Native層Binder系統的一個Mirror,但這個Mirror終歸還需借助Native層Binder系統來開展工作,即Mirror和Native層Binder有著千絲萬縷的關系,一定要在Java層Binder正式工作之前建立這種關系。下面分析Java層Binder框架是如何初始化的。
在Android系統中,在Java初創時期,系統會提前注冊一些JNI函數,其中有一個函數專門負責搭建Java Binder和Native Binder交互關系,該函數是register_android_os_Binder,代碼如下:
```
[android_util_Binder.cpp-->register_android_os_Binder()]
int register_android_os_Binder(JNIEnv* env)
{
??? // 初始化Java Binder類和Native層的關系
??? if(int_register_android_os_Binder(env) < 0)
???????return -1;
??? // 初始化Java BinderInternal類和Native層的關系
??? if(int_register_android_os_BinderInternal(env) < 0)
???????return -1;
??? // 初始化Java BinderProxy類和Native層的關系
??? if(int_register_android_os_BinderProxy(env) < 0)
???????return -1;
??? ......
??? return0;
}
```
據上面的代碼可知,register_android_os_Binder函數完成了Java Binder架構中最重要的3個類的初始化工作。
#### 1\. Binder類的初始化
int_register_android_os_Binder函數完成了Binder類的初始化工作,代碼如下:
```
[android_util_Binder.cpp-->int_register_android_os_Binder()]
static int int_register_android_os_Binder(JNIEnv*env)
{
??? jclassclazz;
???//kBinderPathName為Java層中Binder類的全路徑名,“android/os/Binder“
??? clazz =env->FindClass(kBinderPathName);
??? /*gBinderOffSets是一個靜態類對象,它專門保存Binder類的一些在JNI層中使用的信息,
????? 如成員函數execTranscat的methodID,Binder類中成員mObject的fildID */
???gBinderOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
???gBinderOffsets.mExecTransact
???????????????????? =env->GetMethodID(clazz, "execTransact", "(IIII)Z");
???gBinderOffsets.mObject
???????????????????? =env->GetFieldID(clazz, "mObject", "I");
??? // 注冊Binder類中native函數的實現
??? returnAndroidRuntime::registerNativeMethods(
??????????????????????????? env,kBinderPathName,
??????????????????????????? gBinderMethods,NELEM(gBinderMethods));
}
```
從上面代碼可知,gBinderOffsets對象保存了和Binder類相關的某些在JNI層中使用的信息。它們將用來在JNI層對Java層的Binder對象進行操作。execTransact()函數以及mObject成員的用途將在2.2.3節介紹。
建議 如果讀者對JNI不是很清楚,可參閱卷I第2章“深入理解JNI”。
#### 2\. BinderInternal類的初始化
下一個初始化的類是BinderInternal,其代碼在int_register_android_os_BinderInternal函數中。
```
[android_util_Binder.cpp-->int_register_android_os_BinderInternal()]
static intint_register_android_os_BinderInternal(JNIEnv* env)
{
?? jclassclazz;
?? // 根據BinderInternal的全路徑名找到代表該類的jclass對象。全路徑名為
?? //“com/android/internal/os/BinderInternal”
?? clazz =env->FindClass(kBinderInternalPathName);
??//gBinderInternalOffsets也是一個靜態對象,用來保存BinderInternal類的一些信息
??gBinderInternalOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
?? // 獲取forceBinderGc的methodID
??gBinderInternalOffsets.mForceGc
????????????????= env->GetStaticMethodID(clazz, "forceBinderGc","()V");
?? // 注冊BinderInternal類中native函數的實現
?? returnAndroidRuntime::registerNativeMethods(
???????????????????????? env,kBinderInternalPathName,
????????????????????????gBinderInternalMethods, NELEM(gBinderInternalMethods));
}
```
int_register_android_os_BinderInternal的工作內容和int_register_android_os_Binder的工作內容類似:
+ 獲取一些有用的methodID和fieldID。這表明JNI層一定會向上調用Java層的函數。
+ 注冊相關類中native函數的實現。
#### 3\. BinderProxy類的初始化
int_register_android_os_BinderProxy完成了BinderProxy類的初始化工作,代碼稍顯復雜,如下所示:
```
[android_util_Binder.cpp-->int_register_android_os_BinderProxy()]
static intint_register_android_os_BinderProxy(JNIEnv* env)
{
??? jclassclazz;
??? // **① gWeakReferenceOffsets用來和WeakReference類打交道**
??? clazz =env->FindClass("java/lang/ref/WeakReference");
???gWeakReferenceOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
??? // 獲取WeakReference類get函數的MethodID
???gWeakReferenceOffsets.mGet= env->GetMethodID(clazz, "get",
???????????????????????????????????"()Ljava/lang/Object;");
??? // **② gErrorOffsets用來和Error類打交道**
??? clazz =env->FindClass("java/lang/Error");
???gErrorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
??? // **③ gBinderProxyOffsets用來和BinderProxy類打交道**
??? clazz =env->FindClass(kBinderProxyPathName);
???gBinderProxyOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
???gBinderProxyOffsets.mConstructor= env->GetMethodID(clazz,"<init>", "()V");
??? ......//獲取BinderProxy的一些信息
??? // **④ gClassOffsets用來和Class類打交道**
??? clazz =env->FindClass("java/lang/Class");
???gClassOffsets.mGetName =env->GetMethodID(clazz,
??????? ??????????????????????"getName","()Ljava/lang/String;");
??? // 注冊BinderProxy native函數的實現
??? returnAndroidRuntime::registerNativeMethods(env,
?????????kBinderProxyPathName,gBinderProxyMethods,
???????????????????????????????NELEM(gBinderProxyMethods));
}
```
據上面代碼可知,int_register_android_os_BinderProxy函數除了初始化BinderProxy類外,還獲取了WeakReference類和Error類的一些信息。看來BinderProxy對象的生命周期會委托WeakReference來管理,難怪JNI層會獲取該類get函數的MethodID。
至此,Java Binder幾個重要成員的初始化已完成,同時在代碼中定義了幾個全局靜態對象,分別是gBinderOffsets、gBinderInternalOffsets和gBinderProxyOffsets。
框架的初始化其實就是提前獲取一些JNI層的使用信息,如類成員函數的MethodID,類成員變量的fieldID等。這項工作是必需的,因為它能節省每次使用時獲取這些信息的時間。當Binder調用頻繁時,這些時間累積起來還是不容小覷的。
另外,這個過程中所創建的幾個全局靜態對象為JNI層訪問Java層的對象提供了依據。而在每個初始化函數中所執行的registerNativeMethods()方法則為Java層訪問JNI層打通了道路。換句話說,Binder初始化的工作就是通過JNI建立起Native Binder與Java Binder之間互相通信的橋梁。
下面通過一個例子來分析Java Binder的工作流程。
### 2.2.3 窺一斑,可見全豹乎
這個例子源自ActivityManagerService,我們試圖通過它揭示Java層Binder的工作原理。先來描述一下該例子的分析步驟:
+ 首先分析AMS如何將自己注冊到ServiceManager。
+ 然后分析AMS如何響應客戶端的Binder調用請求。
本例的起點是setSystemProcess,其代碼如下所示:
```
[ActivityManagerService.java-->ActivityManagerService.setSystemProcess()]
public static void setSystemProcess() {
?? try {
??????ActivityManagerService m = mSelf;
?????? // 將ActivityManagerService服務注冊到ServiceManager中
??????ServiceManager.addService("activity", m);......
?? } catch {... }
?? return;
}
```
上面所示代碼行的目的是將ActivityManagerService服務(以后簡稱AMS)加到ServiceManager中。
在整個Android系統中有一個Native的ServiceManager(以后簡稱SM)進程,它統籌管理Android系統上的所有Service。成為一個Service的首要條件是先在SM中注冊。下面來看Java層的Service是如何向SM注冊的。
#### 1\. 向ServiceManager注冊服務
##### (1)創建ServiceManagerProxy
向SM注冊服務的函數叫addService,其代碼如下:
```
[ServiceManager.java-->ServiceManager.addService()]
public static void addService(String name, IBinderservice) {
??? try {
??????? //getIServiceManager返回什么
???????getIServiceManager().addService(name, service);
??? }
??? ......
}
```
首先需要搞清楚getIServiceManager()方法返回的是一個什么對象呢?參考其實現:
```
[ServiceManager.java-->ServiceManager.getIServiceManager()]
private static IServiceManagergetIServiceManager() {
??? ......
??? // 調用asInterface,傳遞的參數類型為IBinder???????
???sServiceManager = ServiceManagerNative.asInterface(
???????????????????????BinderInternal.getContextObject());
??? returnsServiceManager;
}
```
asInterface()方法的參數為BinderInternal.getContextObject()的返回值。于是這個簡短的方法中有兩個內容值得討論:BinderInternal.getContextObject()以及asInterface()。
BinderInternal.getContextObject()方法是一個native的函數,參考其實現:
```
[android_util_Binder.cpp-->android_os_BinderInternal_getContextObject()]
static jobjectandroid_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
??? /* 下面這句代碼在卷I第6章詳細分析過,它將返回一個BpProxy對象,其中
????? NULL(即0,用于標識目的端)指定Proxy通信的目的端是ServiceManager*/
???sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
??? // 由Native對象創建一個Java對象,下面分析該函數
??? returnjavaObjectForIBinder(env, b);
}
```
可見,Java層的ServiceManager需要在Native層獲取指向Native進程中ServiceManager的BpProxy。這個BpProxy不能由Java層的ServiceManager直接使用,于是android_os_BinderInteral_getContextObject()函數通過javaObjectForIBinder()函數將創建一個封裝了這個BpProxy的一個Java對象并返回給調用者。ServiceManager便可一通過這個Java對象實現對BpProxy的訪問。參考這個Java對象的創建過程:
```
[android_util_Binder.cpp-->javaObjectForIBinder()]
jobject javaObjectForIBinder(JNIEnv* env, constsp<IBinder>& val)
{
??? //mProxyLock是一個全局的靜態CMutex對象
???AutoMutex _l(mProxyLock);
??? /* val對象實際類型是BpBinder,讀者可自行分析BpBinder.cpp中的findObject函數。
????? 事實上,在Native層的BpBinder中有一個ObjectManager,它用來管理在Native BpBinder
????? 上創建的Java BpBinder對象。下面這個findObject用來判斷gBinderProxyOffsets
????? 是否已經保存在ObjectManager中。如果是,那就需要刪除這個舊的object */
??? jobjectobject = (jobject)val->findObject(&gBinderProxyOffsets);
??? if(object != NULL) {
???????jobject res = env->CallObjectMethod(object,gWeakReferenceOffsets.mGet);
???????android_atomic_dec(&gNumProxyRefs);
???????val->detachObject(&gBinderProxyOffsets);
???????env->DeleteGlobalRef(object);
??? }
??? // **① 創建一個新的BinderProxy對象。**并將它注冊到Native BpBinder對象的ObjectManager中
??? object =env->NewObject(gBinderProxyOffsets.mClass,
???????????????????????????gBinderProxyOffsets.mConstructor);
??? if(object != NULL) {
??????? /* ② 把Native層的BpProxy的指針保存到BinderProxy對象的成員字段mObject中。
????????? 于是BinderProxy對象的Native方法可以通過mObject獲取BpProxy對象的指針。
????????? 這個操作是將BinderProxy與BpProxy聯系起來的紐帶 */
???????env->SetIntField(object, gBinderProxyOffsets.mObject,(int)val.get());
???????val->incStrong(object);
???????jobject refObject = env->NewGlobalRef(
???????????????env->GetObjectField(object, gBinderProxyOffsets.mSelf));
??????? /* 將這個新創建的BinderProxy對象注冊(attach)到BpBinder的ObjectManager中,
????????? 同時注冊一個回收函數proxy_cleanup。當BinderProxy對象撤銷(detach)的時候,
????????? 該函數會被調用,以釋放一些資源。讀者可自行研究proxy_cleanup函數*/
???????val->attachObject(&gBinderProxyOffsets, refObject,
?????????????????????????????jnienv_to_javavm(env), proxy_cleanup);
??????? //DeathRecipientList保存了一個用于死亡通知的list
???????sp<DeathRecipientList> drl = new DeathRecipientList;
???????drl->incStrong((void*)javaObjectForIBinder);
??????? //將死亡通知list和BinderProxy對象聯系起來
???????env->SetIntField(object, gBinderProxyOffsets.mOrgue,
????????????????????????????reinterpret_cast<jint>(drl.get()));
??????? // 增加該Proxy對象的引用計數
???????android_atomic_inc(&gNumProxyRefs);
??????? /*下面這個函數用于垃圾回收。創建的Proxy對象一旦超過200個,該函數
????????? 將調用BinderInter類的ForceGc做一次垃圾回收 */
???????incRefsCreated(env);
??? }
??? returnobject;
}
```
BinderInternal.getContextObject的代碼有點多,簡單整理一下,可知該函數完成了以下兩個工作:
+ 創建了一個Java層的BinderProxy對象。
+ 通過JNI,該BinderProxy對象和一個Native的BpProxy對象掛鉤,而該BpProxy對象的通信目標就是ServiceManager。
接下來討論asInterface()方法,大家還記得在Native層Binder中那個著名的interface_cast宏嗎?在Java層中,雖然沒有這樣的宏,但是定義了一個類似的函數asInterface。下面來分析ServiceManagerNative類的asInterface函數,其代碼如下:
```
[ServiceManagerNative.java-->ServiceManagerNative.asInterface()]
static public IServiceManager asInterface(IBinderobj)
{
??? ......// 以obj為參數,創建一個ServiceManagerProxy對象
??? returnnew ServiceManagerProxy(obj);
}
```
上面代碼和Native層interface_cast非常類似,都是以一個BpProxy對象為參數構造一個和業務相關的Proxy對象,例如這里的ServiceManagerProxy對象。ServiceManagerProxy對象的各個業務函數會將相應請求打包后交給BpProxy對象,最終由BpProxy對象發送給Binder驅動以完成一次通信。
**說明** 實際上BpProxy也不會直接和Binder驅動交互,真正和Binder驅動交互的是IPCThreadState。
##### (2)addService函數分析
現在來分析ServiceManagerProxy的addService函數,其代碼如下:
```
[ServcieManagerNative.java-->ServiceManagerProxy.addService()]
public void addService(String name, IBinderservice)
?????????????????????????? throwsRemoteException {
??? Parceldata = Parcel.obtain();
??? Parcelreply = Parcel.obtain();
???data.writeInterfaceToken(IServiceManager.descriptor);
???data.writeString(name);
??? // 注意下面這個writeStrongBinder函數,后面我們會詳細分析它
???data.writeStrongBinder(service);
??? /*mRemote實際上就是BinderProxy對象,調用它的transact,將封裝好的請求數據
????? 發送出去 *
???mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
?? ?reply.recycle();
???data.recycle();
}
```
BinderProxy的transact,是一個native函數,其實現函數的代碼如下所示:
```
[android_util_Binder.cpp-->android_os_BinderProxy_transact()]
static jbooleanandroid_os_BinderProxy_transact(JNIEnv* env, jobject obj,
???????????????????????????????????????????jint code, jobject dataObj,
???????????????????????????????????????????jobject replyObj, jint flags)
{
??? ......
??? // 從Java的Parcel對象中得到作為參數的Native的Parcel對象
??? Parcel*data = parcelForJavaObject(env, dataObj);
??? if (data== NULL) {
???????return JNI_FALSE;
??? }
??? // 得到一個用于接收回復的Parcel對象
??? Parcel*reply = parcelForJavaObject(env, replyObj);
??? if(reply == NULL && replyObj != NULL) {
???????return JNI_FALSE;
??? }
??? // 從Java的BinderProxy對象中得到之前已經創建好的那個Native的BpBinder對象
??? IBinder*target = (IBinder*)
???????env->GetIntField(obj, gBinderProxyOffsets.mObject);
??? ......
??? // 通過Native的BpBinder對象,將請求發送給ServiceManager
??? status_terr = target->transact(code, *data, reply, flags);
??? ......
??? signalExceptionForError(env,obj, err);
??? returnJNI_FALSE;
}
```
看了上面的代碼會發現,Java層的Binder最終還是要借助Native的Binder進行通信的。
說明 從架構的角度看,在Java中搭建了一整套框架,如IBinder接口,Binder類和BinderProxy類。但是從通信角度看,不論架構的編寫采用的是Native語言還是Java語言,只要把請求傳遞到Binder驅動就可以了,所以通信的目的是向binder發送請求和接收回復。在這個目的之上,考慮到軟件的靈活性和可擴展性,于是編寫了一個架構。反過來說,也可以不使用架構(即沒有使用任何接口、派生之類的東西)而直接和binder交互,例如ServiceManager作為Binder的一個核心程序,就是直接讀取/dev/binder設備,獲取并處理請求。從這一點上看,Binder的目的雖是簡單的(即打開binder設備,然后讀請求和寫回復),但是架構是復雜的(編寫各種接口類和封裝類等)。我們在研究源碼時,一定要先搞清楚目的。實現只不過是達到該目的的一種手段和方式。脫離目的的實現,如緣木求魚,很容易偏離事物本質。
在對addService進行分析時曾提示writeStrongBinder是一個特別的函數。那么它特別在哪里呢?下面將給出解釋。
##### (3)三人行之Binder、JavaBBinderHolder和JavaBBinder
ActivityManagerService從ActivityManagerNative類派生,并實現了一些接口,其中和Binder的相關的只有這個ActivityManagerNative類,其原型如下:
```
[ActivityManagerNative.java-->ActivityManagerNative]
public abstract class ActivityManagerNative
????????????????????????? extends Binder
????????????????????????? implementsIActivityManager
```
ActivityManagerNative從Binder派生,并實現了IActivityManager接口。下面來看ActivityManagerNative的構造函數:
```
[ActivityManagerNative.java-->ActivityManagerNative.ActivityManagerNative()]
public ActivityManagerNative() {
???attachInterface(this, descriptor);// 該函數很簡單,讀者可自行分析
}
```
而ActivityManagerNative父類的構造函數則是Binder的構造函數:
```
[Binder.java-->Binder.Binder()]
public Binder() {
??? init();
}
```
Binder構造函數中會調用native的init函數,其實現的代碼如下:
```
[android_util_Binder.cpp-->android_os_Binder_init()]
static void android_os_Binder_init(JNIEnv* env,jobject obj)
{
??? // 創建一個JavaBBinderHolder對象
???JavaBBinderHolder* jbh = new JavaBBinderHolder();
???bh->incStrong((void*)android_os_Binder_init);
??? // 將這個JavaBBinderHolder對象保存到Java Binder對象的mObject成員中
???env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
}
```
從上面代碼可知,Java的Binder對象將和一個Native的JavaBBinderHolder對象相關聯。那么,JavaBBinderHolder是何方神圣呢?其定義如下:
```
[android_util_Binder.cpp-->JavaBBinderHolder]
class JavaBBinderHolder : public RefBase
{
public:
???sp<JavaBBinder> get(JNIEnv* env, jobject obj)
??? {
???????AutoMutex _l(mLock);
???????sp<JavaBBinder> b = mBinder.promote();
??????? if(b == NULL) {
???????????// 創建一個JavaBBinder,obj實際上是Java層中的Binder對象
???????????b = new JavaBBinder(env, obj);
???????????mBinder = b;
??????? }
???????return b;
??? }
??? ......
private:
???Mutex?????????? mLock;
???wp<JavaBBinder> mBinder;
};
```
從派生關系上可以發現,JavaBBinderHolder僅從RefBase派生,所以它不屬于Binder家族。Java層的Binder對象為什么會和Native層的一個與Binder家族無關的對象綁定呢?仔細觀察JavaBBinderHolder的定義可知:JavaBBinderHolder類的get函數中創建了一個JavaBBinder對象,這個對象就是從BnBinder派生的。
那么,這個get函數是在哪里調用的?答案在下面這句代碼中:
```
//其中,data是Parcel對象,service此時還是ActivityManagerService
data.writeStrongBinder(service);
```
writeStrongBinder會做一個替換工作,下面是它的native代碼實現:
```
[android_util_Binder.cpp-->android_os_Parcel_writeStrongBinder()]
static voidandroid_os_Parcel_writeStrongBinder(JNIEnv* env,
????????????????????????????? ?????????????????jobject clazz, jobject object)
{
??? /*parcel是一個Native的對象,writeStrongBinder的真正參數是
?????ibinderForJavaObject()的返回值*/
??? conststatus_t err = parcel->writeStrongBinder(
???????????????????????????????????ibinderForJavaObject(env, object));
}
[android_util_Binder.cpp-->ibinderForJavaObject()]
sp<IBinder> ibinderForJavaObject(JNIEnv*env, jobject obj)
{
??? /* 如果Java的obj是Binder類,則首先獲得JavaBBinderHolder對象,然后調用
????? 它的get()函數。而這個get將返回一個JavaBBinder? */
??? if(env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
????JavaBBinderHolder* jbh = (JavaBBinderHolder*)env->GetIntField(obj,
?????????????????????????????????????gBinderOffsets.mObject);
???????return jbh != NULL ? jbh->get(env, obj) : NULL;
??? }
??? // 如果obj是BinderProxy類,則返回Native的BpBinder對象
??? if(env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
???????return (IBinder*)
???????????env->GetIntField(obj, gBinderProxyOffsets.mObject);
??? }
?? returnNULL;
}
```
根據上面的介紹會發現,addService實際添加到Parcel的并不是AMS本身,而是一個叫JavaBBinder的對象。正是將它最終傳遞到Binder驅動。
讀者此時容易想到,Java層中所有的Binder對應的都是這個JavaBBinder。當然,不同的Binder對象對應不同的JavaBBinder對象。
圖2-2展示了Java Binder、JavaBBinderHolder和JavaBBinder的關系。

圖 2 - 2 Java Binder 、JavaBBinderHolder和JavaBBinder三者的關系
從圖2-2可知:
+ Java層的Binder通過mObject指向一個Native層的JavaBBInderHolder對象。
+ Native層的JavaBBinderHolder對象通過mBinder成員變量指向一個Native的JavaBBinder對象。
+ Native的JavaBBinder對象又通過mObject變量指向一個Java層的Binder對象。
為什么不直接讓Java層的Binder對象指向Native層的JavaBBinder對象呢?由于缺乏設計文檔,這里不便妄加揣測,但從JavaBBinderHolder的實現上來分析,估計和垃圾回收(內存管理)有關,因為JavaBBinderHolder中的mBinder對象的類型被定義成弱引用wp了。
建議 對此有更好的解釋的讀者,不妨與大家分享一下。
#### 2\. ActivityManagerService響應請求
初見JavaBBinde時,多少有些吃驚。回想一下Native層的Binder架構:雖然在代碼中調用的是Binder類提供的接口,但其對象卻是一個實際的服務端對象,例如MediaPlayerService對象,AudioFlinger對象。
而在Java層的Binder架構中,JavaBBinder卻是一個和業務完全無關的對象。那么,這個對象如何實現不同業務呢?
為回答此問題,我們必須看它的onTransact函數。當收到請求時,系統會調用這個函數。
說明 關于這個問題,建議讀者閱讀卷I第6章“深入理解Binder”。
```
[android_util_Binder.cpp-->JavaBBinder::onTransact()]
virtual status_t onTransact(
???????uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags =0)
{
??? JNIEnv*env = javavm_to_jnienv(mVM);
???IPCThreadState* thread_state = IPCThreadState::self();
??? .......
??? // 調用Java層Binder對象的execTranscat函數
??? jbooleanres = env->CallBooleanMethod(mObject,
????????????????????gBinderOffsets.mExecTransact,code,
???????????????????(int32_t)&data, (int32_t)reply, flags);
??? ......
??? returnres != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
```
就本例而言,上面代碼中的mObject就是ActivityManagerService,現在調用它的execTransact()方法,該方法在Binder類中實現,具體代碼如下:
```
[Binder.java-->Binder.execTransact()]
private boolean execTransact(int code, intdataObj, int replyObj,int flags) {
??? Parceldata = Parcel.obtain(dataObj);
??? Parcelreply = Parcel.obtain(replyObj);
??? booleanres;
??? try {
? ??????//調用onTransact函數,派生類可以重新實現這個函數,以完成業務功能
??????? res= onTransact(code, data, reply, flags);
??? } catch{ ... }
???reply.recycle();
???data.recycle();
??? returnres;
}
```
ActivityManagerNative類實現了onTransact函數,代碼如下:
```
[ActivityManagerNative.java-->ActivityManagerNative.onTransact()]
public boolean onTransact(int code, Parcel data,Parcel reply, int flags)
???????????throws RemoteException {
??? switch(code) {
??? caseSTART_ACTIVITY_TRANSACTION:
??? {
???????data.enforceInterface(IActivityManager.descriptor);
???????IBinder b = data.readStrongBinder();
???????......
??????? //再由ActivityManagerService實現業務函數startActivity
??????? intresult = startActivity(app, intent, resolvedType,
???????????????????grantedUriPermissions, grantedMode, resultTo, resultWho,
???????????????????requestCode, onlyIfNeeded, debug, profileFile,
???????????????????profileFd, autoStopProfiler);
???????reply.writeNoException();
???????reply.writeInt(result);
???????return true;
??? }
??? .... // 處理其他請求的case
??? }
}
```
由此可以看出,JavaBBinder僅是一個傳聲筒,它本身不實現任何業務函數,其工作是:
+ 當它收到請求時,只是簡單地調用它所綁定的Java層Binder對象的exeTransact。
+ 該Binder對象的exeTransact調用其子類實現的onTransact函數。
+ 子類的onTransact函數將業務又派發給其子類來完成。請讀者務必注意其中的多層繼承關系。
通過這種方式,來自客戶端的請求就能傳遞到正確的Java Binder對象了。圖2-3展示AMS響應請求的整個流程。

圖 2 - 3 AMS響應請求的流程
在圖2-3中,右上角的大方框表示AMS這個對象,其間的虛線箭頭表示調用子類重載的函數。
### 2.2.4 理解AIDL
經過上一節的介紹,讀者已經明白在Java層Binder的架構中,Bp端可以通過BinderProxy的transact()方法與Bn端發送請求,而Bn端通過繼承Binder類并重寫onTransact()接收并處理來自Bp端的請求。這個結構非常清晰而且簡單,但是實現起來卻頗為繁瑣。于是Android提供了AIDL語言以及AIDL解釋器自動生成一個服務的Bn端即Bp端的用于處理Binder通信的代碼。
AIDL的語法與定義一個Java接口的語法非常相似。為了避免業務實現對分析的干擾,本節通過一個最簡單的例子對AIDL的原理進行介紹:
```
[IMyServer.aidl]
package com.understanding.samples;
interface IMyServer {
??? intfoo(String str);
}
```
IMyServer.aidl定義了一個名為IMyServer的Binder服務,并提供了一個可以跨Binder調用的接口foo()。可以通過aidl工具將其解析為一個實現了Bn端及Bp端通過Binder進行通信的Java源代碼。具體命令如下:
```
aidl com/understanding/samples/IMyServer.aidl
```
生成的IMyServer.java可以在com/understanding/samples/文件夾下找到。
建議 讀者可以閱讀aidl有關的文檔了解此工具的詳細功能。
```
[IMyServer.java-->IMyServer]
package com.understanding.samples;
/* **① 首先,IMyServer.aidl被解析為一個Java接口IMyServer。**這個接口定義了AIDL文件中
? 所定義的接口foo() */
public interface IMyServer extendsandroid.os.IInterface {
??? /***② aidl工具生成了一個繼承自IMyServer接口的抽象類IMyServer.Stub。**這個抽象類實現了
????? Bn端通過onTransact()方法接收來自Bp端的請求的代碼。本例中的foo()方法在這個類中
????? 會被定義成一個抽象方法。因為aidl工具根不知道foo()方法是做什么的,它只能在onTransact()
????? 中得知Bp端希望對foo()方法進行調用,所以Stub類是抽象的。 */
??? publicstatic abstract class Stub extends android.os.Binder implements
?????????????????????????????????????????? com.understanding.samples.IMyServer{
???????...... // Stub類的其他實現
??????? /*onTransact()根據code的值選擇調用IMyServer接口中的不同方法。本例中
?????????TRANSACTION_foo意味著需要通過調用foo()方法完成請求 */
???????public boolean onTransact(int code, android.os.Parcel data,
???????????????android.os.Parcel reply, int flags)
???????????????throws android.os.RemoteException {
???????????switch (code) {
??????????? ......
???????????case TRANSACTION_foo: {
???????????????...... // 從data中讀取參數_arg0
???????????????// Stub類的子類需要實現foo()方法
??? ????????????int _result = this.foo(_arg0);
???????????????...... // 向reply中寫入_result
???????????????return true;
???????????}
???????????}
???????????return super.onTransact(code, data, reply, flags);
??????? }
??????? /* **③ aidl工具還生成了一個繼承自IMyServer接口的類Proxy,它是Bp端的實現。**與Bn端的
?????????Stub類不同,它實現了foo()函數。因為foo()函數在Bp端的實現是確定的,即將參數存儲到
?????????Parcel中然后執行transact()方法將請求發送給Bn端,然后從reply中讀取返回值并返回
????????? 給調用者 */
??????? ? private static class Proxy implements com.understanding.samples.IMyServer{
????????? ??...... // Proxy類的其他實現
???????????public int foo(java.lang.String str)
???????????????????throws android.os.RemoteException {
???????????????android.os.Parcel _data = android.os.Parcel.obtain();
???????????????android.os.Parcel _reply = android.os.Parcel.obtain();
???????????????int _result;
???????????????try {
???????????????????...... // 將參數str寫入參數_data
???????????????????// mRemote就是指向IMyServer Bn端的BinderProxy
???????????????????mRemote.transact(Stub.TRANSACTION_foo, _data, _reply, 0);
???????????????????......// 從_replay中讀取返回值_result
???????????????} finally { ...... }
???????????????return _result;
???????????}
??????? }
??????? // TRANSACTION_foo常量用于定義foo()方法的code
??????? ? static final int TRANSACTION_foo =
????????? ???????????????????(android.os.IBinder.FIRST_CALL_TRANSACTION+ 0);
??? }
??? // 聲明IMyServer所提供的接口
??? publicint foo(java.lang.String str) throws android.os.RemoteException;
}
```
可見一個AIDL文件被aidl工具解析之后會產生三個物件:
+ IMyServer接口。它僅僅用來在Java中聲明IMyServer.aidl中所聲明的接口。
+ IMyServer.Stub類。這個繼承自Binder類的抽象類實現了Bn端與Binder通信相關的代碼。
+ IMyServer.Stub.Proxy類。這個類實現了Bp端與Binder通信相關的代碼。
在完成了aidl的解析之后,為了實現一個Bn端,開發者需要繼承IMyServer.Stub類并實現其抽象方法。如下所示:
```
class MyServer extends IMyServer.Stub {
??? intfoo(String str) {
??????? // 做點什么都可以
??????? returnstr.length();
??? }
}
```
于是每一個MyServer類的實例,都具有了作為Bn端的能力。典型的做法是將MyServer類的實例通過ServiceManager.addService()將其注冊為一個系統服務,或者在一個Android標準Service的onBind()方法中將其作為返回值使之可以被其他進程訪問。另外,也可以通過Binder調用將其傳遞給另外一個進程,使之成為一個跨進程的回調對象。
那么Bp端將如何使用IMyServer.Proxy呢?在Bp端所在進程中,一旦獲取了IMyServer的BinderProxy(通過ServiceManager.getService()、onServiceConnected()或者其他方式),就可以以如下方式獲得一個IMyServer.Proxy:
```
// 其中binderProxy就是通過ServiceManager.getService()所獲取
IMyServer remote = IMyServer.Stub.asInterface(binderProxy);
remote.foo(“Hello AIDL!”);
IMyServer.Stub.asInterface()的實現如下:
[IMyServer.java-->IMyServer.Stub.asInterface()]
public static com.understanding.samples.IMyServerasInterface(
???????android.os.IBinder obj) {
??? ......
??? // 創建一個IMyServer.Stub.Proxy。其中參數obj將會被保存為Proxy類的mRemote成員。
? ??return new com.understanding.samples.IMyServer.Stub.Proxy(obj);
}
```
可見,AIDL使得構建一個Binder服務的工作大大地簡化了。
### 2.2.5 Java層Binder架構總結
圖2-4展示了Java層的Binder架構。

圖 2 - 4 Java層Binder架構
根據圖2-4可知:
+ 對于代表客戶端的BinderProxy來說,Java層的BinderProxy在Native層對應一個BpBinder對象。凡是從Java層發出的請求,首先從Java層的BinderProxy傳遞到Native層的BpBinder,繼而由BpBinder將請求發送到Binder驅動。
+ 對于代表服務端的Service來說,Java層的Binder在Native層有一個JavaBBinder對象。前面介紹過,所有Java層的Binder在Native層都對應為JavaBBinder,而JavaBBinder僅起到中轉作用,即把來自客戶端的請求從Native層傳遞到Java層。
+ 系統中依然只有一個Native的ServiceManager。
至此,Java層的Binder架構已介紹完畢。從前面的分析可以看出,Java層Binder非常依賴Native層的Binder。建議想進一步了解Binder的讀者們,要深入了解這一問題,有必要閱讀卷I的第6章“深入理解Binder”。
## 2.3 心系兩界的MessageQueue
卷I第5章介紹過,MessageQueue類封裝了與消息隊列有關的操作。在一個以消息驅動的系統中,最重要的兩部分就是消息隊列和消息處理循環。在Andrid 2.3以前,只有Java世界的居民有資格向MessageQueue中添加消息以驅動Java世界的正常運轉,但從Android 2.3開始,MessageQueue的核心部分下移至Native層,讓Native世界的居民也能利用消息循環來處理他們所在世界的事情。因此現在的MessageQueue心系Native和Java兩個世界。
### 2.3.1 MessageQueue的創建
現在來分析MessageQueue是如何跨界工作的,其代碼如下:
```
[MessageQueue.java-->MessageQueue.MessageQueue()]
MessageQueue() {
??? nativeInit();//構造函數調用nativeInit,該函數由Native層實現
}
```
nativeInit()方法的真正實現為android_os_MessageQueue_nativeInit()函數,其代碼如下:
```
[android_os_MessageQueue.cpp-->android_os_MessageQueue_nativeInit()]
static voidandroid_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
?? ?// NativeMessageQueue是MessageQueue在Native層的代表
? ??NativeMessageQueue* nativeMessageQueue = newNativeMessageQueue();
? ??......
? ??// 將這個NativeMessageQueue對象設置到Java層保存
? ??android_os_MessageQueue_setNativeMessageQueue(env,obj,
?????????????????????????????????????????????????????????nativeMessageQueue);
}
```
nativeInit函數在Native層創建了一個與MessageQueue對應的NativeMessageQueue對象,其構造函數如下:
```
[android_os_MessageQueue.cpp-->NativeMessageQueue::NativeMessageQueue()]
NativeMessageQueue::NativeMessageQueue() {
??? /* 代表消息循環的Looper也在Native層中呈現身影了。根據消息驅動的知識,一個線程會有一個
?? ???Looper來循環處理消息隊列中的消息。下面一行的調用就是取得保存在線程本地存儲空間
?? ??(Thread Local Storage)中的Looper對象 */
??? mLooper= Looper::getForThread();
?? ?if (mLooper == NULL) {
??? ????/* 如為第一次進來,則該線程沒有設置本地存儲,所以須先創建一個Looper,然后再將其保存到
??? ??????TLS中,這是很常見的一種以線程為單位的單例模式*/
????? ??mLooper = new Looper(false);
????? ??Looper::setForThread(mLooper);
??? }
}
```
Native的Looper是Native世界中參與消息循環的一位重要角色。雖然它的類名和Java層的Looper類一樣,但此二者其實并無任何關系。這一點以后還將詳細分析。
### 2.3.2 提取消息
當一切準備就緒后,Java層的消息循環處理,也就是Looper會在一個循環中提取并處理消息。消息的提取就是調用MessageQueue的next()方法。當消息隊列為空時,next就會阻塞。MessageQueue同時支持Java層和Native層的事件,那么其next()方法該怎么實現呢?具體代碼如下:
```
[MessagQueue.java-->MessageQueue.next()]
final Message next() {
? ??int pendingIdleHandlerCount = -1;
??? int nextPollTimeoutMillis = 0;
?? ?for (;;) {
?? ?????......
? ??????// mPtr保存了NativeMessageQueue的指針,調用nativePollOnce進行等待
? ??????nativePollOnce(mPtr,nextPollTimeoutMillis);
?????? ?synchronized (this) {
????? ??????final long now = SystemClock.uptimeMillis();
????? ??????// mMessages用來存儲消息,這里從其中取一個消息進行處理
???? ???????final Message msg = mMessages;
???? ???????if (msg != null) {
???? ???????????final long when = msg.when;
????? ??????????if (now >= when) {
?? ?????????????????mBlocked = false;
??? ????????????????mMessages = msg.next;
???? ???????????????msg.next = null;
??? ????????????????msg.markInUse();
???? ???????????????return msg; // 返回一個Message給Looper進行派發和處理
???????????????} else {
???????? ???????????nextPollTimeoutMillis = (int) Math.min(when- now,
??????? ??????????????????????????????????????????Integer.MAX_VALUE);
?????? ?????????}
?????? ?????} else {
??????? ????????nextPollTimeoutMillis = -1;
????? ??????}
?????? ?????......
????? ??????/* 處理注冊的IdleHandler,當MessageQueue中沒有Message時,
???????????Looper會調用IdleHandler做一些工作,例如做垃圾回收等 ?*/
???????????......
???????????pendingIdleHandlerCount = 0;
???? ???????nextPollTimeoutMillis = 0;
??????? }
??? }
}
```
看到這里,可能會有人覺得這個MessageQueue很簡單,不就是從以前在Java層的wait變成現在Native層的wait了嗎?但是事情本質比表象要復雜得多,來思考下面的情況:
nativePollOnce()返回后,next()方法將從mMessages中提取一個消息。也就是說,要讓nativePollOnce()返回,至少要添加一個消息到消息隊列,否則nativePollOnce()不過是做了一次無用功罷了。
如果nativePollOnce()將在Native層等待,就表明Native層也可以投遞Message,但是從Message類的實現代碼上看,該類和Native層沒有建立任何關系。那么nativePollOnce()在等待什么呢?
對于上面的問題,相信有些讀者心中已有了答案:nativePollOnce()不僅在等待Java層來的Message,實際上還在Native還做了大量的工作。
下面我們來分析Java層投遞Message并觸發nativePollOnce工作的正常流程。
#### 1\. 在Java層投遞Message
MessageQueue的enqueueMessage函數完成將一個Message投遞到MessageQueue中的工作,其代碼如下:
```
[MesssageQueue.java-->MessageQueue.enqueueMessage()]
final boolean enqueueMessage(Message msg, longwhen) {
??? ......
??? finalboolean needWake;
???synchronized (this) {
??????? if(mQuiting) {
???????????return false;
??????? }else if (msg.target == null) {
???????????mQuiting = true;
??????? }
???????msg.when = when;
???????Message p = mMessages;
??????? if(p == null || when == 0 || when < p.when) {
???????????/* 如果p為空,表明消息隊列中沒有消息,那么msg將是第一個消息,needWake
?????????????需要根據mBlocked的情況考慮是否觸發 */
??????????? msg.next= p;
???????????mMessages = msg;
???????????needWake = mBlocked;
?? ?????} else {
???????????// 如果p不為空,表明消息隊列中還有剩余消息,需要將新的msg加到消息尾
???????????Message prev = null;
???????????while (p != null && p.when <= when) {
???????????????prev = p;
???????????????p = p.next;
???????????}
???????????msg.next = prev.next;
???????????prev.next = msg;
???????????// 因為消息隊列之前還剩余有消息,所以這里不用調用nativeWakeup
???????????needWake = false;
??? ????}
??? }
??? if(needWake) {
??????? // 調用nativeWake,以觸發nativePollOnce函數結束等待
???????nativeWake(mPtr);
??? }
??? returntrue;
}
```
上面的代碼比較簡單,主要功能是:
+ 將message按執行時間排序,并加入消息隊。
+ 根據情況調用nativeWake函數,以觸發nativePollOnce函數,結束等待。
建議 雖然代碼簡單,但是對于那些不熟悉多線程的讀者,還是要細細品味一下mBlocked值的作用。我們常說細節體現美,代碼也一樣,這個小小的mBlocked正是如此。
#### 2\. nativeWake函數分析
nativeWake函數的代碼如下所示:
```
[android_os_MessageQueue.cpp-->android_os_MessageQueue_nativeWake()]
static voidandroid_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj,
??????????????????????????????????????????????????????jint ptr)
{
???NativeMessageQueue* nativeMessageQueue =?// 取出NativeMessageQueue對象
??????????????????????reinterpret_cast<NativeMessageQueue*>(ptr);
??? returnnativeMessageQueue->wake(); // 調用它的wake函數
}
[android_os_MessageQueue.cpp-->NativeMessageQueue::wake()]
void NativeMessageQueue::wake() {
???mLooper->wake(); // 層層調用,現在轉到mLooper的wake函數
}
```
Native Looper的wake函數代碼如下:
```
[Looper.cpp-->Looper::wake()]
void Looper::wake() {
??? ssize_tnWrite;
??? do {
??????? // 向管道的寫端寫入一個字符
???????nWrite = write(mWakeWritePipeFd, "W", 1);
??? } while(nWrite == -1 && errno == EINTR);
}
```
Wake()函數則更為簡單,僅僅向管道的寫端寫入一個字符”W”,這樣管道的讀端就會因為有數據可讀而從等待狀態中醒來。
### 2.3.3 nativePollOnce函數分析
nativePollOnce()的實現函數是android_os_MessageQueue_nativePollOnce,代碼如下:
```
[android_os_MessageQueue.cpp-->android_os_MessageQueue_nativePollOnce()]
static voidandroid_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
??????? jintptr, jint timeoutMillis)
????NativeMessageQueue* nativeMessageQueue =
???????????????????????????reinterpret_cast<NativeMessageQueue*>(ptr);
??? // 取出NativeMessageQueue對象,并調用它的pollOnce
???nativeMessageQueue->pollOnce(timeoutMillis);
}
```
分析pollOnce函數:
```
[android_os_MessageQueue.cpp-->NativeMessageQueue::pollOnece()]
void NativeMessageQueue::pollOnce(inttimeoutMillis) {
???mLooper->pollOnce(timeoutMillis); // 重任傳遞到Looper的pollOnce函數
}
```
Looper的pollOnce函數如下:
```
[Looper.cpp-->Looper::pollOnce()]
inline int pollOnce(int timeoutMillis) {
??? returnpollOnce(timeoutMillis, NULL, NULL, NULL);
}
```
上面的函數將調用另外一個有4個參數的pollOnce函數,這個函數的原型如下:
```
int pollOnce(int timeoutMillis, int* outFd, int*outEvents, void** outData)
```
其中:
+ timeOutMillis參數為超時等待時間。如果為-1,則表示無限等待,直到有事件發生為止。如果值為0,則無需等待立即返回。
+ outFd用來存儲發生事件的那個文件描述符 。
+ outEvents用來存儲在該文件描述符1上發生了哪些事件,目前支持可讀、可寫、錯誤和中斷4個事件。這4個事件其實是從epoll事件轉化而來。后面我們會介紹大名鼎鼎的epoll。
+ outData用于存儲上下文數據,這個上下文數據是由用戶在添加監聽句柄時傳遞的,它的作用和pthread_create函數最后一個參數param一樣,用來傳遞用戶自定義的數據。
另外,pollOnce函數的返回值也具有特殊的意義,具體如下:
+ 當返回值為ALOOPER_POLL_WAKE時,表示這次返回是由wake函數觸發的,也就是管道寫端的那次寫事件觸發的。
+ 返回值為ALOOPER_POLL_TIMEOUT表示等待超時。
+ 返回值為ALOOPER_POLL_ERROR,表示等待過程中發生錯誤。
+ 返回值為ALOOPER_POLL_CALLBACK,表示某個被監聽的句柄因某種原因被觸發。這時,outFd參數用于存儲發生事件的文件句柄,outEvents用于存儲所發生的事件。
上面這些知識是和epoll息息相關的。
提示 查看Looper的代碼會發現,Looper采用了編譯選項(即#if和#else)來控制是否使用epoll作為I/O復用的控制中樞。鑒于現在大多數系統都支持epoll,這里僅討論使用epoll的情況。
#### 1\. epoll基礎知識介紹
epoll機制提供了Linux平臺上最高效的I/O復用機制,因此有必要介紹一下它的基礎知識。
從調用方法上看,epoll的用法和select/poll非常類似,其主要作用就是I/O復用,即在一個地方等待多個文件句柄的I/O事件。
下面通過一個簡單例子來分析epoll的工作流程。
```
/* **① 使用epoll前,需要先通過epoll_create函數創建一個epoll句柄。**
? 下面一行代碼中的10表示該epoll句柄初次創建時候分配能容納10個fd相關信息的緩存。
? 對于2.6.8版本以后的內核,該值沒有實際作用,這里可以忽略。其實這個值的主要目的是
? 確定分配一塊多大的緩存。現在的內核都支持動態拓展這塊緩存,所以該值就沒有意義了 */
int epollHandle = epoll_create(10);
/* **② 得到epoll句柄后,下一步就是通過epoll_ctl把需要監聽的文件句柄加入到epoll句柄中。**
? 除了指定文件句柄本身的fd值外,同時還需要指定在該fd上等待什么事件。epoll支持四類事件,
? 分別是EPOLLIN(句柄可讀)、EPOLLOUT(句柄可寫),EPOLLERR(句柄錯誤)、EPOLLHUP(句柄斷)。
? epoll定義了一個結構體struct epoll_event來表達監聽句柄的訴求。
? 假設現在有一個監聽端的socket句柄listener,要把它加入到epoll句柄中 */
struct epoll_event listenEvent; //先定義一個event
/* EPOLLIN表示可讀事件,EPOLLOUT表示可寫事件,另外還有EPOLLERR,EPOLLHUP表示
? 系統默認會將EPOLLERR加入到事件集合中 */
listenEvent.events = EPOLLIN;// 指定該句柄的可讀事件
// epoll_event中有一個聯合體叫data,用來存儲上下文數據,本例的上下文數據就是句柄自己
listenEvent.data.fd = listenEvent;
? /* **③** EPOLL_CTL_ADD將監聽fd和監聽事件加入到epoll句柄的等待隊列中;
? ??EPOLL_CTL_DEL將監聽fd從epoll句柄中移除;
? ??EPOLL_CTL_MOD修改監聽fd的監聽事件,例如本來只等待可讀事件,現在需要同時等待
? ??可寫事件,那么修改listenEvent.events 為EPOLLIN|EPOLLOUT后,再傳給epoll句柄*/
epoll_ctl(epollHandle,EPOLL_CTL_ADD,listener,&listenEvent);
/* 當把所有感興趣的fd都加入到epoll句柄后,就可以開始坐等感興趣的事情發生了。
? 為了接收所發生的事情,先定義一個epoll_event數組 */
struct?epoll_event resultEvents[10];
int timeout = -1;
while(1) {
? ??/* **④ 調用epoll_wait用于等待事件。**其中timeout可以指定一個超時時間,
?????resultEvents用于接收發生的事件,10為該數組的大小。
?????epoll_wait函數的返回值有如下含義:
????? nfds大于0表示所監聽的句柄上有事件發生;
????? nfds等于0表示等待超時;
????? nfds小于0表示等待過程中發生了錯誤*/
?? ?int nfds = epoll_wait(epollHandle,resultEvents, 10, timeout);
?? ?if(nfds == -1) {
??????? // epoll_wait發生了錯誤
??? } else if(nfds == 0) {
? ??????//發生超時,期間沒有發生任何事件
??? } else{
????? ??// ⑤resultEvents用于返回那些發生了事件的信息
????? ??for(int i = 0; i < nfds; i++) {
???????? ???struct epoll_event & event =resultEvents[i];
???????? ???if(event & EPOLLIN) {
? ??????????????/* **⑥ 收到可讀事件。**到底是哪個文件句柄發生該事件呢?可通過event.data這個聯合
?????????????????體取得 前傳遞給epoll的上下文數據,該上下文信息可用于判斷到底是誰發生了事件 */
?????????? ???......
??????? ????}
???????? ???.......//其他處理?
??? ????}
?? ?}
}
```
epoll整體使用流程如上面代碼所示,基本和select/poll類似,不過作為Linux平臺最高效的I/O復用機制,這里有些內容供讀者參考,
epoll的效率為什么會比select高?其中一個原因是調用方法。每次調用select時,都需要把感興趣的事件復制到內核中,而epoll只在epll_ctl進行加入的時候復制一次。另外,epoll內部用于保存事件的數據結構使用的是紅黑樹,查找速度很快。而select采用數組保存信息,不但一次能等待的句柄個數有限,并且查找起來速度很慢。當然,在只等待少量文件句柄時,select和epoll效率相差不是很多,但還是推薦使用epoll。
epoll等待的事件有兩種觸發條件,一個是水平觸發(EPOLLLEVEL),另外一個是邊緣觸發(EPOLLET,ET為Edge Trigger之意),這兩種觸發條件的區別非常重要。讀者可通過man epoll查閱系統提供的更為詳細的epoll機制。
最后,關于pipe,還想提出一個小問題供讀者思考討論:
為什么Android中使用pipe作為線程間通訊的方式?對于pipe的寫端寫入的數據,讀端都不感興趣,只是為了簡單的喚醒。POSIX不是也有線程間同步函數嗎?為什么要用pipe呢?
關于這個問題的答案,可參見鄧凡平的一篇博文“隨筆之如何實現一個線程池”。
+ http://www.cnblogs.com/innost/archive/2011/11/24/2261454.html
#### 2\. pollOnce()函數分析
下面分析帶4個參數的pollOnce()函數,代碼如下:
```
[Looper.cpp-->Looper::pollOnce()]
int Looper::pollOnce(int timeoutMillis, int*outFd, int* outEvents,
void** outData) {
??? intresult = 0;
? ??for(;;) { // 一個無限循環
? ??????// mResponses是一個Vector,這里首先需要處理response
???????while (mResponseIndex < mResponses.size()) {
???????????const Response& response = mResponses.itemAt(mResponseIndex++);
???????????ALooper_callbackFunc callback = response.request.callback;
?????? ?????if (!callback) {// 首先處理那些沒有callback的Response
???????????????int ident = response.request.ident; // ident是這個Response的id
???????????????int fd = response.request.fd;
???????????????int events = response.events;
???????????????void* data = response.request.data;
???????????????......
???????????????if (outFd != NULL) *outFd = fd;
???????????????if (outEvents != NULL) *outEvents = events;
???????????????if (outData != NULL) *outData = data;
???????????????/* 實際上,對于沒有callback的Response,pollOnce只是返回它的
?????????????????ident,并沒有實際做什么處理。因為沒有callback,所以系統也不知道如何處理 */
???????????????return ident;
???????????}
??????? }
??????? if(result != 0) {
?????? ?????if(outFd != NULL) *outFd = 0;
???????????if (outEvents != NULL) *outEvents = NULL;
????? ??????if (outData != NULL) *outData = NULL;
???????????return result;
??????? }
??????? // 調用pollInner函數。注意,它在for循環內部
???????result = pollInner(timeoutMillis);
??? }
}
```
初看上面的代碼,可能會讓人有些丈二和尚摸不著頭腦。但是把pollInner()函數分析完畢,大家就會明白很多。pollInner()函數非常長,把用于調試和統計的代碼去掉,結果如下:
```
[Looper.cpp-->Looper::pollInner()]
int Looper::pollInner(int timeoutMillis) {
??? if(timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
???????nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
???????......//根據Native Message的信息計算此次需要等待的時間
???????timeoutMillis = messageTimeoutMillis;
??? }
??? intresult = ALOOPER_POLL_WAKE;
???mResponses.clear();
???mResponseIndex = 0;
#ifdef LOOPER_USES_EPOLL? // 只討論使用epoll進行I/O復用的方式
??? structepoll_event eventItems[EPOLL_MAX_EVENTS];
??? // 調用epoll_wait,等待感興趣的事件或超時發生
??? inteventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS,
?????????????????????????????????????timeoutMillis);
#else
??? ......//使用別的方式進行I/O復用
#endif
??? //從epoll_wait返回,這時候一定發生了什么事情
???mLock.lock();
??? if(eventCount < 0) { //返回值小于零,表示發生錯誤
??????? if(errno == EINTR) {
???????????goto Done;
??????? }
??????? //設置result為ALLOPER_POLL_ERROR,并跳轉到Done
???????result = ALOOPER_POLL_ERROR;
??????? gotoDone;
??? }
???//eventCount為零,表示發生超時,因此直接跳轉到Done
??? if(eventCount == 0) {
??????result = ALOOPER_POLL_TIMEOUT;
??????? gotoDone;
??? }
#ifdef LOOPER_USES_EPOLL
??? // 根據epoll的用法,此時的eventCount表示發生事件的個數
??? for (inti = 0; i < eventCount; i++) {
??????? intfd = eventItems[i].data.fd;
???????uint32_t epollEvents = eventItems[i].events;
??????? /* 之前通過pipe函數創建過兩個fd,這里根據fd知道是管道讀端有可讀事件。
???????? 讀者還記得對nativeWake函數的分析嗎?在那里我們向管道寫端寫了一個”W”字符,這樣
???????? 就能觸發管道讀端從epoll_wait函數返回了 */
??????? if(fd == mWakeReadPipeFd) {
???????????if (epollEvents & EPOLLIN) {
????? ??????????// awoken函數直接讀取并清空管道數據,讀者可自行研究該函數
???????????????awoken();
???????????}
??????? ????......
??????? }else {
??????????/* mRequests和前面的mResponse相對應,它也是一個KeyedVector,其中存儲了
???????????fd和對應的Request結構體,該結構體封裝了和監控文件句柄相關的一些上下文信息,
??????????? 例如回調函數等。我們在后面的小節會再次介紹該結構體 */
???????????ssize_t requestIndex = mRequests.indexOfKey(fd);
???????????if (requestIndex >= 0) {
???????????????int events = 0;
???????????????// 將epoll返回的事件轉換成上層LOOPER使用的事件
???????????????if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
???????????????if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
???????????????if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
???????????????if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
???????????????// 每處理一個Request,就相應構造一個Response
???????????????pushResponse(events, mRequests.valueAt(requestIndex));
???????????}?
????????????......
??????? }
??? }
Done: ;
#else
???? ......
#endif
??? // 除了處理Request外,還處理Native的Message
???mNextMessageUptime = LLONG_MAX;
??? while(mMessageEnvelopes.size() != 0) {
???????nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
???????const MessageEnvelope& messageEnvelope =mMessageEnvelopes.itemAt(0);
??????? if(messageEnvelope.uptime <= now) {
???????????{
???????????????sp<MessageHandler> handler = messageEnvelope.handler;
???????????????Message message = messageEnvelope.message;
???????????????mMessageEnvelopes.removeAt(0);
???????????????mSendingMessage = true;
???????????????mLock.unlock();
???????????????/* 調用Native的handler處理Native的Message
????????????????從這里也可看出Native Message和Java層的Message沒有什么關系 */
???????????????handler->handleMessage(message);
???????????}
???????????mLock.lock();
???????????mSendingMessage = false;
???????????result = ALOOPER_POLL_CALLBACK;
??????? }else {
????????????mNextMessageUptime = messageEnvelope.uptime;
???????????break;
??????? }
??? }
???mLock.unlock();
??? // 處理那些帶回調函數的Response
?? ?for (size_t i = 0; i < mResponses.size();i++) {
???????const Response& response = mResponses.itemAt(i);
???????ALooper_callbackFunc callback = response.request.callback;
??????? if(callback) {// 有了回調函數,就能知道如何處理所發生的事情了
???????????int fd = response.request.fd;
???????????int events = response.events;
???????????void* data = response.request.data;
???????????// 調用回調函數處理所發生的事件
???????????int callbackResult = callback(fd, events, data);
???????????if (callbackResult == 0) {
???????????????// callback函數的返回值很重要,如果為0,表明不需要再次監視該文件句柄
??????????? ????removeFd(fd);
???????????}
???????????result = ALOOPER_POLL_CALLBACK;
??????? }
??? }
??? returnresult;
}
```
看完代碼了,是否還有點模糊?那么,回顧一下pollInner函數的幾個關鍵點:
+ 首先需要計算一下真正需要等待的時間。
+ 調用epoll_wait函數等待。
+ epoll_wait函數返回,這時候可能有三種情況:
a)??????發生錯誤,則跳轉到Done處。
b)?????超時,這時候也跳轉到Done處。
c)??????epoll_wait監測到某些文件句柄上有事件發生。
+ 假設epoll_wait因為文件句柄有事件而返回,此時需要根據文件句柄來分別處理:
a)??????如果是管道讀這一端有事情,則認為是控制命令,可以直接讀取管道中的數據。
b)?????如果是其他FD發生事件,則根據Request構造Response,并push到Response數組中。
+ 真正開始處理事件是在有Done標志的位置。
a)??????首先處理Native的Message。調用Native Handler的handleMessage處理該Message。
b)?????處理Response數組中那些帶有callback的事件。
上面的處理流程還是比較清晰的,但還是有個一個攔路虎,那就是mRequests,下面就來清剿這個攔路虎。
#### 3\. 添加監控請求
添加監控請求其實就是調用epoll_ctl增加文件句柄。下面通過從Native的Activity找到的一個例子來分析mRequests。
```
[android_app_NativeActivity.cpp-->loadNativeCode_native()]
static jint
loadNativeCode_native(JNIEnv* env, jobject clazz,jstring path,
????????????????????????? jstringfuncName,jobject messageQueue,
????????????????????????? jstringinternalDataDir, jstring obbDir,
????????????????????????? jstringexternalDataDir, int sdkVersion,
????????????????????????? jobject jAssetMgr,jbyteArray savedState)
{
? ??......
? ??/* 調用Looper的addFd函數。第一個參數表示監聽的fd;第二個參數0表示ident;
???? ?第三個參數表示需要監聽的事件,這里為只監聽可讀事件;第四個參數為回調函數,當該fd發生
? ????指定事件時,looper將回調該函數;第五個參數code為回調函數的參數 */
? ??code->looper->addFd(code->mainWorkRead,0,
???? ?????????????????????ALOOPER_EVENT_INPUT,mainWorkCallback, code);
? ......
}
```
Looper的addFd()代碼如下所示:
```
[Looper.cpp-->Looper::addFd()]
int Looper::addFd(int fd, int ident, int events,
????????????????????? ALooper_callbackFunccallback, void* data) {
??? if (!callback) {
???????? /* 判斷該Looper是否支持不帶回調函數的文件句柄添加。一般不支持,因為沒有回調函數
???????? ??Looper也不知道如何處理該文件句柄上發生的事情 */
???????? if(! mAllowNonCallbacks) {
???????????return -1;
??????? }
????? ......
??? }
#ifdef LOOPER_USES_EPOLL
??? intepollEvents = 0;
??? // 將用戶的事件轉換成epoll使用的值
??? if(events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
??? if(events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
??? {
???????AutoMutex _l(mLock);
???????Request request; // 創建一個Request對象
???????request.fd = fd; // 保存fd
???????request.ident = ident; // 保存id
???????request.callback = callback; //保存callback
???????request.data = data;? // 保存用戶自定義數據
???????struct epoll_event eventItem;
???????memset(& eventItem, 0, sizeof(epoll_event));
???????eventItem.events = epollEvents;
???????eventItem.data.fd = fd;
??????? // 判斷該Request是否已經存在,mRequests以fd作為key值
???????ssize_t requestIndex = mRequests.indexOfKey(fd);
??????? if(requestIndex < 0) {
???????????// 如果是新的文件句柄,則需要為epoll增加該fd
???????????int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem);
???????????......
???????????// 保存Request到mRequests鍵值數組
???????????mRequests.add(fd, request);
??????? }else {
???????????// 如果之前加過,那么就修改該監聽句柄的一些信息
???????????int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, &eventItem);
??????????......
???????????mRequests.replaceValueAt(requestIndex, request);
??????? }
??? }
#else
??? ......
#endif
??? return1;
}
```
#### 4\. 處理監控請求
我們發現在pollInner()函數中,當某個監控fd上發生事件后,就會把對應的Request取出來調用。
```
pushResponse(events, mRequests.itemAt(i));
```
此函數如下:
```
[Looper.cpp-->Looper::pushResponse()]
void Looper::pushResponse(int events, constRequest& request) {
??? Responseresponse;
???response.events = events;
???response.request = request; //其實很簡單,就是保存所發生的事情和對應的Request
??? mResponses.push(response);//然后保存到mResponse數組
}
```
根據前面的知識可知,并不是單獨處理Request,而是需要先收集Request,等到Native Message消息處理完之后再做處理。這表明,在處理邏輯上,Native Message的優先級高于監控FD的優先級。
下面來了解如何添加Native的Message。
#### 5\. Native的sendMessage
Android 2.2中只有Java層才可以通過sendMessage()往MessageQueue中添加消息,從4.0開始,Native層也支持sendMessage()了。sendMessage()的代碼如下:
```
[Looper.cpp-->Looper::sendMessage()]
void Looper::sendMessage(constsp<MessageHandler>& handler,
????????????????????????????? constMessage& message) {
??? //Native的sendMessage函數必須同時傳遞一個Handler
??? nsecs_tnow = systemTime(SYSTEM_TIME_MONOTONIC);
???sendMessageAtTime(now, handler, message); //調用sendMessageAtTime
}
[Looper.java-->Looper::sendMessageAtTime()]
void Looper::sendMessageAtTime(nsecs_t uptime,
???????????????????????????????????? constsp<MessageHandler>& handler,
???????????????????????????????????? constMessage& message) {
?? size_t i= 0;
??? {
???????AutoMutex _l(mLock);
???????size_t messageCount = mMessageEnvelopes.size();
??????? // 按時間排序,將消息插入到正確的位置上
???????while (i < messageCount &&
???????????????uptime >= mMessageEnvelopes.itemAt(i).uptime) {
???????????i += 1;
??????? }
???????MessageEnvelope messageEnvelope(uptime, handler, message);
???????mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
??????? // mSendingMessage和Java層中的那個mBlocked一樣,是一個小小的優化措施
??????? if(mSendingMessage) {
???????????return;
??????? }
??? }
??? // 喚醒epoll_wait,讓它處理消息
??? if (i ==0) {
???????wake();
??? }
}
```
### 2.3.4 MessageQueue總結
想不到,一個小小的MessageQueue竟然有如此多的內容。在后面分析Android輸入系統時,會再次在Native層和MessageQueue碰面,這里僅是為后面的相會打下一定的基礎。
現在將站在一個比具體代碼更高的層次來認識一下MessageQueue和它的伙伴們。
#### 1\. 消息處理的大家族合照
MessageQueue只是消息處理大家族的一員,該家族的成員合照如圖2-5所示。

圖 2 - 5 消息處理的家族合照
結合前述內容可從圖2-5中得到:
+ Java層提供了Looper類和MessageQueue類,其中Looper類提供循環處理消息的機制,MessageQueue類提供一個消息隊列,以及插入、刪除和提取消息的函數接口。另外,Handler也是在Java層常用的與消息處理相關的類。
+ MessageQueue內部通過mPtr變量保存一個Native層的NativeMessageQueue對象,mMessages保存來自Java層的Message消息。
+ NativeMessageQueue保存一個native的Looper對象,該Looper從ALooper派生,提供pollOnce和addFd等函數。
+ Java層有Message類和Handler類,而Native層對應也有Message類和MessageHandler抽象類。在編碼時,一般使用的是MessageHandler的派生類WeakMessageHandler類。
注意 在include/media/stagfright/foundation目錄下也定義了一個ALooper類,它是供stagefright使用的類似Java消息循環的一套基礎類。這種同名類的產生,估計是兩個事先未做交流的Group的人寫的。
#### 2\. MessageQueue處理流程總結
+ MessageQueue核心邏輯下移到Native層后,極大地拓展了消息處理的范圍,總結一下有以下幾點:
+ MessageQueue繼續支持來自Java層的Message消息,也就是早期的Message加Handler的處理方式。
+ MessageQueue在Native層的代表NativeMessageQueue支持來自Native層的Message,是通過Native的Message和MessageHandler來處理的。
+ NativeMessageQueue還處理通過addFd添加的Request。在后面分析輸入系統時,還會大量碰到這種方式。
+ 從處理邏輯上看,先是Native的Message,然后是Native的Request,最后才是Java的Message。
## 2.4 本章小結
本章先對Java層的Binder架構做了一次較為深入的分析。Java層的Binder架構和Native層Binder架構類似,但是Java的Binder在通信上還是依賴Native層的Binder。建議想進一步了解Native Binder工作原理的讀者,閱讀卷I第6章“深入理解Binder”。另外,本章還對MessageQueue進行了較為深入的分析。Android 2.2中那個功能簡單的MessageQueue現在變得復雜了,原因是該類的核心邏輯下移到Native層,導致現在的MessageQueue除了支持Java層的Message派發外,還新增了支持Native Message派發以及處理來自所監控的文件句柄的事件。