android 开发art,Android应用开发之Android 系统启动原理(art 虚拟机)
本文將帶你了解Android應(yīng)用開(kāi)發(fā)之Android 系統(tǒng)啟動(dòng)原理(art 虛擬機(jī)),希望本文對(duì)大家學(xué)Android有所幫助。
Android ? 系統(tǒng)啟動(dòng)原理(art 虛擬機(jī))
一、虛擬機(jī)的啟動(dòng)
Android 是一個(gè) Linux 的虛擬機(jī),當(dāng)虛擬機(jī)啟動(dòng)的時(shí)候,會(huì)執(zhí)行手機(jī)根目錄下的 init.rc(實(shí)際上就是 .sh 文件) 這個(gè)可執(zhí)行文件。
在 init.rc 中,有一行 on init 執(zhí)行命令。這是調(diào)用 init.rc 同級(jí)文件 init ,init 是所有安卓手機(jī)的入口執(zhí)行文件,無(wú)法打開(kāi)查看,是亂碼。
xpose 的強(qiáng)大功能,就是對(duì) init 進(jìn)行 ? hook,然后修改。但是替換 init 這個(gè)文件是需要 root 權(quán)限的,所以使用 xpose 這個(gè)框架,是需要進(jìn)行 root 的。
1.init 源碼
inti 文件的源碼是在 \system\core\init 這個(gè)文件夾下,會(huì)把里面所有的東西編譯成 init 這個(gè)可執(zhí)行文件,各個(gè)手機(jī)廠商會(huì)對(duì)這塊文件進(jìn)行修改。
init 的唯一入口是改文件夾下的 init.cpp 這個(gè)文件,里面有一個(gè) main 函數(shù),處理環(huán)境變量,開(kāi)啟服務(wù),渲染等。
main 部分代碼:
?1234567891011121314// If we're in the kernel ? domain, re-exec init to transition to the init domain now// that the SELinux ? policy has been loaded.if (is_first_stage) {????if ? (restorecon("/init") == -1) {????????ERROR("restorecon ? failed: %s\n", ? strerror(errno));????????security_failure();????}????char* ? path = argv[0];????char* args[] = { path, ? const_cast("--second-stage"), nullptr ? };????if (execv(path, args) == -1) ? {????????ERROR("execv(\"%s\") ? failed: %s\n", path, strerror(errno));????????security_failure();????}}
代碼中的 path 是指系統(tǒng)定義好的一些環(huán)境變量,這些路徑是 ? \frameworks\base\cmds 下的所有東西。
所以在這里是判斷是否是第一次啟動(dòng),如果是第一次啟動(dòng),則會(huì)執(zhí)行 \frameworks\base\cmds 下所有的可執(zhí)行文件,包括開(kāi)啟虛擬機(jī)的文件 app_process。
2.app_process 源碼
\frameworks\base\cmds\app_process 下有個(gè) app_main.cpp 文件,里面就是 app_process 源碼。
app_process 部分代碼:
?12345678910if (zygote) ? {????runtime.start("com.android.internal.os.ZygoteInit", ? args, zygote);} else if (className) ? {????runtime.start("com.android.internal.os.RuntimeInit", ? args, zygote);} else {????fprintf(stderr, "Error: no ? class name or --zygote ? supplied.\n");????app_usage();????LOG_ALWAYS_FATAL("app_process: ? no class name or --zygote supplied.");????return ? 10;}
在 app_main 里面的 main 方法最后,調(diào)用了 runtime.start(“com.android.internal.os.ZygoteInit”, args, ? zygote);
點(diǎn)擊查看 run 是第一 AppRuntime。
所以 app_process 調(diào)用了 ? com.android.internal.os.ZygoteInit 這個(gè)類,這是第一個(gè)被調(diào)用的 java 類。對(duì)應(yīng)源碼位置是 \frameworks\base\core\java\com\android\internal\os
3.AndroidRuntime
AppRuntime 繼承于 AndroidRuntime,AndroidRuntime 位于\frameworks\base\core\jni。
start 部分代碼:
?123if (startVm(&mJavaVM, &env, zygote) ? != 0) {????return;}
在 AndroidRuntime 的 start 方法中,調(diào)用了 startVm,這個(gè)方法,這個(gè)方法才是真正的去開(kāi)啟虛擬機(jī)。手機(jī)啟動(dòng)的時(shí)候只是開(kāi)啟 Linux 系統(tǒng),當(dāng)執(zhí)行到這里的時(shí)候,Linux 系統(tǒng)開(kāi)啟安卓運(yùn)行的虛擬機(jī)。
startVm 部分代碼:
?1234567891011/*?* 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");????return -1;}
在 startVm 末尾調(diào)用 JNI_CreateJavaVM,去創(chuàng)建一個(gè)虛擬機(jī)。
4.JNI_CreateJavaVM
JNI_CreateJavaVM 方法位于 \art\runtime\jni_internal.cc 文件中。
JNI_CreateJavaVM :
?1234567891011121314151617181920212223242526272829// ? JNI Invocation interface.?extern "C" jint ? JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) ? {??const JavaVMInitArgs* args = ? static_cast(vm_args);??if ? (IsBadJniVersion(args->version)) {????LOG(ERROR) ? << "Bad JNI version passed to CreateJavaVM: " << ? args->version;????return ? JNI_EVERSION;??}??Runtime::Options ? options;??for (int i = 0; i < args->nOptions; ++i) ? {????JavaVMOption* option = ? &args->options[i];????options.push_back(std::make_pair(std::string(option->optionString), ? option->extraInfo));??}??bool ignore_unrecognized = ? args->ignoreUnrecognized;??if (!Runtime::Create(options, ? ignore_unrecognized)) {????return ? JNI_ERR;??}??Runtime* runtime = Runtime::Current();??bool ? started = runtime->Start();??if (!started) ? {????delete ? Thread::Current()->GetJniEnv();????delete ? runtime->GetJavaVM();????LOG(WARNING) << "CreateJavaVM ? failed";????return ? JNI_ERR;??}??*p_env = ? Thread::Current()->GetJniEnv();??*p_vm = ? runtime->GetJavaVM();??return JNI_OK;}
其中最主要的最后兩行代碼,實(shí)例化了 ? p_env 和 p_vm ,p_env 就是我們編寫(xiě) jni 方法的第一個(gè)參數(shù) JNIEnv *env ,p_vm 就是虛擬機(jī)。
//JNIEnv *env 實(shí)例化
*p_env = Thread::Current()->GetJniEnv();
//實(shí)例化虛擬機(jī)的地方
*p_vm = runtime->GetJavaVM();
注:虛擬機(jī)在 Linux 就是一個(gè)結(jié)構(gòu)體的方式保存著。
5.p_env
GetJniEnv() 這個(gè)函數(shù)定義在文件 \art\runtime 下的 thread.h 中。
* thread.h *
?1234567// Every thread may have an associated ? JNI environmentJNIEnvExt* jni_env_;?// JNI methodsJNIEnvExt* GetJniEnv() ? const {??return jni_env_;}
JNI 方法的第一個(gè)參數(shù)是 JNIEnv,JNIEnv ? 是一個(gè)接口, JNIEnvExt 是 JNIEnv子類。
二、加載 java 文件
在 ? \frameworks\base\core\jni\AndroidRuntime 中繼續(xù)往下,會(huì)發(fā)現(xiàn)加載 java 類,實(shí)際上是調(diào)用 env->FindClass(slashClassName) 進(jìn)行加載的。(java 中 雙親委托機(jī)制 ClassLoader 進(jìn)行加載 java 文件,最底層的實(shí)現(xiàn)也是使用 FindClass 這個(gè)方法)
1.FindClass
FindClass 是在 libnativehelper\include\nativehelper\jni.h 中,
jni.h 下 FindClass :
jclass FindClass(const char* name){ return ? functions->FindClass(this, name); }
這里的 functions 是 JNINativeInterface,最終調(diào)用的是 \art\runtime\jni_internal.cc ? 下的 FindClass 。
\jni_internal.cc 下 FindClass:
static jclass ? FindClass(JNIEnv* env, const char* name) ? {??CHECK_NON_NULL_ARGUMENT(name);??Runtime* runtime = ? Runtime::Current();??ClassLinker* class_linker = ? runtime->GetClassLinker();??std::string ? descriptor(NormalizeJniClassDescriptor(name));??ScopedObjectAccess ? soa(env);??mirror::Class* c = nullptr;??//判斷虛擬機(jī)是否開(kāi)啟??if ? (runtime->IsStarted()) {????StackHandleScope<1>? hs(soa.Self());????Handleclass_loader(hs.NewHandle(GetClassLoader(soa)));????c = ? class_linker->FindClass(soa.Self(), descriptor.c_str(), ? class_loader);??} else {????//還沒(méi)開(kāi)啟虛擬機(jī),即加載的是系統(tǒng)的類????c ? = class_linker->FindSystemClass(soa.Self(), ? descriptor.c_str());??}??return ? soa.AddLocalReference(c);}
最終程序調(diào)用到 class_linker 的 FindClass 方法進(jìn)行加載類。
2. class_linker 的 FindClass
class_linker 所在目錄 \art\runtime 下有一個(gè) class_linker.cc 文件,找到里面的 FindClass 方法。
FindClass 部分代碼:
if (pair.second != nullptr) {??return ? DefineClass(self,?????????????????????descriptor,?????????????????????hash,?????????????????????ScopedNullHandle(),?????????????????????*pair.first,?????????????????????*pair.second);}
在這邊調(diào)用了 DefineClass。
DefineClass 部分代碼:
// Add the newly loaded class to the loaded ? classes table.mirror::Class* existing = InsertClass(descriptor, klass.Get(), ? hash);if (existing != nullptr) {??// We failed to insert because we ? raced with another thread. Calling EnsureResolved may cause??// ? this thread to block.??return EnsureResolved(self, descriptor, ? existing);}?// Load the fields and other things after we are inserted in ? the table. This is so that we don't// end up allocating unfree-able linear ? alloc resources and then lose the race condition. The// other reason is that ? the field roots are only visited from the class table. So we need to be// ? inserted before we allocate / fill in these fields.LoadClass(self, dex_file, ? dex_class_def, klass);
這是調(diào)用了兩個(gè)比較重要的方法, ? InsertClass 和 LoadClass。
InsertClass(descriptor, klass.Get(), hash); 有一個(gè)參數(shù)是 hash,這樣會(huì)把類進(jìn)行緩存,在 DefineClass 執(zhí)行 InsertClass 之前,會(huì)先進(jìn)行這個(gè)判斷,如果已經(jīng)加載的就不再進(jìn)行加載。
LoadClass(self, dex_file, dex_class_def, klass); ? 是真正的去進(jìn)行加載 Class。
LoadClass:
void ? ClassLinker::LoadClass(Thread* ? self,????????????????????????????const ? DexFile& ? dex_file,????????????????????????????const ? DexFile::ClassDef& dex_class_def,????????????????????????????Handleklass) {??const uint8_t* class_data = ? dex_file.GetClassData(dex_class_def);??if (class_data == nullptr) ? {????return;? // no fields or methods - for example ? a marker interface??}??bool has_oat_class = ? false;??if (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) ? {????OatFile::OatClass oat_class = FindOatClass(dex_file, ? klass->GetDexClassDefIndex(),???????????????????????????????????????????????&has_oat_class);????if ? (has_oat_class) {??????LoadClassMembers(self, ? dex_file, class_data, klass, ? &oat_class);????}??}??if ? (!has_oat_class) {????LoadClassMembers(self, dex_file, ? class_data, klass, nullptr);??}}
最開(kāi)始是通過(guò) DexFile 去獲取到 ClassData。因?yàn)樵陬愡€沒(méi)加載的時(shí)候,class 是以 dex格式 存在在 磁盤(pán) 文件下,這時(shí)候需要先把 dex 轉(zhuǎn)為 ? class,再把 class 加載到內(nèi)存中。
然后通過(guò) LoadClassMembers ? 進(jìn)行加載類的信息,分配內(nèi)存。LoadClassMembers ? 中分別對(duì) ArtField 和 ArtMethod 進(jìn)行初始化。
本文由職坐標(biāo)整理并發(fā)布,希望對(duì)同學(xué)們有所幫助。了解更多詳情請(qǐng)關(guān)注職坐標(biāo)移動(dòng)開(kāi)發(fā)之Android頻道!
總結(jié)
以上是生活随笔為你收集整理的android 开发art,Android应用开发之Android 系统启动原理(art 虚拟机)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: css 容器内 div 底部,CSS:在
- 下一篇: 计算机专业接本应用心理学,专接本接应用心