@(Android研究)[Android|源碼|虛擬機]java
[TOC]android
虛擬機啓動時的函數調用路徑:數組
app_main.cc - main |-- AndroidRuntime::start |-- AndroidRuntime::startVm |-- JNI_CreateJavaVM
當init進程啓動zygote進程時會建立虛擬機,下是zygote代碼的main函數,本文從這裏開始分析虛擬機如何建立,這個函數在文件"frameworks/base/cmds/app_process/app_main.cpp"中,下面是它的源碼:app
int main(int argc, char* const argv[]) { ...... AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // 處理命令行參數 // 忽略 argv[0] argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm. // // The first argument after the VM args is the "parent dir", which // is currently unused. // // After the parent dir, we expect one or more the following internal // arguments : // // --zygote : Start in zygote mode // --start-system-server : 啓動系統服務 // --application : Start in application (stand alone, non zygote) mode. // --nice-name : The nice name for this process. // // For non zygote starts, these arguments will be followed by // the main class name. All remaining arguments are passed to // the main method of this class. // // For zygote starts, all remaining arguments are passed to the zygote. // main function. // // Note that we must copy argument string values since we will rewrite the // entire argument block when we apply the nice name to argv0. int i; for (i = 0; i < argc; i++) { if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --. break; } runtime.addOption(strdup(argv[i])); } // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; // Skip unused "parent dir" argument. while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName.setTo(arg + 12); } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); break; } else { --i; break; } } Vector<String8> args; if (!className.isEmpty()) { // We're not in zygote mode, the only argument we need to pass // to RuntimeInit is the application argument. // // The Remainder of args get passed to startup class main(). Make // copies of them before we overwrite them with the process name. args.add(application ? String8("application") : String8("tool")); runtime.setClassNameAndArgs(className, argc - i, argv + i); } else { // We're in zygote mode. maybeCreateDalvikCache(); if (startSystemServer) { args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", ABI_LIST_PROPERTY); return 11; } String8 abiFlag("--abi-list="); abiFlag.append(prop); args.add(abiFlag); // In zygote mode, pass all remaining arguments to the zygote // main() method. for (; i < argc; ++i) { args.add(String8(argv[i])); } } if (!niceName.isEmpty()) { runtime.setArgv0(niceName.string()); set_process_name(niceName.string()); } if (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; } }
**runtime.start(...)**語句啓動了Android運行時,在啓動Android運行時的同時會啓動虛擬機。main函數中的局部變量runtime是AppRuntime類的對象,這個類的代碼定義在文件"frameworks/base/cmds/app_process/app_main.cpp"中,AppRuntime類繼承了AndroidRuntime類,而start函數就是AndroidRuntime類的成員函數。ide
AndroidRuntime類定義在文件"frameworks/base/core/jni/AndroidRuntime.cpp"中,下面是AndroidRuntime::start函數的代碼:函數
/* * 啓動Android運行時。它啓動虛擬機並調用經過"className"參數所指定的類名中 * 的"static void main(String[] args)"方法。 * * 向main函數傳入兩個參數:類名和被指定的選項字符串。 */ void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid()); ...... /* 啓動虛擬機。 */ JniInvocation jni_invocation; jni_invocation.Init(NULL); // 初始化JNI API接口 JNIEnv* env; if (startVm(&mJavaVM, &env, zygote) != 0) { return; } onVmCreated(env); // 在zygote中這個函數什麼都不作。 /* * Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; } /* * 咱們要調用main(),將一個字符串數組當作參數傳入。 * 目前,咱們有兩個參數,類名和一個選項字符串。 * 建立一個數組來保存它們。 */ jclass stringClass; jobjectArray strArray; jstring classNameStr; stringClass = env->FindClass("java/lang/String"); assert(stringClass != NULL); strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); assert(strArray != NULL); classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); assert(optionsStr != NULL); env->SetObjectArrayElement(strArray, i + 1, optionsStr); } /* * 啓動Start VM。這個線程成爲VM的主線程,直到VM結束前不會返回。 * * 對於zygote而言除非設備關機不然這個線程是不會退出的,將zygote * 比做服務端,這個服務端會一直等待並處理各類客戶端的請求。 */ 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 { // 調用Java方法。 env->CallStaticVoidMethod(startClass, startMeth, strArray); #if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env); #endif } } free(slashClassName); ALOGD("Shutting down VM\n"); if (mJavaVM->DetachCurrentThread() != JNI_OK) ALOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) ALOGW("Warning: VM did not shut down cleanly\n"); }
這個函數主要作了下面三件事情:ui
這個函數中調用了**onVmCreated(env);**語句,對於zygote來講,這個函數不作任何事情。this
jni_invocation雖然是AndroidRuntime::start函數的局部變量,可是對於zygote而言除非設備關機不然是不會退出AndroidRuntime::start函數的。對於普通APP,除非APP結束不然也不會退出AndroidRuntime::start函數。在另外一篇分析zygote啓動過程的文章中會說明緣由。命令行
JniInvocation::Init這個函數用於初始化JNI調用,這個函數在文件libnativehelper/JniInvocation.cpp中,下面是這個函數的代碼:線程
/** * 初始化JNI調用API。參數library應當傳入可供dlopen打開的有效的共享庫, * 這個共享庫提供一個JNI調用實現,或者參數library被傳入null則將經過 * persist.sys.dalvik.vm.lib使用默認值。 */ bool JniInvocation::Init(const char* library) { #ifdef HAVE_ANDROID_OS char buffer[PROPERTY_VALUE_MAX]; #else char* buffer = NULL; #endif // 得到共享庫名。 library = GetLibrary(library, buffer); // 加載這個共享庫。 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; } } // 找到符號JNI_GetDefaultJavaVMInitArgs。 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_), "JNI_GetDefaultJavaVMInitArgs")) { return false; } // 找到符號JNI_CreateJavaVM。 if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_), "JNI_CreateJavaVM")) { return false; } // 找到符號JNI_GetCreatedJavaVMs。 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_), "JNI_GetCreatedJavaVMs")) { return false; } return true; }
這個函數作了下面兩件事情:
JniInvocation類中的成員變量handle_保存了共享庫的句柄,成員函數JNI_GetDefaultJavaVMInitArgs_、*JNI_CreateJavaVM_和JNI_GetCreatedJavaVMs_*均保存了從共享庫中得到的函數地址。
JniInvocation::Init調用了JniInvocation::GetLibrary函數得到了共享庫名,這個共享庫中有JNI函數的實現,這個函數在文件libnativehelper/JniInvocation.cpp中,下面是它的代碼:
#ifdef HAVE_ANDROID_OS static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib.2"; static const char* kDebuggableSystemProperty = "ro.debuggable"; static const char* kDebuggableFallback = "0"; // Not debuggable. #endif static const char* kLibraryFallback = "libart.so"; const char* JniInvocation::GetLibrary(const char* library, char* buffer) { #ifdef HAVE_ANDROID_OS const char* default_library; char debuggable[PROPERTY_VALUE_MAX]; property_get(kDebuggableSystemProperty, debuggable, kDebuggableFallback); if (strcmp(debuggable, "1") != 0) { // Not a debuggable build. // Do not allow arbitrary library. This // will also ignore the default library, but initialize to fallback // for cleanliness. library = kLibraryFallback; default_library = kLibraryFallback; } else { // Debuggable build. // Accept the library parameter. For the case it is NULL, load the default // library from the system property. if (buffer != NULL) { property_get(kLibrarySystemProperty, buffer, kLibraryFallback); default_library = buffer; } else { // 若是沒有指定緩衝區,使用備用的默認值。 default_library = kLibraryFallback; } } #else UNUSED(buffer); const char* default_library = kLibraryFallback; #endif if (library == NULL) { library = default_library; } return library; }
能夠發現JniInvocation::GetLibrary函數中默認的庫是kLibraryFallback,而這個變量的值爲libart.so,這個函數的返回值與kLibrarySystemProperty變量也有關係,而這個變量中保存的屬性對應的值一般爲libart.so。因此在這裏我武斷的認定這個函數的返回值總爲libart.so以便後面分析。
對AndroidRuntime::start函數中所執行**jni_invocation.Init(NULL);**語句作一個總結
:
繼續對AndroidRuntime::start函數進行分析,在執行完**jni_invocation.Init(NULL);**語句後緊接着調用了startVm函數,這個函數啓動了虛擬機。這個函數在文件frameworks/base/core/jni/AndroidRuntime.cpp中,下面是它的源碼:
/* * Start the Dalvik Virtual Machine. * (PS:這裏翻譯過來是:啓動Dalvik虛擬機,我認爲是這只不過是註釋內容還未被修改,而實際上啓動的已經不是dalvik虛擬機了) * * Various arguments, most determined by system properties, are passed in. * The "mOptions" vector is updated. * * CAUTION: when adding options in here, be careful not to put the * char buffer inside a nested scope. Adding the buffer to the * options using mOptions.add() does not copy the buffer, so if the * buffer goes out of scope the option may be overwritten. It's best * to put the buffer at the top of the function so that it is more * unlikely that someone will surround it in a scope at a later time * and thus introduce a bug. * * Returns 0 on success. */ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) { int result = -1; JavaVMInitArgs initArgs; ...... // checkjni屬性。 bool checkJni = false; property_get("dalvik.vm.checkjni", propBuf, ""); if (strcmp(propBuf, "true") == 0) { checkJni = true; } else if (strcmp(propBuf, "false") != 0) { /* 屬性即不爲真也不爲假;轉到內核參數。 */ property_get("ro.kernel.android.checkjni", propBuf, ""); if (propBuf[0] == '1') { checkJni = true; } } ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF"); if (checkJni) { /* extended JNI checking */ addOption("-Xcheck:jni"); /* 設置JNI全局引用上限 */ addOption("-Xjnigreflimit:2000"); /* with -Xcheck:jni, 這提供JNI函數調用跟蹤 */ //addOption("-verbose:jni"); } // 根據屬性得到虛擬機的執行模式。 property_get("dalvik.vm.execution-mode", propBuf, ""); if (strcmp(propBuf, "int:portable") == 0) { executionMode = kEMIntPortable; } else if (strcmp(propBuf, "int:fast") == 0) { executionMode = kEMIntFast; } else if (strcmp(propBuf, "int:jit") == 0) { executionMode = kEMJitCompiler; } ...... /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */ parseRuntimeOption("dalvik.vm.jit.op", jitOpBuf, "-Xjitop:"); /* Force interpreter-only mode for selected methods */ parseRuntimeOption("dalvik.vm.jit.method", jitMethodBuf, "-Xjitmethod:"); // 向mOptions中添加執行模式。 if (executionMode == kEMIntPortable) { addOption("-Xint:portable"); } else if (executionMode == kEMIntFast) { addOption("-Xint:fast"); } else if (executionMode == kEMJitCompiler) { addOption("-Xint:jit"); } // libart允許libdvm flags,但反過來不行,因此僅libart的狀況下才傳入一些選項。 property_get("persist.sys.dalvik.vm.lib.2", dalvikVmLibBuf, "libart.so"); bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0); if (libart) { ...... } ...... initArgs.version = JNI_VERSION_1_4; initArgs.options = mOptions.editArray(); initArgs.nOptions = mOptions.size(); initArgs.ignoreUnrecognized = JNI_FALSE; /* * 初始化VM。 * * JavaVM*做用於每一個進程,JNIEnv*做用於每一個線程(The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.)。 * * 若是這個調用成功,則VM就緒,and we can start issuing * JNI calls. */ if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { ALOGE("JNI_CreateJavaVM failed\n"); goto bail; } result = 0; bail: return result; }
AndroidRuntime::startVm函數主要作了兩件事情:
系統屬性主要經過property_get函數得到,這個函數會去系統屬性文件中讀取屬性。
當要添加一個新的選項時會調用AndroidRuntime::addOption函數,它向mOptions中添加一個JavaVMOption對象,這個函數在frameworks/base/core/jni/AndroidRuntime.cpp文件中,下面是它的源碼:
void addOption(const char* optionString, void* extra_info = NULL); void AndroidRuntime::addOption(const char* optionString, void* extraInfo) { JavaVMOption opt; opt.optionString = optionString; opt.extraInfo = extraInfo; mOptions.add(opt); }
下面開始分析JNI_CreateJavaVM函數,這個定義在libnativehelper/JniInvocation.cpp文件中,下面是它的源碼:
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); }
JniInvocation::GetJniInvocation()函數得到的是JniInvocation類的實例,JniInvocation::GetJniInvocation().JNI_CreateJavaVM調用的是JniInvocation類中非靜態成員函數JNI_CreateJavaVM,下面是這個成員函數的源碼:
jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { return JNI_CreateJavaVM_(p_vm, p_env, vm_args); }
JNI_CreateJavaVM_是JniInvocation類中的非靜態成員變量,它指向的是前面所加載的libart.so中的JNI_CreateJavaVM函數,這個成員變量在JniInvocation::Init函數中被賦值。
libart.so中的JNI_CreateJavaVM函數建立了虛擬機,它的源碼art/runtime/jni_internal.cc文件中,下面是這個函數的源碼:
/** * 建立虛擬機。 * 參數p_vm和p_env是輸出參數。 * 參數vm_args是輸入參數,這個參數保存的是虛擬機建立過程當中須要用到的選項。 */ extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args); // 檢查Jni版本。 if (IsBadJniVersion(args->version)) { LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version; return JNI_EVERSION; } // 將全部的虛擬機選項均保存到options中。 RuntimeOptions 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; }
JNI_CreateJavaVM函數主要作了兩件事情:
RuntimeOptions類型的定義在文件art/runtime/runtime.h中:
typedef std::vector<std::pair<std::string, const void*>> RuntimeOptions;
Runtime::Create函數是一個靜態函數在文件art/runtime/runtime.cc中,下面是它的源碼:
bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) { // TODO: acquire a static mutex on Runtime to avoid racing. if (Runtime::instance_ != NULL) { return false; } InitLogging(NULL); // Calls Locks::Init() as a side effect. instance_ = new Runtime; if (!instance_->Init(options, ignore_unrecognized)) { delete instance_; instance_ = NULL; return false; } return true; }
經過分析上面的代碼能夠發現Runtime類被設計爲單例模式,單例對象保存在instance_中,而後又調用了Init函數。
Runtime::Init函數在文件art/runtime/runtime.cc中,下面是它的源碼:
bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) { CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize); MemMap::Init(); std::unique_ptr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized)); ...... java_vm_ = new JavaVMExt(this, options.get()); Thread::Startup(); // ClassLinker needs an attached thread, but we can't fully attach a thread without creating // objects. We can't supply a thread group yet; it will be fixed later. Since we are the main // thread, we do not get a java peer. Thread* self = Thread::Attach("main", false, nullptr, false); ...... VLOG(startup) << "Runtime::Init exiting"; return true; }
這個函數中的new JavaVMExt語句建立了JavaVMExt對象,一個虛擬機有且僅有一個JavaVMExt對象,JavaVMExt類型繼承了JavaVM類型,能夠去查看"art/runtime/jni_internal.h"文件。Thread::Attach函數將虛擬機附加到主線程上。
Thread::Attach函數的源碼在文件"art/runtime/thread.cc"文件中,下面是它的源碼:
Thread* Thread::Attach(const char* thread_name, bool as_daemon, jobject thread_group, bool create_peer) { Thread* self; Runtime* runtime = Runtime::Current(); if (runtime == nullptr) { LOG(ERROR) << "Thread attaching to non-existent runtime: " << thread_name; return nullptr; } { MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_); if (runtime->IsShuttingDownLocked()) { ...... } else { Runtime::Current()->StartThreadBirth(); self = new Thread(as_daemon); self->Init(runtime->GetThreadList(), runtime->GetJavaVM()); Runtime::Current()->EndThreadBirth(); } } ...... }
在這個函數中建立了Thread對象,而後調用了Thread::Init函數,在這個函數中建立了當前線程的JNIEnv。
Thread::Init函數的源碼在文件"art/runtime/thread.cc"文件中,下面是這個函數的源碼:
void Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm) { ...... tlsPtr_.jni_env = new JNIEnvExt(this, java_vm); ...... }
這個函數中建立了JNIEnvExt對象。JNIEnvExt類型繼承了JNIEnv類型,能夠去"art/runtime/jni_internal.h"文件中查看。
如今回到JNI_CreateJavaVM函數中,Runtime::Create函數執行完後,將執行Runtime::Start函數啓動Android運行時,然會調用這兩行語句返回建立的Java虛擬機對象和當前線程的JNI環境:
*p_env = Thread::Current()->GetJniEnv(); *p_vm = runtime->GetJavaVM();
Thread::Current函數得到當前線程的對象。
Tread::GetJniEnv()得到當前線程的JNI環境,這個函數的定義在文件"art/runtime/thread-inl.h"中,下面是它的源碼:
// JNI methods JNIEnvExt* GetJniEnv() const { return tlsPtr_.jni_env; }
Runtime::GetJavaVM()函數得到的是Java虛擬機對象,它的定義在文件"art/runtime/runtime.h"中,下面是它的源碼:
JavaVMExt* GetJavaVM() const { return java_vm_; }
執行完JNI_CreateJavaVM函數後返回到startVM函數中。
執行完startVM成功啓動虛擬機後,將會經過env->CallStaticVoidMethod語句調用"com.android.internal.os.ZygoteInit"這個Java類的main方法,這個Java方法將會啓動zygote服務。
關於如何啓動zygote服務將另寫一篇文章分析。
至此Android5.1源碼虛擬機啓動過程分析完畢。