copy from : http://gityuan.com/2016/02/13/android-zygote/
基於Android 6.0的源碼剖析, 分析Android啟動過程的Zygote進程
/frameworks/base/cmds/app_process/App_main.cpp
/frameworks/base/core/jni/AndroidRuntime.cpp
/frameworks/base/core/java/com/android/internal/os/
- ZygoteInit.java
- Zygote.java
- ZygoteConnection.java
/frameworks/base/core/java/android/net/LocalServerSocket.java
/system/core/libutils/Threads.cpp
一. 概述
Zygote是由init進程通過解析init.zygote.rc文件而創建的,zygote所對應的可執行程序app_process,所對應的源文件是App_main.cpp,進程名為zygote。
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart media onrestart restart netd
Zygote進程能夠重啟的地方:
- servicemanager進程被殺; (onresart)
- surfaceflinger進程被殺; (onresart)
- Zygote進程自己被殺; (oneshot=false)
- system_server進程被殺; (waitpid)
從App_main()開始,Zygote啟動過程的函數調用類大致流程如下:
二、Zygote啟動過程
2.1 App_main.main
[-> App_main.cpp]
int main(int argc, char* const argv[]) { //傳到的參數argv為“-Xzygote /system/bin --zygote --start-system-server” AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); argc--; argv++; //忽略第一個參數 int i; for (i = 0; i < argc; i++) { if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; break; } runtime.addOption(strdup(argv[i])); } //參數解析 bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; //對於64位系統nice_name為zygote64; 32位系統為zygote 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()) { // 運行application或tool程序 args.add(application ? String8("application") : String8("tool")); runtime.setClassNameAndArgs(className, argc - i, argv + i); } else { //進入zygote模式,創建 /data/dalvik-cache路徑 maybeCreateDalvikCache(); if (startSystemServer) { args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { return 11; } String8 abiFlag("--abi-list="); abiFlag.append(prop); args.add(abiFlag); for (; i < argc; ++i) { args.add(String8(argv[i])); } } //設置進程名 if (!niceName.isEmpty()) { runtime.setArgv0(niceName.string()); set_process_name(niceName.string()); } if (zygote) { // 啟動AppRuntime 【見小節2.2】 runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { //沒有指定類名或zygote,參數錯誤 return 10; } }
2.2 start
[-> AndroidRuntime.cpp]
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { static const String8 startSystemServer("start-system-server"); for (size_t i = 0; i < options.size(); ++i) { if (options[i] == startSystemServer) { const int LOG_BOOT_PROGRESS_START = 3000; } } const char* rootDir = getenv("ANDROID_ROOT"); if (rootDir == NULL) { rootDir = "/system"; if (!hasDir("/system")) { return; } setenv("ANDROID_ROOT", rootDir, 1); } JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; // 虛擬機創建【見小節2.3】 if (startVm(&mJavaVM, &env, zygote) != 0) { return; } onVmCreated(env); // JNI方法注冊【見小節2.4】 if (startReg(env) < 0) { return; } jclass stringClass; jobjectArray strArray; jstring classNameStr; //等價 strArray= new String[options.size() + 1]; stringClass = env->FindClass("java/lang/String"); strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); //等價 strArray[0] = "com.android.internal.os.ZygoteInit" classNameStr = env->NewStringUTF(className); env->SetObjectArrayElement(strArray, 0, classNameStr); //等價 strArray[1] = "start-system-server"; // strArray[2] = "--abi-list=xxx"; //其中xxx為系統響應的cpu架構類型,比如arm64-v8a. for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); env->SetObjectArrayElement(strArray, i + 1, optionsStr); } //將"com.android.internal.os.ZygoteInit"轉換為"com/android/internal/os/ZygoteInit" char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ... } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); // 調用ZygoteInit.main()方法【見小節3.1】 env->CallStaticVoidMethod(startClass, startMeth, strArray); } //釋放相應對象的內存空間 free(slashClassName); mJavaVM->DetachCurrentThread(); mJavaVM->DestroyJavaVM(); }
2.3 startVm
[–> AndroidRuntime.cpp]
創建Java虛擬機方法的主要篇幅是關於虛擬機參數的設置,下面只列舉部分在調試優化過程中常用參數。
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) { // JNI檢測功能,用於native層調用jni函數時進行常規檢測,比較弱字符串格式是否符合要求,資源是否正確釋放。該功能一般用於早期系統調試或手機Eng版,對於User版往往不會開啟,引用該功能比較消耗系統CPU資源,降低系統性能。 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; } } if (checkJni) { addOption("-Xcheck:jni"); } //虛擬機產生的trace文件,主要用於分析系統問題,路徑默認為/data/anr/traces.txt parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:"); //對於不同的軟硬件環境,這些參數往往需要調整、優化,從而使系統達到最佳性能 parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m"); parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m"); parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit="); parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree="); parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree="); parseRuntimeOption("dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization="); ... //preloaded-classes文件內容是由WritePreloadedClassFile.java生成的, //在ZygoteInit類中會預加載工作將其中的classes提前加載到內存,以提高系統性能 if (!hasFile("/system/etc/preloaded-classes")) { return -1; } //初始化虛擬機 if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { ALOGE("JNI_CreateJavaVM failed\n"); return -1; } }
2.4 startReg
[–> AndroidRuntime.cpp]
int AndroidRuntime::startReg(JNIEnv* env)
{
//設置線程創建方法為javaCreateThreadEtc 【見小節2.4.1】 androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); env->PushLocalFrame(200); //進程NI方法的注冊【見小節2.4.2】 if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { env->PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL); return 0; }
2.4.1 androidSetCreateThreadFunc
[-> Threads.cpp]
void androidSetCreateThreadFunc(android_create_thread_fn func) { gCreateThreadFn = func; }
虛擬機啟動后startReg()過程,會設置線程創建函數指針gCreateThreadFn
指向javaCreateThreadEtc
.
2.4.2 register_jni_procs
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env) { for (size_t i = 0; i < count; i++) { //【見小節2.4.3】 if (array[i].mProc(env) < 0) { return -1; } } return 0; }
2.4.3 gRegJNI.mProc
static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_RuntimeInit), REG_JNI(register_android_os_Binder), ... };
array[i]是指gRegJNI數組, 該數組有100多個成員。其中每一項成員都是通過REG_JNI宏定義的:
#define REG_JNI(name) { name } struct RegJNIRec { int (*mProc)(JNIEnv*); };
可見,調用mProc
,就等價於調用其參數名所指向的函數。 例如REG_JNI(register_com_android_internal_os_RuntimeInit).mProc也就是指進入register_com_android_internal_os_RuntimeInit方法,接下來就繼續以此為例來說明:
int register_com_android_internal_os_RuntimeInit(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit", gMethods, NELEM(gMethods)); } //gMethods:java層方法名與jni層的方法的一一映射關系 static JNINativeMethod gMethods[] = { { "nativeFinishInit", "()V", (void*) com_android_internal_os_RuntimeInit_nativeFinishInit }, { "nativeZygoteInit", "()V", (void*) com_android_internal_os_RuntimeInit_nativeZygoteInit }, { "nativeSetExitWithoutCleanup", "(Z)V", (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup }, };
三. 進入Java層
前面[小節2.2]AndroidRuntime.start()執行到最后通過反射調用到ZygoteInit.main(),見下文:
3.1 ZygoteInit.main
[–>ZygoteInit.java]
public static void main(String argv[]) { try { RuntimeInit.enableDdms(); //開啟DDMS功能 SamplingProfilerIntegration.start(); boolean startSystemServer = false; String socketName = "zygote"; String abiList = null; for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = 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]); } } ... registerZygoteSocket(socketName); //為Zygote注冊socket【見小節3.2】 preload(); // 預加載類和資源【見小節3.3】 SamplingProfilerIntegration.writeZygoteSnapshot(); gcAndFinalize(); //GC操作 if (startSystemServer) { startSystemServer(abiList, socketName);//啟動system_server【見小節3.4】 } runSelectLoop(abiList); //進入循環模式【見小節3.5】 closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); //啟動system_server中會講到。 } catch (RuntimeException ex) { closeServerSocket(); throw ex; } }
在異常捕獲后調用的方法caller.run(),會在后續的system_server文章會講到。
3.2 registerZygoteSocket
[–>ZygoteInit.java]
private static void registerZygoteSocket(String socketName) { if (sServerSocket == null) { int fileDesc; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try { String env = System.getenv(fullSocketName); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { ... } try { FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc); //設置文件描述符 sServerSocket = new LocalServerSocket(fd); //創建Socket的本地服務端 } catch (IOException ex) { ... } } }
3.3 preload
[–>ZygoteInit.java]
static void preload() { //預加載位於/system/etc/preloaded-classes文件中的類 preloadClasses(); //預加載資源,包含drawable和color資源 preloadResources(); //預加載OpenGL preloadOpenGL(); //通過System.loadLibrary()方法, //預加載"android","compiler_rt","jnigraphics"這3個共享庫 preloadSharedLibraries(); //預加載 文本連接符資源 preloadTextResources(); //僅用於zygote進程,用於內存共享的進程 WebViewFactory.prepareWebViewInZygote(); }
執行Zygote進程的初始化,對於類加載,采用反射機制Class.forName()方法來加載。對於資源加載,主要是 com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists,在應用程序中以com.android.internal.R.xxx開頭的資源,便是此時由Zygote加載到內存的。
zygote進程內加載了preload()方法中的所有資源,當需要fork新進程時,采用copy on write技術,如下:
3.4 startSystemServer
[–>ZygoteInit.java]
private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException { long capabilities = posixCapabilitiesAsBits( OsConstants.CAP_BLOCK_SUSPEND, 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_RESOURCE, OsConstants.CAP_SYS_TIME, OsConstants.CAP_SYS_TTY_CONFIG ); //參數准備 String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007", "--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.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); // fork子進程,用於運行system_server pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } //進入子進程system_server if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } // 完成system_server進程剩余的工作 handleSystemServerProcess(parsedArgs); } return true; }
准備參數並fork新進程,從上面可以看出system server進程參數信息為uid=1000,gid=1000,進程名為sytem_server,從zygote進程fork新進程后,需要關閉zygote原有的socket。另外,對於有兩個zygote進程情況,需等待第2個zygote創建完成。更多詳情見Android系統啟動-systemServer上篇。
3.5 runSelectLoop
[–>ZygoteInit.java]
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); //sServerSocket是socket通信中的服務端,即zygote進程。保存到fds[0] fds.add(sServerSocket.getFileDescriptor()); peers.add(null); while (true) { 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 { //處理輪詢狀態,當pollFds有事件到來則往下執行,否則阻塞在這里 Os.poll(pollFds, -1); } catch (ErrnoException ex) { ... } for (int i = pollFds.length - 1; i >= 0; --i) { //采用I/O多路復用機制,當接收到客戶端發出連接請求 或者數據處理請求到來,則往下執行; // 否則進入continue,跳出本次循環。 if ((pollFds[i].revents & POLLIN) == 0) { continue; } if (i == 0) { //即fds[0],代表的是sServerSocket,則意味着有客戶端連接請求; // 則創建ZygoteConnection對象,並添加到fds。 ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); //添加到fds. } else { //i>0,則代表通過socket接收來自對端的數據,並執行相應操作【見小節3.6】 boolean done = peers.get(i).runOnce(); if (done) { peers.remove(i); fds.remove(i); //處理完則從fds中移除該文件描述符 } } } } }
Zygote采用高效的I/O多路復用機制,保證在沒有客戶端連接請求或數據處理時休眠,否則響應客戶端的請求。
3.6 runOnce
[-> ZygoteConnection.java]
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; try { //讀取socket客戶端發送過來的參數列表 args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { ... return true; } ... try { //將binder客戶端傳遞過來的參數,解析成Arguments對象格式 parsedArgs = new Arguments(args); ... //【見小節7】 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir); } catch (Exception e) { ... } try { if (pid == 0) { //子進程執行 IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; //進入子進程流程 handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); return true; } else { //父進程執行 IoUtils.closeQuietly(childPipeFd); childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } }
更多內容,見理解Android進程創建流程
四、總結
Zygote啟動過程的調用流程圖:
- 解析init.zygote.rc中的參數,創建AppRuntime並調用AppRuntime.start()方法;
- 調用AndroidRuntime的startVM()方法創建虛擬機,再調用startReg()注冊JNI函數;
- 通過JNI方式調用ZygoteInit.main(),第一次進入Java世界;
- registerZygoteSocket()建立socket通道,zygote作為通信的服務端,用於響應客戶端請求;
- preload()預加載通用類、drawable和color資源、openGL以及共享庫以及WebView,用於提高app啟動效率;
- zygote完畢大部分工作,接下來再通過startSystemServer(),fork得力幫手system_server進程,也是上層framework的運行載體。
- zygote功成身退,調用runSelectLoop(),隨時待命,當接收到請求創建新進程請求時立即喚醒並執行相應工作。
最后,介紹給通過cmd命令,來fork新進程來執行類中main方法的方式:(啟動后進入RuntimeInit.main)