AppRuntime類的聲明和實現均在App_main.cpp中,它是從AndroidRuntime類派生出來的,圖4-1顯示了這兩個類的關系和一些重要函數:
:-: 
圖4-1 AppRuntime和AndroidRuntime的關系
由上圖我們可知:
- AppRuntime重載了onStarted、onZygoteInit和onExit函數。
前面的代碼中調用了AndroidRuntime的start函數,由圖4-1可知,這個start函數使用的是基類AndroidRuntime的start,我們來分析一下它,注意它的調用參數。
**AndroidRuntime.cpp**
~~~
void AndroidRuntime::start(const char*className, const bool startSystemServer)
{
//className的值是"com.android.internal.os.ZygoteInit"
//startSystemServer的值是true
char*slashClassName = NULL;
char*cp;
JNIEnv* env;
blockSigpipe();//處理SIGPIPE信號
......
constchar* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
//如果環境變量中沒有ANDROID_ROOT,則新增該變量,并設置值為“/system"
rootDir = “/system";
......
setenv("ANDROID_ROOT", rootDir, 1);
}
//① 創建虛擬機
if(startVm(&mJavaVM, &env) != 0)
goto bail;
//②注冊JNI函數
if(startReg(env) < 0) {
goto bail;
}
jclassstringClass;
jobjectArray strArray;
jstring classNameStr;
jstring startSystemServerStr;
stringClass = env->FindClass("java/lang/String");
//創建一個有兩個元素的String數組,即Java代碼 String strArray[] = new String[2]
strArray = env->NewObjectArray(2, stringClass, NULL);
classNameStr = env->NewStringUTF(className);
//設置第一個元素為"com.android.internal.os.ZygoteInit"
env->SetObjectArrayElement(strArray, 0, classNameStr);
startSystemServerStr = env->NewStringUTF(startSystemServer ?
"true" : "false");
//設置第二個元素為"true",注意這兩個元素都是String類型,即字符串。
env->SetObjectArrayElement(strArray, 1, startSystemServerStr);
jclassstartClass;
jmethodID startMeth;
slashClassName = strdup(className);
/*
將字符串“com.android.internal.os.ZygoteInit”中的“. ”換成“/”,
這樣就變成了“com/android/internal/os/ZygoteInit”,這個名字符合JNI規范,
我們可將其簡稱為ZygoteInit類。
*/
for(cp = slashClassName; *cp != '\0'; cp++)
if(*cp == '.')
*cp = '/';
startClass = env->FindClass(slashClassName);
......
//找到ZygoteInit類的static main函數的jMethodId。
startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
......
/*
③通過JNI調用Java函數,注意調用的函數是main,所屬的類是
com.android.internal.os.ZygoteInit,傳遞的參數是
“com.android.internal.os.ZygoteInit true”,
調用ZygoteInit的main函數后,Zygote便進入了Java世界!
也就是說,Zygote是開創Android系統中Java世界的盤古。
*/
env->CallStaticVoidMethod(startClass,startMeth, strArray);
//Zygote退出,在正常情況下,Zygote不需要退出。
if(mJavaVM->DetachCurrentThread() != JNI_OK)
LOGW("Warning: unable to detach main thread\n");
if(mJavaVM->DestroyJavaVM() != 0)
LOGW("Warning: VM did not shut down cleanly\n");
bail:
free(slashClassName);
}
~~~
通過上面的分析,我們找到了三個關鍵點,它們共同組成了開創Android系統中Java世界的三部曲。現在讓我們來具體地觀察它們。
1. 創建虛擬機——startVm
我們先看三部曲中的第一部:startVm,這個函數沒有特別之處,就是調用JNI的虛擬機創建函數,但是虛擬機創建時的一些參數卻是在startVm中被確定的,其代碼如下所示:
**AndroidRuntime.cpp**
~~~
int AndroidRuntime::startVm(JavaVM** pJavaVM,JNIEnv** pEnv)
{
//這個函數絕大部分代碼都是設置虛擬機的參數,我們只分析其中的兩個。
/*
下面的代碼是用來設置JNI check選項的。JNIcheck 指的是Native層調用JNI函數時,
系統所做的一些檢查工作。例如調用NewUTFString函數時,系統會檢查傳入的字符串是不是符合
UTF-8的要求。JNI check還能檢查資源是否正確釋放。但這個選項也有其副作用,比如:
1)因為檢查工作比較耗時,所以會影響系統運行速度。
2)有些檢查過于嚴格,例如上面的字符串檢查,一旦出錯,則調用進程就會abort。
所以,JNI check選項一般只在調試的eng版設置,而正式發布的user版則不設置該選項。
下面這幾句代碼就控制著是否啟用JNI check,這是由系統屬性決定的,eng版如經過特殊配置,也可以去掉JNI check。
*/
property_get("dalvik.vm.checkjni",propBuf, "");
if(strcmp(propBuf, "true") == 0) {
checkJni = true;
} elseif (strcmp(propBuf, "false") != 0) {
property_get("ro.kernel.android.checkjni",propBuf, "");
if(propBuf[0] == '1') {
checkJni = true;
}
}
......
/*
設置虛擬機heapsize,默認為16MB。絕大多數廠商都會修改這個值,一般是32MB。
heapsize不能設置過小,否則在操作大尺寸的圖片時無法分配所需內存。
這里有一個問題,即heapsize既然是系統級的屬性,那么能否根據不同應用程序的需求來進行動
態調整?我開始也考慮過能否實現這一構想,不過希望很快就破滅了。對這一問題,我們將在拓展
部分深入討論。
*/
strcpy(heapsizeOptsBuf, "-Xmx");
property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
if(checkJni) {
opt.optionString ="-Xcheck:jni";
mOptions.add(opt);
//JNIcheck中的資源檢查,系統中創建的Globalreference個數不能超過2000
opt.optionString = "-Xjnigreflimit:2000";
mOptions.add(opt);
}
// 調用JNI_CreateJavaVM創建虛擬機,pEnv返回當前線程的JNIEnv變量
if(JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
LOGE("JNI_CreateJavaVM failed\n");
goto bail;
}
result= 0;
bail:
free(stackTraceFile);
returnresult;
}
~~~
關于dalvik虛擬機的詳細參數,讀者可以參見Dalvik/Docs/Dexopt.html中的說明。這個Docs目錄下的內容,或許可幫助我們更深入地了解dalvik虛擬機。
2. 注冊JNI函數——startReg
前面已經介紹了如何創建虛擬機,下一步則需要給這個虛擬機注冊一些JNI函數。正是因為后續Java世界用到的一些函數是采用native方式來實現的,所以才必須提前注冊這些函數。
下面我們來看看這個startReg函數,代碼如下所示:
**AndroidRuntime.cpp**
~~~
int AndroidRuntime::startReg(JNIEnv* env)
{
//注意,設置Thread類的線程創建函數為javaCreateThreadEtc
//它的作用,將在對Thread分析一部分(第5章)中做詳細介紹。
androidSetCreateThreadFunc((android_create_thread_fn)javaCreateThreadEtc);
env->PushLocalFrame(200);
//注冊jni函數,gRegJNI是一個全局數組。
if(register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
//下面這句話應當是“碼農”休閑時的小把戲。在日新月異的IT世界中,它現已絕對是“文物”了。
//createJavaThread("fubar", quickTest, (void*)"hello");
return0;
}
~~~
我們來看看register_jni_procs,代碼如下所示:
**AndroidRuntime.cpp**
~~~
static int register_jni_procs(const RegJNIRecarray[], size_t count, JNIEnv* env)
{
for(size_t i = 0; i < count; i++) {
if(array[i].mProc(env) < 0) {//僅僅是一個封裝,調用數組元素的mProc函數
return -1;
}
}
return 0;
}
~~~
上面的函數調用的不過是數組元素的mProc函數,再讓我們直接看看這個全局數組的gRegJNI變量。
**AndroidRuntime.cpp::gRegJNI聲明**
~~~
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_debug_JNITest),
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
...//共有100項
};
~~~
REG_JNI是一個宏,宏里邊包括的就是那個mProc函數,這里,我們來分析一個例子。
**android_debug_JNITest.cpp**
~~~
int register_android_debug_JNITest(JNIEnv* env)
{
//為android.debug.JNITest類注冊它所需要的JNI函數
returnjniRegisterNativeMethods(env, "android/debug/JNITest",
gMethods,NELEM(gMethods));
}
~~~
哦,原來mProc就是為Java類注冊JNI函數!
至此,虛擬機已創建好,JNI函數也已注冊,下一步就要分析CallStaticVoidMethod了。通過這個函數,我們將進入Android所精心打造的Java世界,而且最佳情況是,永遠也不回到Native世界。
- 前言
- 第1章 閱讀前的準備工作
- 1.1 系統架構
- 1.1.1 Android系統架構
- 1.1.2 本書的架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.3 工具介紹
- 1.3.1 Source Insight介紹
- 1.3.2 Busybox的使用
- 1.4 本章小結
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 學習JNI的實例:MediaScanner
- 2.3 Java層的MediaScanner分析
- 2.3.1 加載JNI庫
- 2.3.2 Java的native函數和總結
- 2.4 JNI層MediaScanner的分析
- 2.4.1 注冊JNI函數
- 2.4.2 數據類型轉換
- 2.4.3 JNIEnv介紹
- 2.4.4 通過JNIEnv操作jobject
- 2.4.5 jstring介紹
- 2.4.6 JNI類型簽名介紹
- 2.4.7 垃圾回收
- 2.4.8 JNI中的異常處理
- 2.5 本章小結
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 屬性服務
- 3.3 本章小結
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 關于zygote的總結
- 4.3 SystemServer分析
- 4.3.1 SystemServer的誕生
- 4.3.2 SystemServer的重要使命
- 4.3.3 關于 SystemServer的總結
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService發送請求
- 4.4.2 有求必應之響應請求
- 4.4.3 關于zygote分裂的總結
- 4.5 拓展思考
- 4.5.1 虛擬機heapsize的限制
- 4.5.2 開機速度優化
- 4.5.3 Watchdog分析
- 4.6 本章小結
- 第5章 深入理解常見類
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初識影子對象
- 5.2.2 第二板斧--由弱生強
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 輕量級的引用計數控制類LightRefBase
- 5.2.5 題外話-三板斧的來歷
- 5.3 Thread類及常用同步類分析
- 5.3.1 一個變量引發的思考
- 5.3.2 常用同步類
- 5.4 Looper和Handler類分析
- 5.4.1 Looper類分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步關系
- 5.4.4 HandlerThread介紹
- 5.5 本章小結
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函數
- 6.2.2 獨一無二的ProcessState
- 6.2.3 時空穿越魔術-defaultServiceManager
- 6.2.4 注冊MediaPlayerService
- 6.2.5 秋風掃落葉-StartThread Pool和join Thread Pool分析
- 6.2.6 你徹底明白了嗎
- 6.3 服務總管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服務的注冊
- 6.3.3 ServiceManager存在的意義
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查詢ServiceManager
- 6.4.2 子承父業
- 6.5 拓展思考
- 6.5.1 Binder和線程的關系
- 6.5.2 有人情味的訃告
- 6.5.3 匿名Service
- 6.6 學以致用
- 6.6.1 純Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小結
- 第7章 深入理解Audio系統
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介紹
- 7.2.2 AudioTrack(Java空間)分析
- 7.2.3 AudioTrack(Native空間)分析
- 7.2.4 關于AudioTrack的總結
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的誕生
- 7.3.2 通過流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 關于AudioFlinger的總結
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的創建
- 7.4.2 重回AudioTrack
- 7.4.3 聲音路由切換實例分析
- 7.4.4 關于AudioPolicy的總結
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 題外話
- 7.6 本章小結
- 第8章 深入理解Surface系統
- 8.1 概述
- 8.2 一個Activity的顯示
- 8.2.1 Activity的創建
- 8.2.2 Activity的UI繪制
- 8.2.3 關于Activity的總結
- 8.3 初識Surface
- 8.3.1 和Surface有關的流程總結
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI層分析
- 8.3.4 Surface和畫圖
- 8.3.5 初識Surface小結
- 8.4 深入分析Surface
- 8.4.1 與Surface相關的基礎知識介紹
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface對象的創建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介紹
- 8.4.7 深入分析Surface的總結
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的誕生
- 8.5.2 SF工作線程分析
- 8.5.3 Transaction分析
- 8.5.4 關于SurfaceFlinger的總結
- 8.6 拓展思考
- 8.6.1 Surface系統的CB對象分析
- 8.6.2 ViewRoot的你問我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小結
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理與機制分析
- 9.2.1 Netlink和Uevent介紹
- 9.2.2 初識Vold
- 9.2.3 NetlinkManager模塊分析
- 9.2.4 VolumeManager模塊分析
- 9.2.5 CommandListener模塊分析
- 9.2.6 Vold實例分析
- 9.2.7 關于Vold的總結
- 9.3 Rild的原理與機制分析
- 9.3.1 初識Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 關于Rild main函數的總結
- 9.3.6 Rild實例分析
- 9.3.7 關于Rild的總結
- 9.4 拓展思考
- 9.4.1 嵌入式系統的存儲知識介紹
- 9.4.2 Rild和Phone的改進探討
- 9.5 本章小結
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模塊分析
- 10.2.2 MSS模塊分析
- 10.2.3 android.process.media媒體掃描工作的流程總結
- 10.3 MediaScanner分析
- 10.3.1 Java層分析
- 10.3.2 JNI層分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 關于MediaScanner的總結
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介紹
- 10.4.2 我問你答
- 10.5 本章小結