· 介紹Binder系統的Java層框架 java
· 介紹MessageQueue android
· 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 app
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
以本章作爲本書Android分析之旅的開篇,將重點關注兩個基礎知識點,它們是:
· Binder系統在Java世界是如何佈局和工做的
· MessageQueue的新職責
先來分析Java層中的Binder。
建議讀者先閱讀《深刻理解Android:卷I》(如下簡稱「卷I」)的第6章「深刻理解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的方式。
雖然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]
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;
//初始化Java Parcel類和Native層的關係
if(int_register_android_os_Parcel(env) < 0)
return -1;
return0;
}
據上面的代碼可知,register_android_os_Binder函數完成了Java Binder架構中最重要的4個類的初始化工做。咱們重點關注前3個。
int_register_android_os_Binder函數完成了Binder類的初始化工做,代碼以下:
[-->android_util_Binder.cpp]
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不是很清楚,可參閱卷I第2章「深刻理解JNI」。
下一個初始化的類是BinderInternal,其代碼在int_register_android_os_BinderInternal函數中。
[-->android_util_Binder.cpp]
static intint_register_android_os_BinderInternal(JNIEnv* env)
{
jclass clazz;
//根據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函數的實現
return AndroidRuntime::registerNativeMethods(
env,kBinderInternalPathName,
gBinderInternalMethods, NELEM(gBinderInternalMethods));
}
int_register_android_os_BinderInternal的工做內容和int_register_android_os_Binder的工做內容相似:
· 獲取一些有用的methodID和fieldID。這代表JNI層必定會向上調用Java層的函數。
· 註冊相關類中native函數的實現。
int_register_android_os_BinderProxy完成了BinderProxy類的初始化工做,代碼稍顯複雜,以下所示:
[-->android_util_Binder.cpp]
static intint_register_android_os_BinderProxy(JNIEnv* env)
{
jclassclazz;
clazz =env->FindClass("java/lang/ref/WeakReference");
//gWeakReferenceOffsets用來和WeakReference類打交道
gWeakReferenceOffsets.mClass = (jclass)env->NewGlobalRef(clazz);
//獲取WeakReference類get函數的MethodID
gWeakReferenceOffsets.mGet= env->GetMethodID(clazz, "get",
"()Ljava/lang/Object;");
clazz = env->FindClass("java/lang/Error");
//gErrorOffsets用來和Error類打交道
gErrorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
clazz =env->FindClass(kBinderProxyPathName);
//gBinderProxyOffsets用來和BinderProxy類打交道
gBinderProxyOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
gBinderProxyOffsets.mConstructor= env->GetMethodID(clazz,"<init>", "()V");
...... //獲取BinderProxy的一些信息
clazz =env->FindClass("java/lang/Class");
//gClassOffsets用來和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。
這幾個對象的命名中都有一個Offsets,我以爲這很是彆扭,不知道讀者是否有同感。
框架的初始化其實就是提早獲取一些JNI層的使用信息,如類成員函數的MethodID,類成員變量的fieldID等。這項工做是必需的,由於它能節省每次使用時獲取這些信息的時間。當Binder調用頻繁時,這些時間累積起來仍是不容小覷的。
下面咱們經過一個例子來分析Java Binder的工做流程。
這個例子源自ActivityManagerService,咱們試圖經過它揭示Java層Binder的工做原理。先來描述一下該例子的分析步驟:
· 首先分析AMS如何將本身註冊到ServiceManager。
· 而後分析AMS如何響應客戶端的Binder調用請求。
本例的起點是setSystemProcess,其代碼以下所示:
[-->ActivityManagerService.java]
public static void setSystemProcess() {
try {
ActivityManagerService m = mSelf;
//將ActivityManagerService服務註冊到ServiceManager中
ServiceManager.addService("activity", m);......
}
......
return;
}
上面所示代碼行的目的是將ActivityManagerService服務加到ServiceManager中。ActivityManagerService(之後簡稱AMS)是Android核心服務中的核心,咱們之後會常常和它打交道。
你們知道,整個Android系統中有一個Native的ServiceManager(之後簡稱SM)進程,它統籌管理Android系統上的全部Service。成爲一個Service的首要條件是先在SM中註冊。下面來看Java層的Service是如何向SM註冊的。
向SM註冊服務的函數叫addService,其代碼以下:
[-->ServiceManager.java]
public static void addService(String name, IBinderservice) {
try {
//getIServiceManager返回什麼
getIServiceManager().addService(name,service);
}
......
}
//分析getIServiceManager函數
private static IServiceManagergetIServiceManager() {
......
//調用asInterface,傳遞的參數類型爲IBinder
sServiceManager= ServiceManagerNative.asInterface(
BinderInternal.getContextObject());
returnsServiceManager;
}
asInterface的參數爲BinderInternal.getContextObject的返回值。這是一個native的函數,其實現的代碼爲:
[-->android_util_Binder.cpp]
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);
}
[-->android_util_Binder.cpp]
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
*/
jobject object =(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) {
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。
你們還記得在Native層Binder中那個著名的interface_cast宏嗎?在Java層中,雖然沒有這樣的宏,可是定義了一個相似的函數asInterface。下面來分析ServiceManagerNative類的asInterface函數,其代碼以下:
[-->ServiceManagerNative.java]
static public IServiceManager asInterface(IBinderobj)
{
...... //以obj爲參數,建立一個ServiceManagerProxy對象
return new ServiceManagerProxy(obj);
}
上面代碼和Native層interface_cast很是相似,都是以一個BpProxy對象爲參數構造一個和業務相關的Proxy對象,例如這裏的ServiceManagerProxy對象。ServiceManagerProxy對象的各個業務函數會將相應請求打包後交給BpProxy對象,最終由BpProxy對象發送給Binder驅動以完成一次通訊。
提示 實際上BpProxy也不會和Binder驅動交互,真正和Binder驅動交互的是IPCThreadState。
如今來分析ServiceManagerProxy的addService函數,其代碼以下:
[-->ServcieManagerNative.java]
public void addService(String name, IBinderservice)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = 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]
static jbooleanandroid_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jintcode, 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進行通訊的。
關於Binder這套架構,筆者有一個體會願和讀者一塊兒討論分析。
從架構的角度看,在Java中搭建了一整套框架,如IBinder接口,Binder類和BinderProxy類。可是從通訊角度看,不論架構的編寫採用的是Native語言仍是Java語言,只要把請求傳遞到Binder驅動就能夠了,因此通訊的目的是向binder發送請求和接收回復。在這個目的之上,考慮到軟件的靈活性和可擴展性,因而編寫了一個架構。反過來講,也能夠不使用架構(即沒有使用任何接口、派生之類的東西)而直接和binder交互,例如ServiceManager做爲Binder的一個核心程序,就是直接讀取/dev/binder設備,獲取並處理請求。從這一點上看,Binder的目的雖是簡單的(即打開binder設備,而後讀請求和寫回復),可是架構是複雜的(編寫各類接口類和封裝類等)。咱們在研究源碼時,必定要先搞清楚目的。實現只不過是達到該目的的一種手段和方式。脫離目的的實現,如緣木求魚,很容易偏離事物本質。
在對addService進行分析時,咱們曾提示writeStrongBinder是一個特別的函數。那麼它特別在哪裏呢?
ActivityManagerService從ActivityManagerNative類派生,並實現了一些接口,其中和Binder的相關的只有這個ActivityManagerNative類,其原型以下:
[-->ActivityManagerNative.java]
public abstract class ActivityManagerNative
extends Binder
implementsIActivityManager
ActivityManagerNative從Binder派生,並實現了IActivityManager接口。下面來看ActivityManagerNative的構造函數:
[-->ActivityManagerNative.java]
public ActivityManagerNative() {
attachInterface(this, descriptor);//該函數很簡單,讀者可自行分析
}
//這是ActivityManagerNative父類的構造函數,即Binder的構造函數
public Binder() {
init();
}
Binder構造函數中會調用native的init函數,其實現的代碼以下:
[-->android_util_Binder.cpp]
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]
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]
static void android_os_Parcel_writeStrongBinder(JNIEnv*env,
jobjectclazz, jobject object)
{
//parcel是一個Native的對象,writeStrongBinder的真正參數是
//ibinderForJavaObject的返回值
conststatus_t err = parcel->writeStrongBinder(
ibinderForJavaObject(env,object));
}
[-->android_util_Binder.cpp]
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 JavaBinder、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了。
建議 對此,若是讀者有更好的解釋,不妨與你們分享一下。
初見JavaBBinde時,多少有些吃驚。回想一下Native層的Binder架構:雖然在代碼中調用的是Binder類提供的接口,但其對象倒是一個實際的服務端對象,例如MediaPlayerService對象,AudioFlinger對象。
而Java層的Binder架構中,JavaBBinder倒是一個和業務徹底無關的對象。那麼,這個對象如何實現不一樣業務呢?
爲回答此問題,咱們必須看它的onTransact函數。當收到請求時,系統會調用這個函數。
關於這個問題,建議讀者閱讀卷I第六章《深刻理解Binder》。
[-->android_util_Binder.cpp]
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函數
jboolean res = env->CallBooleanMethod(mObject,
gBinderOffsets.mExecTransact,code,
(int32_t)&data,(int32_t)reply, flags);
......
return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
就本例而言,上面代碼中的mObject就是ActivityManagerService,如今調用它的execTransact函數,該函數在Binder類中實現,具體代碼以下:
[-->Binder.java]
private boolean execTransact(int code, intdataObj, int replyObj,int flags) {
Parcel data = Parcel.obtain(dataObj);
Parcel reply = Parcel.obtain(replyObj);
boolean res;
try{
//調用onTransact函數,派生類能夠從新實現這個函數,以完成業務功能
res = onTransact(code, data, reply, flags);
}......
reply.recycle();
data.recycle();
return res;
}
}
ActivityManagerNative類實現了onTransact函數,代碼以下:
[-->ActivityManagerNative.java]
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;
}
由此能夠看出,JavaBBinder僅是一個傳聲筒,它自己不實現任何業務函數,其工做是:
· 當它收到請求時,只是簡單地調用它所綁定的Java層Binder對象的exeTransact。
· 該Binder對象的exeTransact調用其子類實現的onTransact函數。
· 子類的onTransact函數將業務又派發給其子類來完成。請讀者務必注意其中的多層繼承關係。
經過這種方式,來自客戶端的請求就能傳遞到正確的Java Binder對象了。圖2-3展現AMS響應請求的整個流程。
圖2-3 AMS響應請求的流程
圖2-3中,右上角的大方框表示AMS這個對象,其間的虛線箭頭表示調用子類重載的函數。
圖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」。
卷I第5章介紹過,MessageQueue類封裝了與消息隊列有關的操做。在一個以消息驅動的系統中,最重要的兩部分就是消息隊列和消息處理循環。在Andrid 2.3之前,只有Java世界的居民有資格向MessageQueue中添加消息以驅動Java世界的正常運轉,但從Android 2.3開始,MessageQueue的核心部分下移至Native層,讓Native世界的居民也能利用消息循環來處理他們所在世界的事情。所以如今的MessageQueue心繫Native和Java兩個世界。
如今來分析MessageQueue是如何跨界工做的,其代碼以下:
[-->MessageQueue.java]
MessageQueue() {
nativeInit(); //構造函數調用nativeInit,該函數由Native層實現
}
nativeInit函數的真正實現爲android_os_MessageQueue_nativeInit,其代碼以下:
[-->android_os_MessageQueue.cpp]
static voidandroid_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
//NativeMessageQueue是MessageQueue在Native層的表明
NativeMessageQueue*nativeMessageQueue = new NativeMessageQueue();
......
//將這個NativeMessageQueue對象設置到Java層保存
android_os_MessageQueue_setNativeMessageQueue(env,obj,
nativeMessageQueue);
}
nativeInit函數在Native層建立了一個與MessageQueue對應的NativeMessageQueue對象,其構造函數以下:
[-->android_os_MessageQueue.cpp]
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類同樣,但此兩者其實並沒有任何關係。這一點之後還將詳細分析。
當一切準備就緒後,Java層的消息循環處理,也就是Looper會在一個循環中提取並處理消息。消息的提取就是調用MessageQueue的next函數。當消息隊列爲空時,next就會阻塞。MessageQueue同時支持Java層和Native層的事件,那麼其next函數該怎麼實現呢?具體代碼以下:
[-->MessagQueue.java]
final Message next() {
intpendingIdleHandlerCount = -1;
intnextPollTimeoutMillis = 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工做的正常流程。
MessageQueue的enqueueMessage函數完成將一個Message投遞到MessageQueue中的工做,其代碼以下:
[-->MesssageQueue.java]
final boolean enqueueMessage(Message msg, longwhen) {
......
final boolean 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);
}
return true;
}
上面的代碼比較簡單,主要功能是:
· 將message按執行時間排序,並加入消息隊。
· 根據狀況調用nativeWake函數,以觸發nativePollOnce函數,結束等待。
建議 雖然代碼簡單,可是對於那些不熟悉多線程的讀者,仍是要細細品味一下mBlocked值的做用。咱們常說細節體現美,代碼也同樣,這個小小的mBlocked正是如此。
nativeWake函數的代碼以下所示:
[-->android_os_MessageQueue.cpp]
static voidandroid_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj,
jint ptr)
{
NativeMessageQueue*nativeMessageQueue = //取出NativeMessageQueue對象
reinterpret_cast<NativeMessageQueue*>(ptr);
returnnativeMessageQueue->wake(); //調用它的wake函數
}
void NativeMessageQueue::wake() {
mLooper->wake();//層層調用,如今轉到mLooper的wake函數
}
Native Looper的wake函數代碼以下:
[-->Looper.cpp]
void Looper::wake() {
ssize_tnWrite;
do {
//向管道的寫端寫入一個字符
nWrite = write(mWakeWritePipeFd, "W", 1);
} while(nWrite == -1 && errno == EINTR);
if(nWrite != 1) {
if(errno != EAGAIN) {
LOGW("Could not write wake signal, errno=%d", errno);
}
}
}
wake函數則更爲簡單,僅僅向管道的寫端寫入一個字符」W」,這樣管道的讀端就會由於有數據可讀而從等待狀態中醒來。
nativePollOnce的實現函數是android_os_MessageQueue_nativePollOnce,代碼以下:
[-->android_os_MessageQueue.cpp]
static void android_os_MessageQueue_nativePollOnce(JNIEnv*env, jobject obj,
jintptr, jint timeoutMillis)
NativeMessageQueue*nativeMessageQueue =
reinterpret_cast<NativeMessageQueue*>(ptr);
//取出NativeMessageQueue對象,並調用它的pollOnce
nativeMessageQueue->pollOnce(timeoutMillis);
}
//分析pollOnce函數
void NativeMessageQueue::pollOnce(inttimeoutMillis) {
mLooper->pollOnce(timeoutMillis); //重任傳遞到Looper的pollOnce函數
}
Looper的pollOnce函數以下:
[-->Looper.cpp]
inline int pollOnce(int timeoutMillis) {
return pollOnce(timeoutMillis, NULL, NULL, NULL);
}
上面的函數將調用另一個有4個參數的pollOnce函數,這個函數的原型以下:
int pollOnce(int timeoutMillis, int* outFd, int*outEvents, void** outData)
其中:
· timeOutMillis參數爲超時等待時間。若是爲-1,則表示無限等待,直到有事件發生爲止。若是值爲0,則無需等待當即返回。
· outFd用來存儲發生事件的那個文件描述符①。
· outEvents用來存儲在該文件描述符[①]上發生了哪些事件,目前支持可讀、可寫、錯誤和中斷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的狀況。
epoll機制提供了Linux平臺上最高效的I/O複用機制,所以有必要介紹一下它的基礎知識。
從調用方法上看,epoll的用法和select/poll很是相似,其主要做用就是I/O複用,即在一個地方等待多個文件句柄的I/O事件。
下面經過一個簡單例子來分析epoll的工做流程。
[-->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句柄中。
*/
structepoll_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_eventresultEvents[10];
inttimeout = -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發生了錯誤
}
elseif(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呢?
關於這個問題的答案,可參見筆者一篇博文「隨筆之如何實現一個線程池」。[②]
下面分析帶4個參數的pollOnce函數,代碼以下:
[-->Looper.cpp]
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]
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
//從這裏也可看出NativeMessage和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函數返回,這時候可能有三種狀況:
m 發生錯誤,則跳轉到Done處。
m 超時,這時候也跳轉到Done處。
m epoll_wait監測到某些文件句柄上有事件發生。
· 假設epoll_wait由於文件句柄有事件而返回,此時須要根據文件句柄來分別處理:
m 若是是管道讀這一端有事情,則認爲是控制命令,能夠直接讀取管道中的數據。
m 若是是其餘FD發生事件,則根據Request構造Response,並push到Response數組中。
· 真正開始處理事件是在有Done標誌的位置。
m 首先處理Native的Message。調用Native Handler的handleMessage處理該Message。
m 處理Response數組中那些帶有callback的事件。
上面的處理流程仍是比較清晰的,但仍是有個一個攔路虎,那就是mRequests,下面就來清剿這個攔路虎。
添加監控請求其實就是調用epoll_ctl增長文件句柄。下面經過從Native的Activity找到的一個例子來分析mRequests。
[-->android_app_NativeActivity.cpp]
static jint
loadNativeCode_native(JNIEnv* env, jobject clazz,jstring path,
jstring funcName,jobject messageQueue,
jstring internalDataDir, jstring obbDir,
jstring externalDataDir, int sdkVersion,
jobject jAssetMgr, jbyteArraysavedState)
{
......
/*
調用Looper的addFd函數。第一個參數表示監聽的fd;第二個參數0表示ident;
第三個參數表示須要監聽的事件,這裏爲只監聽可讀事件;第四個參數爲回調函數,當該fd發生
指定事件時,looper將回調該函數;第五個參數code爲回調函數的參數
*/
code->looper->addFd(code->mainWorkRead,0,
ALOOPER_EVENT_INPUT,mainWorkCallback, code);
......
}
Looper的addFd代碼以下所示:
[-->Looper.cpp]
int Looper::addFd(int fd, int ident, int events,
ALooper_callbackFunccallback, void* data) {
if (!callback) {
//判斷該Looper是否支持不帶回調函數的文件句柄添加。通常不支持,由於沒有回調函數
//Looper也不知道如何處理該文件句柄上發生的事情
if(! mAllowNonCallbacks) {
return -1;
}
......
}
#ifdefLOOPER_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;
}
咱們發如今pollInner函數中,當某個監控fd上發生事件後,就會把對應的Request取出來調用。
pushResponse(events, mRequests.itemAt(i));
此函數以下:
[-->Looper.cpp]
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。
Android 2.2中只有Java層才能夠經過sendMessage往MessageQueue中添加消息,從4.0開始,Native層也支持sendMessage了[③]。sendMessage的代碼以下:
[-->Looper.cpp]
void Looper::sendMessage(constsp<MessageHandler>& handler,
constMessage& message) {
//Native的sendMessage函數必須同時傳遞一個Handler
nsecs_tnow = systemTime(SYSTEM_TIME_MONOTONIC);
sendMessageAtTime(now, handler, message); //調用sendMessageAtTime
}
void Looper::sendMessageAtTime(nsecs_t uptime,
const sp<MessageHandler>& handler,
const Message& message) {
size_t i= 0;
{ //acquire lock
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();
}
}
想不到,一個小小的MessageQueue居然有如此多的內容。在後面分析Android輸入系統時,咱們會再次在Native層和MessageQueue碰面,這裏僅是爲後面的相會打下必定的基礎。
如今,咱們將站在一個比具體代碼更高的層次來認識一下MessageQueue和它的夥伴們。
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的人寫的。
MessageQueue核心邏輯下移到Native層後,極大地拓展了消息處理的範圍,總結一下有如下幾點:
· MessageQueue繼續支持來自Java層的Message消息,也就是早期的Message加Handler的處理方式。
· MessageQueue在Native層的表明NativeMessageQueue支持來自Native層的Message,是經過Native的Message和MessageHandler來處理的。
· NativeMessageQueue還處理經過addFd添加的Request。在後面分析輸入系統時,還會大量碰到這種方式。
· 從處理邏輯上看,先是Native的Message,而後是Native的Request,最後纔是Java的Message。
對Java程序員來講,之前單純的MessageQueue開始變得複雜。有同事常常與筆者討論,cpu並非很忙,爲何sendMessage的消息好久後才執行?是的,對於只瞭解MessageQueue Java層的工做人員,這個問題仍是沒辦法回答。由於MessageQueue在Native層的兄弟NativeMessageQueue可能正在處理一個Native的Message,而Java的調用堆棧信息又不能打印Native層的活動,因此這個對Java程序員來講看上去很面善的MessageQueue,仍是讓筆者爲某些只沉迷於Java語言的同仁們感到擔憂。
本章先對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派發以及處理來自所監控的文件句柄的事件。