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

相关文章

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

一文带你了解SpringBoot中启动参数的各种用法

《一文带你了解SpringBoot中启动参数的各种用法》在使用SpringBoot开发应用时,我们通常需要根据不同的环境或特定需求调整启动参数,那么,SpringBoot提供了哪些方式来配置这些启动参... 目录一、启动参数的常见传递方式二、通过命令行参数传递启动参数三、使用 application.pro

SpringBoot项目启动报错"找不到或无法加载主类"的解决方法

《SpringBoot项目启动报错找不到或无法加载主类的解决方法》在使用IntelliJIDEA开发基于SpringBoot框架的Java程序时,可能会出现找不到或无法加载主类com.example.... 目录一、问题描述二、排查过程三、解决方案一、问题描述在使用 IntelliJ IDEA 开发基于

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

Spring、Spring Boot、Spring Cloud 的区别与联系分析

《Spring、SpringBoot、SpringCloud的区别与联系分析》Spring、SpringBoot和SpringCloud是Java开发中常用的框架,分别针对企业级应用开发、快速开... 目录1. Spring 框架2. Spring Boot3. Spring Cloud总结1. Sprin

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory