[原文出處-----------Android ART運行時無縫替換Dalvik虛擬機的過程分析](http://blog.csdn.net/luoshengyang/article/details/18006645)
Android 4.4發布了一個ART運行時,準備用來替換掉之前一直使用的Dalvik虛擬機,希望籍此解決飽受詬病的性能問題。老羅不打算分析ART的實現原理,只是很有興趣知道ART是如何無縫替換掉原來的Dalvik虛擬機的。畢竟在原來的系統中,大量的代碼都是運行在Dalvik虛擬機里面的。開始覺得這個替換工作是挺復雜的,但是分析了相關代碼之后,發現思路是很清晰的。本文就詳細分析這個無縫的替換過程。
我們知道,Dalvik虛擬機實則也算是一個Java虛擬機,只不過它執行的不是class文件,而是dex文件。因此,ART運行時最理想的方式也是實現為一個Java虛擬機的形式,這樣就可以很容易地將Dalvik虛擬機替換掉。注意,我們這里說實現為Java虛擬機的形式,實際上是指提供一套完全與Java虛擬機兼容的接口。例如,Dalvik虛擬機在接口上與Java虛擬機是一致的,但是它的內部可以是完全不一樣的東西。
實際上,ART運行時就是真的和Dalvik虛擬機一樣,實現了一套完全兼容Java虛擬機的接口。為了方便描述,接下來我們就將ART運行時稱為ART虛擬機,它和Dalvik虛擬機、Java虛擬機的關系如圖1所示:

圖1 Java虛擬機、Dalvik虛擬機和ART運行時的關系
從圖1可以知道,Dalvik虛擬機和ART虛擬機都實現了三個用來抽象Java虛擬機的接口:
1. JNI_GetDefaultJavaVMInitArgs -- 獲取虛擬機的默認初始化參數
2. JNI_CreateJavaVM -- 在進程中創建虛擬機實例
3. JNI_GetCreatedJavaVMs -- 獲取進程中創建的虛擬機實例
在Android系統中,Davik虛擬機實現在libdvm.so中,ART虛擬機實現在libart.so中。也就是說,libdvm.so和libart.so導出了JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM和JNI_GetCreatedJavaVMs這三個接口,供外界調用。
此外,Android系統還提供了一個系統屬性persist.sys.dalvik.vm.lib,它的值要么等于libdvm.so,要么等于libart.so。當等于libdvm.so時,就表示當前用的是Dalvik虛擬機,而當等于libart.so時,就表示當前用的是ART虛擬機。
以上描述的Dalvik虛擬機和ART虛擬機的共同之處,當然它們之間最顯著還是不同之處。不同的地方就在于,Dalvik虛擬機執行的是dex字節碼,ART虛擬機執行的是本地機器碼。這意味著Dalvik虛擬機包含有一個解釋器,用來執行dex字節碼,具體可以參考[Dalvik虛擬機簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/8852432)這個系列的文章。當然,Android從2.2開始,也包含有JIT(Just-In-Time),用來在運行時動態地將執行頻率很高的dex字節碼翻譯成本地機器碼,然后再執行。通過JIT,就可以有效地提高Dalvik虛擬機的執行效率。但是,將dex字節碼翻譯成本地機器碼是發生在應用程序的運行過程中的,并且應用程序每一次重新運行的時候,都要做重做這個翻譯工作的。因此,即使用采用了JIT,Dalvik虛擬機的總體性能還是不能與直接執行本地機器碼的ART虛擬機相比。
那么,ART虛擬機執行的本地機器碼是從哪里來的呢?Android的運行時從Dalvik虛擬機替換成ART虛擬機,并不要求開發者要將重新將自己的應用直接編譯成目標機器碼。也就是說,開發者開發出的應用程序經過編譯和打包之后,仍然是一個包含dex字節碼的APK文件。既然應用程序包含的仍然是dex字節碼,而ART虛擬機需要的是本地機器碼,這就必然要有一個翻譯的過程。這個翻譯的過程當然不能發生應用程序運行的時候,否則的話就和Dalvik虛擬機的JIT一樣了。在計算機的世界里,與JIT相對的是AOT。AOT進Ahead-Of-Time的簡稱,它發生在程序運行之前。我們用靜態語言(例如C/C++)來開發應用程序的時候,編譯器直接就把它們翻譯成目標機器碼。這種靜態語言的編譯方式也是AOT的一種。但是前面我們提到,ART虛擬機并不要求開發者將自己的應用直接編譯成目標機器碼。這樣,將應用的dex字節碼翻譯成本地機器碼的最恰當AOT時機就發生在應用安裝的時候。
我們知道,沒有ART虛擬機之前,應用在安裝的過程,其實也會執行一次“翻譯”的過程。只不過這個“翻譯”的過程是將dex字節碼進行優化,也就是由dex文件生成odex文件。這個過程由安裝服務PackageManagerService請求守護進程installd來執行的。從這個角度來說,在應用安裝的過程中將dex字節碼翻譯成本地機器碼對原來的應用安裝流程基本上就不會產生什么影響。
有了以上的背景知識之后,我們接下來就從兩個角度來了解ART虛擬機是如何做到無縫替換Dalvik虛擬機的:
1. ART虛擬機的啟動過程;
2. Dex字節碼翻譯成本地機器碼的過程。
我們知道,Android系統在啟動的時候,會創建一個Zygote進程,充當應用程序進程孵化器。Zygote進程在啟動的過程中,又會創建一個Dalvik虛擬機。Zygote進程是通過復制自己來創建新的應用程序進程的。這意味著Zygote進程會將自己的Dalvik虛擬機復制給應用程序進程。通過這種方式就可以大大地提高應用程序的啟動速度,因為這種方式避免了每一個應用程序進程在啟動的時候都要去創建一個Dalvik。事實上,Zygote進程通過自我復制的方式來創建應用程序進程,省去的不僅僅是應用程序進程創建Dalvik虛擬機的時間,還能省去應用程序進程加載各種系統庫和系統資源的時間,因為它們在Zygote進程中已經加載過了,并且也會連同Dalvik虛擬機一起復制到應用程序進程中去。關于Zygote進程和應用程序進程啟動的更多知識,可以參考[Android系統進程Zygote啟動過程的源代碼分析](http://blog.csdn.net/luoshengyang/article/details/6768304)和[Android應用程序進程啟動過程的源代碼分析](http://blog.csdn.net/luoshengyang/article/details/6747696)這兩篇文章。
即然應用程序進程里面的Dalvik虛擬機都是從Zygote進程中復制過來的,那么接下來我們就繼續Zygote進程是如何創建Dalvik虛擬機的。從[Dalvik虛擬機的啟動過程分析](http://blog.csdn.net/luoshengyang/article/details/8885792)這篇文章可以知道,Zygote進程中的Dalvik虛擬機是從AndroidRuntime::start這個函數開始創建的。因此,接下來我們就看看這個函數的實現:
~~~
void AndroidRuntime::start(const char* className, const char* options)
{
......
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) {
return;
}
......
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
......
}
~~~
這個函數定義在文件frameworks/base/core/jni/AndroidRuntime.cpp中。
AndroidRuntime類的成員函數start最主要是做了以下三件事情:
1. 創建一個JniInvocation實例,并且調用它的成員函數init來初始化JNI環境;
2. 調用AndroidRuntime類的成員函數startVm來創建一個虛擬機及其對應的JNI接口,即創建一個JavaVM接口和一個JNIEnv接口;
3. 有了上述的JavaVM接口和JNIEnv接口之后,就可以在Zygote進程中加載指定的class了。
其中,第1件事情和第2件事情又是最關鍵的。因此,接下來我們繼續分析它們所對應的函數的實現。
JniInvocation類的成員函數init的實現如下所示:
~~~
#ifdef HAVE_ANDROID_OS
static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib";
#endif
static const char* kLibraryFallback = "libdvm.so";
bool JniInvocation::Init(const char* library) {
#ifdef HAVE_ANDROID_OS
char default_library[PROPERTY_VALUE_MAX];
property_get(kLibrarySystemProperty, default_library, kLibraryFallback);
#else
const char* default_library = kLibraryFallback;
#endif
if (library == NULL) {
library = default_library;
}
handle_ = dlopen(library, RTLD_NOW);
if (handle_ == NULL) {
if (strcmp(library, kLibraryFallback) == 0) {
// Nothing else to try.
ALOGE("Failed to dlopen %s: %s", library, dlerror());
return false;
}
// Note that this is enough to get something like the zygote
// running, we can't property_set here to fix this for the future
// because we are root and not the system user. See
// RuntimeInit.commonInit for where we fix up the property to
// avoid future fallbacks. http://b/11463182
ALOGW("Falling back from %s to %s after dlopen error: %s",
library, kLibraryFallback, dlerror());
library = kLibraryFallback;
handle_ = dlopen(library, RTLD_NOW);
if (handle_ == NULL) {
ALOGE("Failed to dlopen %s: %s", library, dlerror());
return false;
}
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
"JNI_GetCreatedJavaVMs")) {
return false;
}
return true;
}
~~~
這個函數定義在文件libnativehelper/JniInvocation.cpp中。
JniInvocation類的成員函數init所做的事情很簡單。它首先是讀取系統屬性persist.sys.dalvik.vm.lib的值。前面提到,系統屬性persist.sys.dalvik.vm.lib的值要么等于libdvm.so,要么等于libart.so。因此,接下來通過函數dlopen加載到進程來的要么是libdvm.so,要么是libart.so。無論加載的是哪一個so,都要求它導出JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM和JNI_GetCreatedJavaVMs這三個接口,并且分別保存在JniInvocation類的三個成員變量JNI_GetDefaultJavaVMInitArgs_、JNI_CreateJavaVM_和JNI_GetCreatedJavaVMs_中。這三個接口也就是前面我們提到的用來抽象Java虛擬機的三個接口。
從這里就可以看出,JniInvocation類的成員函數init實際上就是根據系統屬性persist.sys.dalvik.vm.lib來初始化Dalvik虛擬機或者ART虛擬機環境。
接下來我們繼續看AndroidRuntime類的成員函數startVm的實現:
~~~
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
......
/*
* Initialize the VM.
*
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
goto bail;
}
......
}
~~~
這個函數定義在文件frameworks/base/core/jni/AndroidRuntime.cpp中。
AndroidRuntime類的成員函數startVm最主要就是調用函數JNI_CreateJavaVM來創建一個JavaVM接口及其對應的JNIEnv接口:
~~~
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
}
~~~
這個函數定義在文件libnativehelper/JniInvocation.cpp中。
JniInvocation類的靜態成員函數GetJniInvocation返回的便是前面所創建的JniInvocation實例。有了這個JniInvocation實例之后,就繼續調用它的成員函數JNI_CreateJavaVM來創建一個JavaVM接口及其對應的JNIEnv接口:
~~~
jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
}
~~~
這個函數定義在文件libnativehelper/JniInvocation.cpp中。
JniInvocation類的成員變量JNI_CreateJavaVM_指向的就是前面所加載的libdvm.so或者libart.so所導出的函數JNI_CreateJavaVM,因此,JniInvocation類的成員函數JNI_CreateJavaVM返回的JavaVM接口指向的要么是Dalvik虛擬機,要么是ART虛擬機。
通過上面的分析,我們就很容易知道,Android系統通過將ART運行時抽象成一個Java虛擬機,以及通過系統屬性persist.sys.dalvik.vm.lib和一個適配層JniInvocation,就可以無縫地將Dalvik虛擬機替換為ART運行時。這個替換過程設計非常巧妙,因為涉及到的代碼修改是非常少的。
以上就是ART虛擬機的啟動過程,接下來我們再分析應用程序在安裝過程中將dex字節碼翻譯為本地機器碼的過程。
Android應用程序的安裝過程可以參考[Android應用程序安裝過程源代碼分析](http://blog.csdn.net/luoshengyang/article/details/Android%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B%E6%BA%90%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90)這篇文章。 簡單來說,就是Android系統通過PackageManagerService來安裝APK,在安裝的過程,PackageManagerService會通過另外一個類Installer的成員函數dexopt來對APK里面的dex字節碼進行優化:
~~~
public final class Installer {
......
public int dexopt(String apkPath, int uid, boolean isPublic) {
StringBuilder builder = new StringBuilder("dexopt");
builder.append(' ');
builder.append(apkPath);
builder.append(' ');
builder.append(uid);
builder.append(isPublic ? " 1" : " 0");
return execute(builder.toString());
}
......
}
~~~
這個函數定義在文件frameworks/base/services/java/com/android/server/pm/Installer.java中。
Installer通過socket向守護進程installd發送一個dexopt請求,這個請求是由installd里面的函數dexopt來處理的:
~~~
int dexopt(const char *apk_path, uid_t uid, int is_public)
{
struct utimbuf ut;
struct stat apk_stat, dex_stat;
char out_path[PKG_PATH_MAX];
char dexopt_flags[PROPERTY_VALUE_MAX];
char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX];
char *end;
int res, zip_fd=-1, out_fd=-1;
......
/* The command to run depend ones the value of persist.sys.dalvik.vm.lib */
property_get("persist.sys.dalvik.vm.lib", persist_sys_dalvik_vm_lib, "libdvm.so");
/* Before anything else: is there a .odex file? If so, we have
* precompiled the apk and there is nothing to do here.
*/
sprintf(out_path, "%s%s", apk_path, ".odex");
if (stat(out_path, &dex_stat) == 0) {
return 0;
}
if (create_cache_path(out_path, apk_path)) {
return -1;
}
......
out_fd = open(out_path, O_RDWR | O_CREAT | O_EXCL, 0644);
......
pid_t pid;
pid = fork();
if (pid == 0) {
......
if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) {
run_dexopt(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
} else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) {
run_dex2oat(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
} else {
exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */
}
exit(68); /* only get here on exec failure */
}
......
}
~~~
這個函數定義在文件frameworks/native/cmds/installd/commands.c中。
函數dexopt首先是讀取系統屬性persist.sys.dalvik.vm.lib的值,接著在/data/dalvik-cache目錄中創建一個odex文件。這個odex文件就是作為dex文件優化后的輸出文件。再接下來,函數dexopt通過fork來創建一個子進程。如果系統屬性persist.sys.dalvik.vm.lib的值等于libdvm.so,那么該子進程就會調用函數run_dexopt來將dex文件優化成odex文件。另一方面,如果系統屬性persist.sys.dalvik.vm.lib的值等于libart.so,那么該子進程就會調用函數run_dex2oat來將dex文件翻譯成oat文件,實際上就是將dex字節碼翻譯成本地機器碼,并且保存在一個oat文件中。
函數run_dexopt和run_dex2oat的實現如下所示:
~~~
static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
const char* output_file_name, const char* dexopt_flags)
{
static const char* DEX_OPT_BIN = "/system/bin/dexopt";
static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
char zip_num[MAX_INT_LEN];
char odex_num[MAX_INT_LEN];
sprintf(zip_num, "%d", zip_fd);
sprintf(odex_num, "%d", odex_fd);
ALOGV("Running %s in=%s out=%s\n", DEX_OPT_BIN, input_file_name, output_file_name);
execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
dexopt_flags, (char*) NULL);
ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
}
static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
const char* output_file_name, const char* dexopt_flags)
{
static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
char oat_location_arg[strlen("--oat-name=") + PKG_PATH_MAX];
sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
execl(DEX2OAT_BIN, DEX2OAT_BIN,
zip_fd_arg, zip_location_arg,
oat_fd_arg, oat_location_arg,
(char*) NULL);
ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
}
~~~
這兩個函數定義在文件frameworks/native/cmds/installd/commands.c中。
這從里就可以看出,函數run_dexopt通過調用/system/bin/dexopt來對dex字節碼進行優化,而函數run_dex2oat通過調用/system/bin/dex2oat來將dex字節碼翻譯成本地機器碼。注意,無論是對dex字節碼進行優化,還是將dex字節碼翻譯成本地機器碼,最終得到的結果都是保存在相同名稱的一個odex文件里面的,但是前者對應的是一個dey文件(表示這是一個優化過的dex),后者對應的是一個oat文件(實際上是一個自定義的elf文件,里面包含的都是本地機器指令)。通過這種方式,原來任何通過絕對路徑引用了該odex文件的代碼就都不需要修改了。
通過上面的分析,我們就很容易知道,只需要將dex文件的優化過程替換成dex文件翻譯成本地機器碼的過程,就可以輕松地在應用安裝過程,無縫地將Dalvik虛擬機替換成ART運行時。
最后,還有一個地方需要注意的是,應用程序的安裝發生在兩個時機,第一個時機是系統啟動的時候,第二個時機系統啟動完成后用戶自行安裝的時候。在第一個時機中,系統除了會對/system/app和/data/app目錄下的所有APK進行dex字節碼到本地機器碼的翻譯之外,還會對/system/framework目錄下的APK或者JAR文件,以及這些APK所引用的外部JAR,進行dex字節碼到本地機器碼的翻譯。這樣就可以保證除了應用之外,系統中使用Java來開發的系統服務,也會統一地從dex字節碼翻譯成本地機器碼。也就是說,將Android系統中的Dalvik虛擬機替換成ART運行時之后,系統中的代碼都是由ART運行時來執行的了,這時候就不會對Dalvik虛擬機產生任何的依賴。
至此,我們就分析完成ART運行時無縫替換Dalvik虛擬機的過程了,
- 前言
- Android組件設計思想
- Android源代碼開發和調試環境搭建
- Android源代碼下載和編譯
- Android源代碼情景分析法
- Android源代碼調試分析法
- 手把手教你為手機編譯ROM
- 在Ubuntu上下載、編譯和安裝Android最新源代碼
- 在Ubuntu上下載、編譯和安裝Android最新內核源代碼(Linux Kernel)
- 如何單獨編譯Android源代碼中的模塊
- 在Ubuntu上為Android系統編寫Linux內核驅動程序
- 在Ubuntu上為Android系統內置C可執行程序測試Linux內核驅動程序
- 在Ubuntu上為Android增加硬件抽象層(HAL)模塊訪問Linux內核驅動程序
- 在Ubuntu為Android硬件抽象層(HAL)模塊編寫JNI方法提供Java訪問硬件服務接口
- 在Ubuntu上為Android系統的Application Frameworks層增加硬件訪問服務
- 在Ubuntu上為Android系統內置Java應用程序測試Application Frameworks層的硬件服務
- Android源代碼倉庫及其管理工具Repo分析
- Android編譯系統簡要介紹和學習計劃
- Android編譯系統環境初始化過程分析
- Android源代碼編譯命令m/mm/mmm/make分析
- Android系統鏡像文件的打包過程分析
- 從CM刷機過程和原理分析Android系統結構
- Android系統架構概述
- Android系統整體架構
- android專用驅動
- Android硬件抽象層HAL
- Android應用程序組件
- Android應用程序框架
- Android用戶界面架構
- Android虛擬機之Dalvik虛擬機
- Android硬件抽象層
- Android硬件抽象層(HAL)概要介紹和學習計劃
- Android專用驅動
- Android Logger驅動系統
- Android日志系統驅動程序Logger源代碼分析
- Android應用程序框架層和系統運行庫層日志系統源代碼分析
- Android日志系統Logcat源代碼簡要分析
- Android Binder驅動系統
- Android進程間通信(IPC)機制Binder簡要介紹和學習計劃
- 淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路
- 淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路
- Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析
- Android系統進程間通信(IPC)機制Binder中的Client獲得Server遠程接口過程源代碼分析
- Android系統進程間通信Binder機制在應用程序框架層的Java接口源代碼分析
- Android Ashmem驅動系統
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)驅動程序源代碼分析
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)在進程間共享的原理分析
- Android系統匿名共享內存(Anonymous Shared Memory)C++調用接口分析
- Android應用程序進程管理
- Android應用程序進程啟動過程的源代碼分析
- Android系統進程Zygote啟動過程的源代碼分析
- Android系統默認Home應用程序(Launcher)的啟動過程源代碼分析
- Android應用程序消息機制
- Android應用程序消息處理機制(Looper、Handler)分析
- Android應用程序線程消息循環模型分析
- Android應用程序輸入事件分發和處理機制
- Android應用程序鍵盤(Keyboard)消息處理機制分析
- Android應用程序UI架構
- Android系統的開機畫面顯示過程分析
- Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析
- SurfaceFlinger
- Android系統Surface機制的SurfaceFlinger服務
- SurfaceFlinger服務簡要介紹和學習計劃
- 啟動過程分析
- 對幀緩沖區(Frame Buffer)的管理分析
- 線程模型分析
- 渲染應用程序UI的過程分析
- Android應用程序與SurfaceFlinger服務的關系
- 概述和學習計劃
- 連接過程分析
- 共享UI元數據(SharedClient)的創建過程分析
- 創建Surface的過程分析
- 渲染Surface的過程分析
- Android應用程序窗口(Activity)
- 實現框架簡要介紹和學習計劃
- 運行上下文環境(Context)的創建過程分析
- 窗口對象(Window)的創建過程分析
- 視圖對象(View)的創建過程分析
- 與WindowManagerService服務的連接過程分析
- 繪圖表面(Surface)的創建過程分析
- 測量(Measure)、布局(Layout)和繪制(Draw)過程分析
- WindowManagerService
- WindowManagerService的簡要介紹和學習計劃
- 計算Activity窗口大小的過程分析
- 對窗口的組織方式分析
- 對輸入法窗口(Input Method Window)的管理分析
- 對壁紙窗口(Wallpaper Window)的管理分析
- 計算窗口Z軸位置的過程分析
- 顯示Activity組件的啟動窗口(Starting Window)的過程分析
- 切換Activity窗口(App Transition)的過程分析
- 顯示窗口動畫的原理分析
- Android控件TextView的實現原理分析
- Android視圖SurfaceView的實現原理分析
- Android應用程序UI硬件加速渲染
- 簡要介紹和學習計劃
- 環境初始化過程分析
- 預加載資源地圖集服務(Asset Atlas Service)分析
- Display List構建過程分析
- Display List渲染過程分析
- 動畫執行過程分析
- Android應用程序資源管理框架
- Android資源管理框架(Asset Manager)
- Asset Manager 簡要介紹和學習計劃
- 編譯和打包過程分析
- Asset Manager的創建過程分析
- 查找過程分析
- Dalvik虛擬機和ART虛擬機
- Dalvik虛擬機
- Dalvik虛擬機簡要介紹和學習計劃
- Dalvik虛擬機的啟動過程分析
- Dalvik虛擬機的運行過程分析
- Dalvik虛擬機JNI方法的注冊過程分析
- Dalvik虛擬機進程和線程的創建過程分析
- Dalvik虛擬機垃圾收集機制簡要介紹和學習計劃
- Dalvik虛擬機Java堆創建過程分析
- Dalvik虛擬機為新創建對象分配內存的過程分析
- Dalvik虛擬機垃圾收集(GC)過程分析
- ART虛擬機
- Android ART運行時無縫替換Dalvik虛擬機的過程分析
- Android運行時ART簡要介紹和學習計劃
- Android運行時ART加載OAT文件的過程分析
- Android運行時ART加載類和方法的過程分析
- Android運行時ART執行類方法的過程分析
- ART運行時垃圾收集機制簡要介紹和學習計劃
- ART運行時Java堆創建過程分析
- ART運行時為新創建對象分配內存的過程分析
- ART運行時垃圾收集(GC)過程分析
- ART運行時Compacting GC簡要介紹和學習計劃
- ART運行時Compacting GC堆創建過程分析
- ART運行時Compacting GC為新創建對象分配內存的過程分析
- ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析
- ART運行時Mark-Compact( MC)GC執行過程分析
- ART運行時Foreground GC和Background GC切換過程分析
- Android安全機制
- SEAndroid安全機制簡要介紹和學習計劃
- SEAndroid安全機制框架分析
- SEAndroid安全機制中的文件安全上下文關聯分析
- SEAndroid安全機制中的進程安全上下文關聯分析
- SEAndroid安全機制對Android屬性訪問的保護分析
- SEAndroid安全機制對Binder IPC的保護分析
- 從NDK在非Root手機上的調試原理探討Android的安全機制
- APK防反編譯
- Android視頻硬解穩定性問題探討和處理
- Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析
- Android應用程序安裝過程源代碼分析
- Android應用程序啟動過程源代碼分析
- 四大組件源代碼分析
- Activity
- Android應用程序的Activity啟動過程簡要介紹和學習計劃
- Android應用程序內部啟動Activity過程(startActivity)的源代碼分析
- 解開Android應用程序組件Activity的"singleTask"之謎
- Android應用程序在新的進程中啟動新的Activity的方法和過程分析
- Service
- Android應用程序綁定服務(bindService)的過程源代碼分析
- ContentProvider
- Android應用程序組件Content Provider簡要介紹和學習計劃
- Android應用程序組件Content Provider應用實例
- Android應用程序組件Content Provider的啟動過程源代碼分析
- Android應用程序組件Content Provider在應用程序之間共享數據的原理分析
- Android應用程序組件Content Provider的共享數據更新通知機制分析
- BroadcastReceiver
- Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃
- Android應用程序注冊廣播接收器(registerReceiver)的過程分析
- Android應用程序發送廣播(sendBroadcast)的過程分析