Zygote启动浅分析

2023-10-17 10:38
文章标签 分析 启动 zygote

本文主要是介绍Zygote启动浅分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 0x00:Zygote的诞生
    • 一.init
    • 二.app_main.cpp
  • 0x01:Zygote从C/C++世界到Java世界
      • 一.启动参数
      • 二.AndroidRuntime
  • 0x02:Zygote的Java世界
    • 一.ZygoteInit的main函数
    • 二.forkSystemServer
    • 三.handleSystemServerProcess
      • (1) nativeZygoteInit
      • (2) applicationInit
    • 四.runSelectLoop

0x00:Zygote的诞生

一.init

Zygote翻译为"受精卵"。“受精卵"顾名思义,作为孵化生命的起始,显然通过它可以创造整个Android世界。
那么Zygote从何处诞生的呢?
作为Android系统启动的第一个进程"init进程”。这里便是Zygote诞生之处。
init进程的源码可以查看:“system/core/init/init.cpp”中(init.cpp)。
init进程首先创建文件夹,挂载设备等。其中最重要的一步是解析"init.rc"文件。该文件位于“system/core/rootdir/init.rc”中(init.rc)。
在init.rc中你可以看到这样一句话import /init.${ro.zygote}.rc。每一个ro.zygote对应四个值,zygote32、zygote64、zygote32_64、zygote64_32 。

  • 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
    以上配置文件都在system/core/rootdir/目录下面。这里只单拿出"init.zygote64_32.rc"(init.zygote64_32.rc)来做分析。
    直接上代码:
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 reserved_disk
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
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/tasksservice 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 reserved_disk
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks

二.app_main.cpp

Zygote进程代码在app_main.cpp中。(/frameworks/base/cmds/app_process/app_main.cpp)
在app_main.cpp中需要对参数进行解析。主要有一下两种情况

  • –start-system-server参数形式,该参数用于初始化SystemServer进程
  • –application参数形式,该参数用于启动一个新的普通应用。

代码如下:

int main(int argc, char* const argv[])
{
// 省略代码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) {//需要启动SystemServerstartSystemServer = true;} else if (strcmp(arg, "--application") == 0) {//表示是application启动模式,也就是普通应用程序application = true;} else if (strncmp(arg, "--nice-name=", 12) == 0) {//进程别名niceName.setTo(arg + 12);} else if (strncmp(arg, "--", 2) != 0) {//application启动的classclassName.setTo(arg);break;} else {--i;break;}}// 省略代码
}

0x01:Zygote从C/C++世界到Java世界

一.启动参数

接下来开始"从C/C++世界到Java世界"
app_main.cpp的main方法的部分代码:

int main(int argc, char* const argv[])
{// 省略代码if (zygote) { // 判断是不是zygote进程// 如果调用ZygoteInit的main函数runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (className) {// 如果调用RuntimeInit的main函数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.");}
}

通过上面的代码我们可以了解到,从C语言世界到Java世界有两条路。第一种是启动Zygote。第二个启动普通应用程序。

二.AndroidRuntime

这里也是对应了上文中app_main.cpp里面的启动模式。那么start函数是什么方法呢。它的实现在AndroidRuntime.cpp
AndroidRuntime.cpp中的start方法

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{/*** 这里的classame是"com.android.internal.os.ZygoteInit"* 或者是"com.android.internal.os.RuntimeInit"**/ALOGD(">>>>>> START %s uid %d <<<<<<\n",className != NULL ? className : "(unknown)", getuid());static const String8 startSystemServer("start-system-server");/** 'startSystemServer == true' means runtime is obsolete and not run from* init.rc anymore, so we print out the boot start event here.*/for (size_t i = 0; i < options.size(); ++i) {if (options[i] == startSystemServer) {/* track our progress through the boot sequence */const int LOG_BOOT_PROGRESS_START = 3000;LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));}}const char* rootDir = getenv("ANDROID_ROOT");if (rootDir == NULL) {rootDir = "/system";if (!hasDir("/system")) {LOG_FATAL("No root directory specified, and /android does not exist.");return;}setenv("ANDROID_ROOT", rootDir, 1);}//const char* kernelHack = getenv("LD_ASSUME_KERNEL");//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);/* start the virtual machine */JniInvocation jni_invocation;jni_invocation.Init(NULL);JNIEnv* env;// 启动虚拟机if (startVm(&mJavaVM, &env, zygote) != 0) {return;}onVmCreated(env);// 注册jni函数if (startReg(env) < 0) {ALOGE("Unable to register all android natives\n");return;}/** We want to call main() with a String array with arguments in it.* At present we have two arguments, the class name and an option string.* Create an array to hold them.*/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);}// 将className字符串的.转成/char* slashClassName = toSlashClassName(className != NULL ? 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 {// 调用"ZygoteInit的main方法"env->CallStaticVoidMethod(startClass, startMeth, strArray); #if 0if (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");
}

将className字符串的.转成/

char* AndroidRuntime::toSlashClassName(const char* className)
{char* result = strdup(className);for (char* cp = result; *cp != '\0'; cp++) {if (*cp == '.') {*cp = '/';}}return result;
}

由上面的代码可知,启动过程是

  1. 启动虚拟机。
  2. 注册jni函数。
  3. 通过CallStaticVoidMethod方法执行"ZygoteInit"的main方法。

0x02:Zygote的Java世界

一.ZygoteInit的main函数

通过上面的分析我们知道。最后执行到了ZygoteInit.java的main函数中。
代码如下:

	@UnsupportedAppUsagepublic static void main(String argv[]) {ZygoteServer zygoteServer = null;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);}Runnable caller;try {if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {MetricsLogger.histogram(null, "boot_zygote_init",(int) SystemClock.elapsedRealtime());}String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK);bootTimingsTraceLog.traceBegin("ZygoteInit");RuntimeInit.preForkInit();boolean startSystemServer = false;String zygoteSocketName = "zygote";String abiList = null;boolean enableLazyPreload = false;// 解析传到main函数里面的参数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)) {zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());} else {throw new RuntimeException("Unknown command line argument: " + argv[i]);}}final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);if (abiList == null) {throw new RuntimeException("No ABI list supplied.");}if (!enableLazyPreload) {bootTimingsTraceLog.traceBegin("ZygotePreload");EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());// 预加载class和Resourcepreload(bootTimingsTraceLog);EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());bootTimingsTraceLog.traceEnd(); // ZygotePreload} else {Zygote.resetNicePriority();}// Do an initial gc to clean up after startupbootTimingsTraceLog.traceBegin("PostZygoteInitGC");gcAndFinalize();bootTimingsTraceLog.traceEnd(); // PostZygoteInitGCbootTimingsTraceLog.traceEnd(); // ZygoteInit// Disable tracing so that forked processes do not inherit stale tracing tags from// Zygote.Trace.setTracingEnabled(false, 0);Zygote.initNativeState(isPrimaryZygote);ZygoteHooks.stopZygoteNoThreadCreation();// 创建ZygoteServerzygoteServer = new ZygoteServer(isPrimaryZygote);if (startSystemServer) {// fork出一个SystemServer,最后调用fork函数Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);// {@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");// 无限循环监听,不断处理来自 Socket 的请求。caller = zygoteServer.runSelectLoop(abiList);} catch (Throwable ex) {Log.e(TAG, "System zygote died with exception", ex);throw ex;} finally {if (zygoteServer != null) {zygoteServer.closeServerSocket();}}// We're in the child process and have exited the select loop. Proceed to execute the// command.if (caller != null) {caller.run();}}

从上面的一大段代码可以看出主要的流程是:

  1. 解析传到ZygoteInit类的main函数里面的参数
  2. 预加载class和Resource
  3. 创建ZygoteServer
  4. fork一个SystemServer
  5. 执行runSelectLoop函数

其中我们需要关心的是第三点和第四点,接下来一个一个函数的分析。

二.forkSystemServer

ZygoteInit的forkSystemServer函数

	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,OsConstants.CAP_BLOCK_SUSPEND);/* Containers run without some capabilities, so drop any caps that are not available. */StructCapUserHeader header = new StructCapUserHeader(OsConstants._LINUX_CAPABILITY_VERSION_3, 0);StructCapUserData[] data;try {data = Os.capget(header);} catch (ErrnoException ex) {throw new RuntimeException("Failed to capget()", ex);}capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);/* 准备SystemServer的参数 */String args[] = {"--setuid=1000","--setgid=1000","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"+ "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011","--capabilities=" + capabilities + "," + capabilities,"--nice-name=system_server","--runtime-args","--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,"com.android.server.SystemServer",};ZygoteArguments parsedArgs = null;int pid;try {parsedArgs = new ZygoteArguments(args);Zygote.applyDebuggerSystemProperty(parsedArgs);Zygote.applyInvokeWithSystemProperty(parsedArgs);if (shouldProfileSystemServer()) {parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;}// 调用到Zygote的forkSystemServer,最后调用linux函数forkpid = Zygote.forkSystemServer(parsedArgs.mUid, parsedArgs.mGid,parsedArgs.mGids,parsedArgs.mRuntimeFlags,null,parsedArgs.mPermittedCapabilities,parsedArgs.mEffectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}/* 子进程 */if (pid == 0) {if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}zygoteServer.closeServerSocket();// 调用handleSystemServerProcess函数return handleSystemServerProcess(parsedArgs);}return null;}

三.handleSystemServerProcess

	private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {// set umask to 0077 so new files and directories will default to owner-only permissions.Os.umask(S_IRWXG | S_IRWXO);if (parsedArgs.mNiceName != null) {Process.setArgV0(parsedArgs.mNiceName);}final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");if (systemServerClasspath != null) {if (performSystemServerDexOpt(systemServerClasspath)) {// Throw away the cached classloader. If we compiled here, the classloader would// not have had AoT-ed artifacts.// Note: This only works in a very special environment where selinux enforcement is// disabled, e.g., Mac builds.sCachedSystemServerClassLoader = null;}// Capturing profiles is only supported for debug or eng builds since selinux normally// prevents it.if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {try {Log.d(TAG, "Preparing system server profile");prepareSystemServerProfile(systemServerClasspath);} catch (Exception e) {Log.wtf(TAG, "Failed to set up system server profile", e);}}}if (parsedArgs.mInvokeWith != null) {String[] args = parsedArgs.mRemainingArgs;// If we have a non-null system server class path, we'll have to duplicate the// existing arguments and append the classpath to it. ART will handle the classpath// correctly when we exec a new process.if (systemServerClasspath != null) {String[] amendedArgs = new String[args.length + 2];amendedArgs[0] = "-cp";amendedArgs[1] = systemServerClasspath;System.arraycopy(args, 0, amendedArgs, 2, args.length);args = amendedArgs;}WrapperInit.execApplication(parsedArgs.mInvokeWith,parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,VMRuntime.getCurrentInstructionSet(), null, args);throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");} else {createSystemServerClassLoader();ClassLoader cl = sCachedSystemServerClassLoader;if (cl != null) {Thread.currentThread().setContextClassLoader(cl);}/** ZygoteInit的zygoteInit函数*/return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mRemainingArgs, cl);}/* should never reach here */}public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {if (RuntimeInit.DEBUG) {Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");}Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");RuntimeInit.redirectLogStreams();// 关键代码RuntimeInit.commonInit();ZygoteInit.nativeZygoteInit();return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);}

到这里我们发现handleSystemServerProcess最后执行了"commonInit",“nativeZygoteInit”,"applicationInit"三个方法。这里最重要的是nativeZygoteInit和applicationInit

(1) nativeZygoteInit

nativeZygoteInit是一个native方法,该方法在AndroidRuntime的com_android_internal_os_ZygoteInit_nativeZygoteInit方法中。

static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{// gCurRuntime是AndroidRuntime的对象gCurRuntime->onZygoteInit();
}

onZygoteInit方法在AppRuntime类中

	virtual void onStarted(){// 启动binder线程池sp<ProcessState> proc = ProcessState::self();ALOGV("App process: starting thread pool.\n");proc->startThreadPool();AndroidRuntime* ar = AndroidRuntime::getRuntime();ar->callMain(mClassName, mClass, mArgs);IPCThreadState::self()->stopProcess();hardware::IPCThreadState::self()->stopProcess();}

(2) applicationInit

	protected static Runnable applicationInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {nativeSetExitWithoutCleanup(true);VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);final Arguments args = new Arguments(argv);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);// return findStaticMain(args.startClass, args.startArgs, classLoader);}// findStaticMain方法// 通过className区分调用哪个类的main方法protected static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {Class<?> cl;try {cl = Class.forName(className, true, classLoader);} catch (ClassNotFoundException ex) {throw new RuntimeException("Missing class when invoking static main " + className,ex);}// 通过反射执行SystemServer Java代码的main函数Method m;try {m = cl.getMethod("main", new Class[] { String[].class });} catch (NoSuchMethodException ex) {throw new RuntimeException("Missing static main on " + className, ex);} catch (SecurityException ex) {throw new RuntimeException("Problem getting static main on " + className, ex);}int modifiers = m.getModifiers();if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {throw new RuntimeException("Main method is not public and static on " + className);}/** This throw gets caught in ZygoteInit.main(), which responds* by invoking the exception's run() method. This arrangement* clears up all the stack frames that were required in setting* up the process.*/return new MethodAndArgsCaller(m, argv);}

四.runSelectLoop

	Runnable runSelectLoop(String abiList) {ArrayList<FileDescriptor> socketFDs = new ArrayList<>();ArrayList<ZygoteConnection> peers = new ArrayList<>();socketFDs.add(mZygoteSocket.getFileDescriptor());peers.add(null);// 无限循环while (true) {// 省略代码while (--pollIndex >= 0) {if ((pollFDs[pollIndex].revents & POLLIN) == 0) {continue;}if (pollIndex == 0) {// 创建ZygoteConnectionZygoteConnection newPeer = acceptCommandPeer(abiList);peers.add(newPeer);socketFDs.add(newPeer.getFileDescriptor());} else if (pollIndex < usapPoolEventFDIndex) {// Session socket accepted from the Zygote server sockettry {ZygoteConnection connection = peers.get(pollIndex);// 重要代码,调用processOneCommandfinal Runnable command = connection.processOneCommand(this);// TODO (chriswailes): Is this extra check necessary?if (mIsForkChild) {// We're in the child. We should always have a command to run at this// stage if processOneCommand hasn't called "exec".if (command == null) {throw new IllegalStateException("command == null");}return command;} else {// We're in the server - we should never have any commands to run.if (command != null) {throw new IllegalStateException("command != null");}// We don't know whether the remote side of the socket was closed or// not until we attempt to read from it from processOneCommand. This// shows up as a regular POLLIN event in our regular processing loop.if (connection.isClosedByPeer()) {connection.closeSocket();peers.remove(pollIndex);socketFDs.remove(pollIndex);}}} catch (Exception e) {if (!mIsForkChild) {// We're in the server so any exception here is one that has taken place// pre-fork while processing commands or reading / writing from the// control socket. Make a loud noise about any such exceptions so that// we know exactly what failed and why.Slog.e(TAG, "Exception executing zygote command: ", e);// Make sure the socket is closed so that the other end knows// immediately that something has gone wrong and doesn't time out// waiting for a response.ZygoteConnection conn = peers.remove(pollIndex);conn.closeSocket();socketFDs.remove(pollIndex);} else {// We're in the child so any exception caught here has happened post// fork and before we execute ActivityThread.main (or any other main()// method). Log the details of the exception and bring down the process.Log.e(TAG, "Caught post-fork exception in child process.", e);throw e;}} finally {// Reset the child flag, in the event that the child process is a child-// zygote. The flag will not be consulted this loop pass after the Runnable// is returned.mIsForkChild = false;}} else {// Either the USAP pool event FD or a USAP reporting pipe.// If this is the event FD the payload will be the number of USAPs removed.// If this is a reporting pipe FD the payload will be the PID of the USAP// that was just specialized.long messagePayload = -1;try {byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {DataInputStream inputStream =new DataInputStream(new ByteArrayInputStream(buffer));messagePayload = inputStream.readLong();} else {Log.e(TAG, "Incomplete read from USAP management FD of size "+ readBytes);continue;}} catch (Exception ex) {if (pollIndex == usapPoolEventFDIndex) {Log.e(TAG, "Failed to read from USAP pool event FD: "+ ex.getMessage());} else {Log.e(TAG, "Failed to read from USAP reporting pipe: "+ ex.getMessage());}continue;}if (pollIndex > usapPoolEventFDIndex) {Zygote.removeUsapTableEntry((int) messagePayload);}usapPoolFDRead = true;}}// 省略代码}}

我们再看下processOneCommand代码:

Runnable processOneCommand(ZygoteServer zygoteServer) {// 省略代码// fork一个子进程pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);try {if (pid == 0) {// 子进程zygoteServer.setForkChild();zygoteServer.closeServerSocket();IoUtils.closeQuietly(serverPipeFd);serverPipeFd = null;// handleChildProc函数return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);} else {// In the parent. A pid < 0 indicates a failure and will be handled in// handleParentProc.IoUtils.closeQuietly(childPipeFd);childPipeFd = null;handleParentProc(pid, serverPipeFd);return null;}} finally {IoUtils.closeQuietly(childPipeFd);IoUtils.closeQuietly(serverPipeFd);}
}

接下来是handleChildProc方法

	private Runnable handleChildProc(ZygoteArguments parsedArgs,FileDescriptor pipeFd, boolean isZygote) {/** By the time we get here, the native code has closed the two actual Zygote* socket connections, and substituted /dev/null in their place.  The LocalSocket* objects still need to be closed properly.*/closeSocket();if (parsedArgs.mNiceName != null) {Process.setArgV0(parsedArgs.mNiceName);}// End of the postFork event.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);if (parsedArgs.mInvokeWith != null) {WrapperInit.execApplication(parsedArgs.mInvokeWith,parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,VMRuntime.getCurrentInstructionSet(),pipeFd, parsedArgs.mRemainingArgs);// Should not get here.throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");} else {if (!isZygote) {// 初始化zygote进程的相关方法,参考上面handleSystemServerProcess里面关于该方法的分析return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mRemainingArgs, null /* classLoader */);} else {// 初始化fork的子进程的相关函数return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mRemainingArgs, null /* classLoader */);}}}

ZygoteInit的childZygoteInit方法:

	static final Runnable childZygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);// 这里和上面的分析一样执行findStaticMain,执行args.startClass参数代表的类的main方法// 如果是一个应用一般是执行ActivityThread的main函数return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);}

从上面的分析可以知道runSelectLoop的流程

  1. while(true)监听socket
  2. 创建ZygoteConnection且调用processOneCommand方法
  3. 执行forkAndSpecialize,fork子进程
  4. fork一个SystemServer
  5. 执行handleChildProc,如果是一个应用一般是执行ActivityThread的main函数
    以上的流程就是打开一个应用的时候,如何去创建,同时执行ActivityThread的函数。

以上就是Zygote启动粗浅分析,其中的大部分细节,可以等到我们以后需要研究和使用的时候去分析。

这篇关于Zygote启动浅分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/224806

相关文章

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

SpringBoot项目启动后自动加载系统配置的多种实现方式

《SpringBoot项目启动后自动加载系统配置的多种实现方式》:本文主要介绍SpringBoot项目启动后自动加载系统配置的多种实现方式,并通过代码示例讲解的非常详细,对大家的学习或工作有一定的... 目录1. 使用 CommandLineRunner实现方式:2. 使用 ApplicationRunne

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结

bat脚本启动git bash窗口,并执行命令方式

《bat脚本启动gitbash窗口,并执行命令方式》本文介绍了如何在Windows服务器上使用cmd启动jar包时出现乱码的问题,并提供了解决方法——使用GitBash窗口启动并设置编码,通过编写s... 目录一、简介二、使用说明2.1 start.BAT脚本2.2 参数说明2.3 效果总结一、简介某些情

python中的与时间相关的模块应用场景分析

《python中的与时间相关的模块应用场景分析》本文介绍了Python中与时间相关的几个重要模块:`time`、`datetime`、`calendar`、`timeit`、`pytz`和`dateu... 目录1. time 模块2. datetime 模块3. calendar 模块4. timeit

python-nmap实现python利用nmap进行扫描分析

《python-nmap实现python利用nmap进行扫描分析》Nmap是一个非常用的网络/端口扫描工具,如果想将nmap集成进你的工具里,可以使用python-nmap这个python库,它提供了... 目录前言python-nmap的基本使用PortScanner扫描PortScannerAsync异