在Android中,zygote是整個系統建立新進程的核心進程。zygote進程在內部會先啓動Dalvik虛擬機,繼而加載一些必要的系統資源和系統類,最後進入一種監聽狀態。在以後的運做中,當其餘系統模塊(好比 AMS)但願建立新進程時,只需向zygote進程發出請求,zygote進程監聽到該請求後,會相應地fork出新的進程,因而這個新進程在初生之時,就先天具備了本身的Dalvik虛擬機以及系統資源。java
關鍵類 | 路徑 |
---|---|
init.rc | system/core/rootdir/init.rc |
init.cpp | system/core/init/init.cpp |
init.zygote64.rc | system/core/rootdir/init.zygote64.rc |
builtins.cpp | system/core/init/builtins.cpp |
service.cpp | system/core/init/service.cpp |
app_main.cpp | frameworks/base/cmds/app_process/app_main.cpp |
AndroidRuntime.cpp | frameworks/base/core/jni/AndroidRuntime.cpp |
JniInvocation.cpp | libnativehelper/JniInvocation.cpp |
ZygoteInit.java | frameworks/base/core/java/com/android/internal/os/ZygoteInit.java |
ZygoteServer.java | frameworks/base/core/java/com/android/internal/os/ZygoteServer.java |
在Android系統中,JavaVM(Java虛擬機)、應用程序進程以及運行系統的關鍵服務的SystemServer進程都是由Zygote進程來建立的,咱們也將它稱爲孵化器。它經過fock(複製進程)的形式來建立應用程序進程和SystemServer進程,因爲Zygote進程在啓動時會建立JavaVM,所以經過fock而建立的應用程序進程和SystemServer進程能夠在內部獲取一個JavaVM的實例拷貝。android
在分析init進程時,咱們知道init進程啓動後,會解析init.rc文件,而後建立和加載service字段指定的進程。zygote進程就是以這種方式,被init進程加載的。ios
在system/core/rootdir/init.rc的開始部分,能夠看到:c++
import /init.environ.rc import /init.usb.rc import /init.${ro.hardware}.rc import /vendor/etc/init/hw/init.${ro.hardware}.rc import /init.usb.configfs.rc import /init.${ro.zygote}.rc // ${ro.zygote}由廠商定義,與平臺相關 on early-init # Set init and its forked children's oom_adj. write /proc/1/oom_score_adj -1000
從以前分析的init篇中咱們知道,在不一樣的平臺(3二、64及64_32)上,init.rc將包含不一樣的zygote.rc文件。在system/core/rootdir目錄下,有init.zygote32_64.rc、init.zyote64.rc、 init.zyote32.rc、init.zygote64_32.rc。編程
✨ init.zygote32.rc:zygote 進程對應的執行程序是 app_process (純 32bit 模式)
✨ init.zygote64.rc:zygote 進程對應的執行程序是 app_process64 (純 64bit 模式)
✨ init.zygote32_64.rc:啓動兩個 zygote 進程 (名爲 zygote 和 zygote_secondary),對應的執行程序分別是 app_process32 (主模式)、app_process64
✨ init.zygote64_32.rc:啓動兩個 zygote 進程 (名爲 zygote 和 zygote_secondary),對應的執行程序分別是 app_process64 (主模式)、app_process32數組
爲何要定義這麼多種狀況呢?直接定義一個不就行了,這主要是由於Android 5.0之後開始支持64位程序,爲了兼容32位和64位才這樣定義。不一樣的zygote.rc內容大體相同,主要區別體如今啓動的是32位,仍是64位的進程。init.zygote32_64.rc和init.zygote64_32.rc會啓動兩個進程,且存在主次之分。緩存
這裏拿64位處理器爲例,init.zygote64_32.rc的代碼以下所示:安全
// 進程名稱是zygote,運行的二進制文件在/system/bin/app_process64 // 啓動參數是 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote class main priority -20 user root group root readproc socket zygote stream 660 root system // 建立一個socket,名字叫zygote,以tcp形式 onrestart write /sys/android_power/request_state wake // onrestart 指當進程重啓時執行後面的命令 onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netd onrestart restart wificond writepid /dev/cpuset/foreground/tasks // 建立子進程時,向 /dev/cpuset/foreground/tasks 寫入pid // 另外一個service ,名字 zygote_secondary service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload class main priority -20 user root group root readproc socket zygote_secondary stream 660 root system onrestart restart zygote writepid /dev/cpuset/foreground/tasks
定義了service,確定有地方調用 start zygote。在以前init解析的博客中,咱們分析過init進程的啓動。init進程啓動的最後,會產生」late-init」事件。app
// Don't mount filesystems or start core system services in charger mode. std::string bootmode = GetProperty("ro.bootmode", ""); if (bootmode == "charger") { am.QueueEventTrigger("charger"); } else { am.QueueEventTrigger("late-init"); }
對應於init.rc配置文件中,咱們找到以下代碼:框架
# Mount filesystems and start core system services. on late-init trigger early-fs ... ... # Now we can start zygote for devices with file based encryption trigger zygote-start // 觸發了zygote-start事件後,就會啓動zygote進程 ... ...
對應於init.rc配置文件中,咱們找到以下代碼:
# It is recommended to put unnecessary data/ initialization from post-fs-data # to start-zygote in device's init.rc to unblock zygote start. on zygote-start && property:ro.crypto.state=unencrypted # A/B update verifier that marks a successful boot. exec_start update_verifier_nonencrypted start netd // start對應的映射關係定義於system/core/init/builtins.cpp中 start zygote // 調用start對應的處理函數,啓動名爲zygote的服務(傳入前文init.zygote.rc中定義的參數) start zygote_secondary on zygote-start && property:ro.crypto.state=unsupported # A/B update verifier that marks a successful boot. exec_start update_verifier_nonencrypted start netd start zygote start zygote_secondary on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file # A/B update verifier that marks a successful boot. exec_start update_verifier_nonencrypted start netd start zygote start zygote_secondary
start命令有一個對應的執行函數do_start,定義在platform/system/core/init/builtins.cpp中
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max(); // clang-format off static const Map builtin_functions = { ... ... {"start", {1, 1, do_start}}, ... ... }; // clang-format on return builtin_functions; }
咱們來看下do_start():
static int do_start(const std::vector<std::string>& args) { Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); // 找到zygote service對應信息 if (!svc) { LOG(ERROR) << "do_start: Service " << args[1] << " not found"; return -1; } if (!svc->Start()) // 啓動對應的進程 return -1; return 0; }
do_start首先是經過FindServiceByName去service數組中遍歷,根據名字匹配出對應的service,而後調用service的Start函數。
最後,咱們來看看service.cpp中定義Start函數:
bool Service::Start() { ... ... pid_t pid = -1; if (namespace_flags_) { pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr); } else { pid = fork(); // 從init進程中,fork出zygote進程 } ... ... }
Start函數主要是fork出一個新進程,而後執行service對應的二進制文件,並將參數傳遞進去。那麼下面咱們以init.zygote64.rc爲例進行分析。
從上面咱們分析的init.zygote64.rc能夠看出,zygote64啓動文件的地址爲app_process64。app_process64對應的代碼定義在frameworks/base/cmds/app_process中,
咱們來看看對應的Android.mk: frameworks/base/cmds/app_process
LOCAL_PATH:= $(call my-dir) ... ... app_process_src_files := \ app_main.cpp \ ... ... LOCAL_MODULE:= app_process LOCAL_MULTILIB := both LOCAL_MODULE_STEM_32 := app_process32 LOCAL_MODULE_STEM_64 := app_process64
其實無論是app_process、app_process32仍是app_process64,對應的源文件都是app_main.cpp。
接下來咱們就看看app_process對應的main函數,該函數定義於app_main.cpp中。
在app_main.cpp的main函數中,主要作的事情就是參數解析. 這個函數有兩種啓動模式:
✨ 一種是zygote模式,也就是初始化zygote進程,傳遞的參數有--start-system-server --socket-name=zygote,前者表示啓動SystemServer,後者指定socket的名稱(Zygote64_32)。
✨ 一種是application模式,也就是啓動普通應用程序,傳遞的參數有class名字以及class帶的參數。
二者最終都是調用AppRuntime對象的start函數,加載ZygoteInit或RuntimeInit兩個Java類,並將以前整理的參數傳入進去。
咱們這裏暫時只講解ZygoteInit的加載流程。
int main(int argc, char* const argv[]) { // 將參數argv放到argv_String字符串中,而後打印出來 // 以前start zygote傳入的參數是 -Xzygote /system/bin --zygote --start-system-server if (!LOG_NDEBUG) { String8 argv_String; for (int i = 0; i < argc; ++i) { argv_String.append("\""); argv_String.append(argv[i]); argv_String.append("\" "); } ALOGV("app_process main with argv: %s", argv_String.string()); } // AppRuntime定義於app_main.cpp中,繼承自AndroidRuntime // 就是對Android運行環境的一種抽象,相似於java虛擬機對Java程序的做用 AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Process command line arguments // ignore argv[0] argc--; argv++; // 這兩個參數是Java程序須要依賴的Jar包,至關於import const char* spaced_commands[] = { "-cp", "-classpath" }; // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s). bool known_command = false; int i; // 找到解析參數的起點 for (i = 0; i < argc; i++) { // 將spaced_commands中的參數額外加入VM if (known_command == true) { runtime.addOption(strdup(argv[i])); // The static analyzer gets upset that we don't ever free the above // string. Since the allocation is from main, leaking it doesn't seem // problematic. NOLINTNEXTLINE ALOGV("app_process main add known option '%s'", argv[i]); known_command = false; continue; } for (int j = 0; j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0])); ++j) { // 比較參數是不是spaced_commands中的參數 if (strcmp(argv[i], spaced_commands[j]) == 0) { known_command = true; ALOGV("app_process main found known command '%s'", argv[i]); } } // 若是參數第一個字符是'-',直接跳出循環,以前傳入的第一個參數是 -Xzygote,因此執行到這兒就跳出了 if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --. break; } runtime.addOption(strdup(argv[i])); // The static analyzer gets upset that we don't ever free the above // string. Since the allocation is from main, leaking it doesn't seem // problematic. NOLINTNEXTLINE ALOGV("app_process main add option '%s'", argv[i]); } // Parse runtime arguments. Stop at first unrecognized option. // 從這裏其實能夠看出,經過app_main能夠啓動zygote、system-server及普通apk進程 // 這個能夠經過init.rc來配置 bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; // app_process的名稱改成zygote String8 className; // 啓動apk進程時,對應的類名 ++i; // Skip unused "parent dir" argument. // 跳過一個參數,以前跳過了-Xzygote,這裏繼續跳過 /system/bin ,也就是所謂的 "parent dir" while (i < argc) { // 開始解析輸入參數 const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { // 表示是zygote啓動模式 zygote = true; niceName = ZYGOTE_NICE_NAME; // 這個值根據平臺多是zygote64或zygote } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; // init.zygote.rc中定義了該字段,啓動zygote後會啓動system-server } else if (strcmp(arg, "--application") == 0) { application = true; // 表示是application啓動模式,也就是普通應用程序 } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName.setTo(arg + 12); // 進程別名,能夠本身指定進程名 } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); // 與--application配置,啓動指定的類,application啓動的class break; } else { --i; break; } } // 準備參數 Vector<String8> args; if (!className.isEmpty()) { // className不爲空,說明是application啓動模式 // 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); // 將className和參數設置給runtime ... ... } else { // zygote啓動模式 // We're in zygote mode. maybeCreateDalvikCache(); // 建立Dalvik的緩存目錄並定義權限 if (startSystemServer) { // 增長start-system-server參數,默認啓動zygote後,就會啓動system_server args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; // 獲取平臺對應的abi信息 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="); // 參數須要制定abi abiFlag.append(prop); args.add(abiFlag); // 加入--abi-list=參數 // In zygote mode, pass all remaining arguments to the zygote // main() method. for (; i < argc; ++i) { args.add(String8(argv[i])); // 將剩下的參數加入args } } if (!niceName.isEmpty()) { // 將app_process的進程名,替換爲niceName runtime.setArgv0(niceName.string(), true /* setProcName */); } if (zygote) { // 調用Runtime的start函數, 啓動ZygoteInit runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { // 啓動zygote沒有進入這個分支 // 但這個分支說明,經過配置init.rc文件,實際上是能夠不經過zygote來啓動一個進程 // 若是是application啓動模式,則加載RuntimeInit runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { // error狀況 fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); } }
因爲AppRuntime繼承自AndroidRuntime,且沒有重寫start方法,所以zygote的流程進入到了AndroidRuntime.cpp。
接下來,咱們來看看AndroidRuntime的start函數的流程。
/* * Start the Android runtime. This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class * named by "className". * * Passes the main function two arguments, the class name and the specified * options string. */ void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... ... // 打印一些日誌,獲取ANDROID_ROOT環境變量 /* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); // 初始化JNI,加載libart.so JNIEnv* env; // 建立虛擬機,其中大多數參數由系統屬性決定 // 最終,startVm利用JNI_CreateJavaVM建立出虛擬機 if (startVm(&mJavaVM, &env, zygote) != 0) { return; } // 回調AppRuntime的onVmCreated函數 // 對於zygote進程的啓動流程而言,無實際操做,表示虛擬建立完成,可是裏面是空實現 onVmCreated(env); ... ... }
這邊咱們跟一下jni_invocation.Init():libnativehelper/JniInvocation.cpp
Init函數主要做用是初始化JNI,具體工做是首先經過dlopen加載libart.so得到其句柄,而後調用dlsym從libart.so中找到JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM、JNI_GetCreatedJavaVMs三個函數地址,賦值給對應成員屬性,這三個函數會在後續虛擬機建立中調用。
bool JniInvocation::Init(const char* library) { #ifdef __ANDROID__ char buffer[PROP_VALUE_MAX]; #else char* buffer = NULL; #endif library = GetLibrary(library, buffer); // 默認返回 libart.so // Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed. // This is due to the fact that it is possible that some threads might have yet to finish // exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is // unloaded. const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE; /* * 1.dlopen功能是以指定模式打開指定的動態連接庫文件,並返回一個句柄 * 2.RTLD_NOW表示須要在dlopen返回前,解析出全部未定義符號,若是解析不出來,在dlopen會返回NULL * 3.RTLD_NODELETE表示在dlclose()期間不卸載庫,而且在之後使用dlopen()從新加載庫時不初始化庫中的靜態變量 */ handle_ = dlopen(library, kDlopenFlags); // 獲取libart.so的句柄 if (handle_ == NULL) { // 獲取失敗打印錯誤日誌並嘗試再次打開libart.so 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, kDlopenFlags); if (handle_ == NULL) { ALOGE("Failed to dlopen %s: %s", library, dlerror()); return false; } } /* * 1.FindSymbol函數內部實際調用的是dlsym * 2.dlsym做用是根據 動態連接庫 操做句柄(handle)與符號(symbol),返回符號對應的地址 * 3.這裏實際就是從libart.so中將JNI_GetDefaultJavaVMInitArgs等對應的地址存入&JNI_GetDefaultJavaVMInitArgs_中 */ 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; }
其次,咱們再跟一下startVm():
這個函數特別長,可是裏面作的事情很單一,其實就是從各類系統屬性中讀取一些參數,而後經過addOption設置到AndroidRuntime的mOptions數組中存起來,另外就是調用以前從libart.so中找到JNI_CreateJavaVM函數,並將這些參數傳入,因爲本篇主要講zygote啓動流程,所以關於虛擬機的實現就不深刻探究了。
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) { JavaVMInitArgs initArgs; char propBuf[PROPERTY_VALUE_MAX]; char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX]; char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX]; ... ... /* route exit() to our handler */ addOption("exit", (void*) runtime_exit); // 將參數放入mOptions數組中 ... ... initArgs.version = JNI_VERSION_1_4; initArgs.options = mOptions.editArray(); // 將mOptions賦值給initArgs initArgs.nOptions = mOptions.size(); initArgs.ignoreUnrecognized = JNI_FALSE; /* * 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) { // 調用libart.so的JNI_CreateJavaVM函數 ALOGE("JNI_CreateJavaVM failed\n"); return -1; } return 0; }
咱們回到AndroidRuntime的start函數。初始化JVM後,接下來就會調用startReg函數。
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... ... /* 01. 建立Java虛擬機*/ /* * Register android functions. */ if (startReg(env) < 0) { // 註冊JNI函數 ALOGE("Unable to register all android natives\n"); return; } ... ... }
startReg首先是設置了Android建立線程的處理函數,而後建立了一個200容量的局部引用做用域,用於確保不會出現OutOfMemoryException,最後就是調用register_jni_procs進行JNI註冊。
咱們跟進startReg():
/* * Register android native functions with the VM. */ /*static*/ int AndroidRuntime::startReg(JNIEnv* env) { ATRACE_NAME("RegisterAndroidNatives"); /* * This hook causes all future threads created in this process to be * attached to the JavaVM. (This needs to go away in favor of JNI * Attach calls.) */ // 定義Android建立線程的func:javaCreateThreadEtc,這個函數內部是經過Linux的clone來建立線程的 androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); ALOGV("--- registering native functions ---\n"); /* * Every "register" function calls one or more things that return * a local reference (e.g. FindClass). Because we haven't really * started the VM yet, they're all getting stored in the base frame * and never released. Use Push/Pop to manage the storage. */ env->PushLocalFrame(200); // 建立一個200容量的局部引用做用域,這個局部引用其實就是局部變量 if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { // 註冊JNI函數 env->PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL); // 釋放局部引用做用域 //createJavaThread("fubar", quickTest, (void*) "hello"); return 0; }
從上述代碼能夠看出,startReg函數中主要是經過register_jni_procs來註冊JNI函數。其中,gRegJNI是一個全局數組,該數組的定義以下:
static const RegJNIRec gRegJNI[] = { // 裏面就是一堆的函數指針 REG_JNI(register_com_android_internal_os_RuntimeInit), REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit), REG_JNI(register_android_os_SystemClock), REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), ... ... };
咱們挑一個register_com_android_internal_os_ZygoteInit_nativeZygoteInit,這其實是自定義JNI函數並進行動態註冊的標準寫法,
內部是調用JNI的RegisterNatives,這樣註冊後,Java類ZygoteInit的native方法nativeZygoteInit就會調用com_android_internal_os_ZygoteInit_nativeZygoteInit函數。
int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env) { const JNINativeMethod methods[] = { { "nativeZygoteInit", "()V", (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit }, }; return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit", methods, NELEM(methods)); }
REG_JNI對應的宏定義及RegJNIRec結構體的定義爲:
#ifdef NDEBUG #define REG_JNI(name) { name } struct RegJNIRec { int (*mProc)(JNIEnv*); }; #else #define REG_JNI(name) { name, #name } struct RegJNIRec { int (*mProc)(JNIEnv*); const char* mName; }; #endif
根據宏定義能夠看出,宏REG_JNI將獲得函數名;定義RegJNIRec數組時,函數名被賦值給RegJNIRec結構體,因而每一個函數名被強行轉換爲函數指針。
所以,register_jni_procs的參數就是一個函數指針數組,數組的大小和JNIEnv。
咱們來跟進一下register_jni_procs函數:
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env) { for (size_t i = 0; i < count; i++) { if (array[i].mProc(env) < 0) { // 調用mProc #ifndef NDEBUG ALOGD("----------!!! %s failed to load\n", array[i].mName); #endif return -1; } } return 0; }
結合前面的分析,容易知道register_jni_procs函數,實際上就是調用函數指針(mProc)對應的函數,以進行實際的JNI函數註冊。
繼續分析AndroidRuntime.cpp的start函數:
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... ... /* 01. 建立Java虛擬機*/ /* 02. 註冊JNI函數 */ /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ // 替換string爲實際路徑 // 例如:將 "com.android.internal.os.ZygoteInit" 替換爲 "com/android/internal/os/ZygoteInit" char* slashClassName = toSlashClassName(className != NULL ? className : ""); jclass startClass = env->FindClass(slashClassName); // 找到class文件 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"); // 經過反射找到ZygoteInit的main函數 if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); // 調用ZygoteInit的main函數 ... ... } } 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"); }
能夠看到,在AndroidRuntime的最後,將經過反射調用ZygoteInit的main函數。至此,zygote進程進入了java世界。
其實咱們仔細想想,就會以爲zygote的整個流程其實是很是符合實際狀況的。
✨✨ 在Android中,每一個進程都運行在對應的虛擬機上,所以zygote首先就負責建立出虛擬機。
✨✨ 而後,爲了反射調用java代碼,必須有對應的JNI函數,因而zygote進行了JNI函數的註冊。
✨✨ 當一切準備穩當後,zygote進程才進入到了java世界。
如今咱們跟進ZygoteInit.java的main函數。
public static void main(String argv[]) { //建立ZygoteServer對象 ZygoteServer zygoteServer = new ZygoteServer(); // Mark zygote start. This ensures that thread creation will throw // an error. // 調用native函數,確保當前沒有其它線程在運行 // 主要仍是處於安全的考慮 ZygoteHooks.startZygoteNoThreadCreation(); // Zygote goes into its own process group. try { Os.setpgid(0, 0); } catch (ErrnoException ex) { throw new RuntimeException("Failed to setpgid(0,0)", ex); } final Runnable caller; try { ... ... RuntimeInit.enableDdms(); boolean startSystemServer = false; String socketName = "zygote"; String abiList = null; boolean enableLazyPreload = false; // 解析參數,獲得上述變量的值 for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true; } else if ("--enable-lazy-preload".equals(argv[i])) { enableLazyPreload = true; } else if (argv[i].startsWith(ABI_LIST_ARG)) { abiList = argv[i].substring(ABI_LIST_ARG.length()); } else if (argv[i].startsWith(SOCKET_NAME_ARG)) { socketName = argv[i].substring(SOCKET_NAME_ARG.length()); } else { throw new RuntimeException("Unknown command line argument: " + argv[i]); } } if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } zygoteServer.registerServerSocket(socketName); // 註冊server socket // In some configurations, we avoid preloading resources and classes eagerly. // In such cases, we will preload things prior to our first fork. if (!enableLazyPreload) { ... ... preload(bootTimingsTraceLog); // 默認狀況,預加載信息 ... ... } else { // 如註釋,延遲預加載 // 變動Zygote進程優先級爲NORMAL級別 // 第一次fork時纔會preload Zygote.resetNicePriority(); } // Do an initial gc to clean up after startup bootTimingsTraceLog.traceBegin("PostZygoteInitGC"); gcAndFinalize(); // 若是預加載了,頗有必要GC一波 bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC ... ... // Zygote process unmounts root storage spaces. Zygote.nativeUnmountStorageOnInit(); // Set seccomp policy // 加載seccomp的過濾規則 // 全部 Android 軟件都使用系統調用(簡稱爲 syscall)與 Linux 內核進行通訊 // 內核提供許多特定於設備和SOC的系統調用,讓用戶空間進程(包括應用)能夠直接與內核進行交互 // 不過,其中許多系統調用Android未予使用或未予正式支持 // 經過seccomp,Android可以使應用軟件沒法訪問未使用的內核系統調用 // 因爲應用沒法訪問這些系統調用,所以,它們不會被潛在的有害應用利用 // 該過濾器安裝到zygote進程中,因爲全部Android應用均衍生自該進程 // 於是會影響到全部應用 Seccomp.setPolicy(); /// M: Added for BOOTPROF addBootEvent("Zygote:Preload End"); /// @} ZygoteHooks.stopZygoteNoThreadCreation(); // 容許有其它線程了 if (startSystemServer) { Runnable r = forkSystemServer(abiList, socketName, zygoteServer); // fork出system server // {@code r == null} in the parent (zygote) process, and {@code r != null} in the // child (system_server) process. if (r != null) { r.run(); return; } } Log.i(TAG, "Accepting command socket connections"); // The select loop returns early in the child process after a fork and // loops forever in the zygote. caller = zygoteServer.runSelectLoop(abiList); // zygote進程進入無限循環,處理請求 } catch (Throwable ex) { ... ... } finally { zygoteServer.closeServerSocket(); } // We're in the child process and have exited the select loop. Proceed to execute the // command. if (caller != null) { caller.run(); } }
上面是ZygoteInit的main函數的主幹部分,除了安全相關的內容外,最主要的工做就是註冊server socket、預加載、啓動system server及進入無限循環處理請求消息。
接下來咱們分四部分分別討論!
Android O將server socket相關的工做抽象到ZygoteServer.java中了。咱們來看看其中的registerZygoteSocket函數:
/** * Registers a server socket for zygote command connections * * @throws RuntimeException when open fails */ void registerServerSocket(String socketName) { if (mServerSocket == null) { int fileDesc; // ANDROID_SOCKET_PREFIX爲"ANDROID_SOCKET_" // 此處的socket name,就是zygote final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try { // 還記得麼?在init.zygote.rc被加載時,指定了名爲zygote的socket // 在進程被建立時,就會建立對應的文件描述符,並加入到環境變量中 // 所以,此時能夠取出對應的環境變量 String env = System.getenv(fullSocketName); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException(fullSocketName + " unset or invalid", ex); } try { FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc); // 獲取zygote socket的文件描述符 mServerSocket = new LocalServerSocket(fd); // 將socket包裝成一個server socket } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } } }
咱們跟蹤LocalServerSocket():
public LocalServerSocket(String name) throws IOException { impl = new LocalSocketImpl(); impl.create(LocalSocket.SOCKET_STREAM); // 建立SOCKET_STREAM類型的AF_UNIX socket localAddress = new LocalSocketAddress(name); impl.bind(localAddress); // 綁定到指定地址 impl.listen(LISTEN_BACKLOG); // 開始監聽 }
咱們看看預加載的內容:
static void preload(TimingsTraceLog bootTimingsTraceLog) { ... ... beginIcuCachePinning(); // Pin ICU Data, 獲取字符集轉換資源等 ... ... preloadClasses(); // 讀取文件system/etc/preloaded-classes,而後經過反射加載對應的類 // 通常由廠商來定義,有時須要加載數千個類,啓動慢的緣由之一 ... ... preloadResources(); // 負責加載一些經常使用的系統資源 ... ... nativePreloadAppProcessHALs(); ... ... preloadOpenGL(); // 圖形相關 ... ... preloadSharedLibraries(); // 一些必要庫 preloadTextResources(); // 語言相關的字符信息 // Ask the WebViewFactory to do any initialization that must run in the zygote process, // for memory sharing purposes. WebViewFactory.prepareWebViewInZygote(); endIcuCachePinning(); warmUpJcaProviders(); // 安全相關的 Log.d(TAG, "end preload"); sPreloadComplete = true; }
爲了讓系統實際運行時更加流暢,在zygote啓動時候,調用preload函數進行了一些預加載操做。Android 經過zygote fork的方式建立子進程。zygote進程預加載這些類和資源,在fork子進程時,僅須要作一個複製便可。
這樣能夠節約子進程的啓動時間。同時,根據fork的copy-on-write機制可知,有些類若是不作改變,甚至都不用複製,子進程能夠和父進程共享這部分數據,從而省去很多內存的佔用。
再來看看啓動System Server的流程:
/** * Prepare the arguments and forks for the system server process. * * Returns an {@code Runnable} that provides an entrypoint into system_server code in the * child process, and {@code null} in the parent. */ private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { long capabilities = posixCapabilitiesAsBits( OsConstants.CAP_IPC_LOCK, OsConstants.CAP_KILL, OsConstants.CAP_NET_ADMIN, OsConstants.CAP_NET_BIND_SERVICE, OsConstants.CAP_NET_BROADCAST, OsConstants.CAP_NET_RAW, OsConstants.CAP_SYS_MODULE, OsConstants.CAP_SYS_NICE, OsConstants.CAP_SYS_PTRACE, OsConstants.CAP_SYS_TIME, OsConstants.CAP_SYS_TTY_CONFIG, OsConstants.CAP_WAKE_ALARM ); /* Containers run without this capability, so avoid setting it in that case */ if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) { capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND); } /* Hardcoded command line to start the system server */ String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "com.android.server.SystemServer", }; ZygoteConnection.Arguments parsedArgs = null; int pid; try { parsedArgs = new ZygoteConnection.Arguments(args); // 將上面準備的參數,按照ZygoteConnection的風格進行封裝 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); /* Request to fork the system server process */ pid = Zygote.forkSystemServer( // 經過fork"分裂"出system_server parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ if (pid == 0) { // 處理32_64和64_32的狀況 if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } // fork時會copy socket,system server須要主動關閉 zygoteServer.closeServerSocket(); // system server進程處理本身的工做 return handleSystemServerProcess(parsedArgs); } return null; }
建立出SystemServer進程後,zygote進程調用ZygoteServer中的函數runSelectLoop,處理server socket收到的命令。
/** * Runs the zygote process's select loop. Accepts new connections as * they happen, and reads commands from connections one spawn-request's * worth at a time. */ Runnable runSelectLoop(String abiList) { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); // 首先將server socket加入到fds fds.add(mServerSocket.getFileDescriptor()); peers.add(null); while (true) { // 每次循環,都從新建立須要監聽的pollFds StructPollfd[] pollFds = new StructPollfd[fds.size()]; for (int i = 0; i < pollFds.length; ++i) { pollFds[i] = new StructPollfd(); pollFds[i].fd = fds.get(i); // 關注事件到來 pollFds[i].events = (short) POLLIN; } try { // 等待事件到來 Os.poll(pollFds, -1); } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); } // 注意這裏是倒序的,即優先處理已創建連接的信息,後處理新建連接的請求 for (int i = pollFds.length - 1; i >= 0; --i) { if ((pollFds[i].revents & POLLIN) == 0) { continue; } // server socket最早加入fds, 所以這裏是server socket收到數據 if (i == 0) { // 收到新的創建通訊的請求,創建通訊鏈接 ZygoteConnection newPeer = acceptCommandPeer(abiList); // 加入到peers和fds, 即下一次也開始監聽 peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); } else { //其它通訊鏈接收到數據 ... ... } } } }
從上面代碼可知,初始時fds中僅有server socket,所以當有數據到來時,將執行i等於0的分支。此時,顯然是須要建立新的通訊鏈接,所以acceptCommandPeer將被調用。
咱們看看acceptCommandPeer函數:
/** * Waits for and accepts a single command connection. Throws * RuntimeException on failure. */ private ZygoteConnection acceptCommandPeer(String abiList) { try { // socket編程中,accept()調用主要用在基於鏈接的套接字類型,好比SOCK_STREAM和SOCK_SEQPACKET // 它提取出所監聽套接字的等待鏈接隊列中第一個鏈接請求,建立一個新的套接字,並返回指向該套接字的文件描述符 // 新創建的套接字不在監聽狀態,原來所監聽的套接字的狀態也不受accept()調用的影響 return createNewConnection(mServerSocket.accept(), abiList); } catch (IOException ex) { throw new RuntimeException( "IOException during accept()", ex); } } protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList) throws IOException { return new ZygoteConnection(socket, abiList); }
從上面的代碼,能夠看出acceptCommandPeer調用了server socket的accpet函數。因而當新的鏈接創建時,zygote將會建立出一個新的socket與其通訊,並將該socket加入到fds中。所以,一旦通訊鏈接創建後,fds中將會包含有多個socket。
當poll監聽到這一組sockets上有數據到來時,就會從阻塞中恢復。因而,咱們須要判斷究竟是哪一個socket收到了數據。
在runSelectLoop中採用倒序的方式輪詢。因爲server socket第一個被加入到fds,所以最後輪詢到的socket才須要處理新建鏈接的操做;其它socket收到數據時,僅須要調用zygoteConnection的runonce函數執行數據對應的操做。若一個鏈接處理完全部對應消息後,該鏈接對應的socket和鏈接等將被移除。
Zygote啓動流程到此結束,Zygote進程共作了以下幾件事:
🔨 1. 建立AppRuntime並調用其start方法,啓動Zygote進程。
🔨 2. 建立JavaVM併爲JavaVM註冊JNI.
🔨 3. 經過JNI調用ZygoteInit的main函數進入Zygote的Java框架層。
🔨 4. 經過registerZygoteSocket函數建立服務端Socket,預加載類和資源,並經過runSelectLoop函數等待如ActivityManagerService等的請求。
🔨 5. 啓動SystemServer進程。
01. https://blog.csdn.net/tfygg/article/details/52086621 02. https://www.jianshu.com/p/cbc6b84aee08 03. https://www.jianshu.com/p/ab9b83a77af6