Zygote进程分析

Zygote进程分析

zygote的启动流程

从init的启动流程中得知,init进程会通过解析init.rc文件执行tigger中的nonecrypted 找到文件对应的main方法。具体文件名称为:/framework/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    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 runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;

    // Everything up to '--' or first non '-' arg goes to the vm.
    //
    // The first argument after the VM args is the "parent dir", which
    // is currently unused.
    //
    // After the parent dir, we expect one or more the following internal
    // arguments :
    //
    // --zygote : Start in zygote mode
    // --start-system-server : Start the system server.
    // --application : Start in application (stand alone, non zygote) mode.
    // --nice-name : The nice name for this process.
    //
    // For non zygote starts, these arguments will be followed by
    // the main class name. All remaining arguments are passed to
    // the main method of this class.
    //
    // For zygote starts, all remaining arguments are passed to the zygote.
    // main function.
    //
    // Note that we must copy argument string values since we will rewrite the
    // entire argument block when we apply the nice name to argv0.
    //
    // As an exception to the above rule, anything in "spaced commands"
    // goes to the vm even though it has a space in it.
    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++) {
        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) {
          if (strcmp(argv[i], spaced_commands[j]) == 0) {
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }

        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.
	//如果zygote为true则代表即将创建该进程
	//如果startSystemServer为true则代表创建zygote时也会创建systemServer
	//系统正常启动都会将这两个boolean 默认给到true
	//init.zygote32.rc 启动zygote服务的指令行:service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
	//因为rc文件启动main后携带了--zygote --start-system-server 这两个参数

	bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;   //将zygote变量设置为true,名称是:zygote
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;  //将startSystemServer变量设置为true
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if (!className.isEmpty()) {
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);

        if (!LOG_NDEBUG) {
          String8 restOfArgs;
          char* const* argv_new = argv + i;
          int argc_new = argc - i;
          for (int k = 0; k < argc_new; ++k) {
            restOfArgs.append("\"");
            restOfArgs.append(argv_new[k]);
            restOfArgs.append("\" ");
          }
          ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
        }
    } else {
        // We're in zygote mode.
		//进入创建zygote模式
		//创建/data/dalvik-cache,为后续会创建Dalvik虚拟机做准备
		maybeCreateDalvikCache();
		//将"start-system-server"放入启动的参数args中
        if (startSystemServer) {
            args.add(String8("start-system-server"));
        }

        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }

        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        //将所有剩余参数传递给args,例如application或tool或start-system-server或abi
        //这些启动参数将会传递到其他进程中,后续取出参数决定是否启动systemServer等操作
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }
//zygote变量为true,将创建zygote,该args启动参数会包含start-system-server
//调用runntime(AppRunntime)的start来启动zygote,将args传入,因为args包含了启动systemServer的标志
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

从代码中得知,app_main.cpp的main方法先解析init.zygote32.rc携带的参数service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server 根据参数 --zygote --start-system-server 值来判断是否创建zygote 同时创建systemserver。通过通过调用runtime.start方法来启动zygote。通过代码得知runtime类是 AppRuntime,并没有start但是AppRuntime的父类AndroidRuntime有start方法,所以得知在app_main.cpp文件里面调用的是AndroidRuntime的start方法。代码路径:\frameworks\base\core\java\com\android\internal\os/ZygoteInit.java 代码如下:

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());
	//默认会启动systemServer
    static const String8 startSystemServer("start-system-server");
    // Whether this is the primary zygote, meaning the zygote which will fork system server.
//是否私有,如果systemServer会被创建时,将设置为私有
	bool primary_zygote = false;

    /*
     * '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) {
		//options就是传递过来的args,默认是包含了start-system-server
        if (options[i] == startSystemServer) {
            primary_zygote = true;
           /* 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)));
        }
    }
	//获取环境变量,这里第一次执行时默认为空,所以rootDir不存在
	// 将直接拿到/system作为rootDir并设置环境变量
    const char* rootDir = getenv("ANDROID_ROOT");
    if (rootDir == NULL) {
        rootDir = "/system";
        if (!hasDir("/system")) {
            LOG_FATAL("No root directory specified, and /system does not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }

    const char* artRootDir = getenv("ANDROID_ART_ROOT");
    if (artRootDir == NULL) {
        LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
        return;
    }

    const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
    if (i18nRootDir == NULL) {
        LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
        return;
    }

    const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
    if (tzdataRootDir == NULL) {
        LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
        return;
    }

    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

    /* start the virtual machine */
	//这里就开始启动虚拟机了
	//jni功能初始化
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
	//创建dalvik虚拟机 ,虚拟机运行在进程里面,虚拟机这块代码实现了内存管理这个功能
	//进程是程序运行的最小的内存空间
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
     //调用startReg函数用来为dvm注册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;

	//通过反射拿到string类型
    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
	//options就是app_main.cpp传递过来的args,包含start-system-server
	//将options转换为array list对象
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
	//从app_main的main哈数得知className为com.android.internal.os.zygoteInit
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
	//将数据转换给java 类型的array数组
    env->SetObjectArrayElement(strArray, 0, classNameStr);

    for (size_t i = 0; i < options.size(); ++i) {
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr != NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
     //启动com.android.internal.os.ZygoteInit,该线程为jvm的主进程,在vm退出之前不会返回
    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 {
    	//通过反射的方式,找到zygoteInit的main函数
        // 若获取到内容则执行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 {
        	// 通过JNI调用ZygoteInit的main函数,将args(strArray)传递到java层
            // 因为ZygoteInit的main函数是Java编写的,因此需要通过JNI调用
            // 所以这里继续跟到java层面:ZygoteInit.java
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
	// 若执行到这里,则会结束zygote创建,关闭jvm,释放字符串所占空间
    free(slashClassName);
	//虚拟机崩溃或退出的时候才会执行到这里
    ALOGD("Shutting down VM\n");
	//将当前线程从虚拟机可见的线程集中分离
	if (mJavaVM->DetachCurrentThread() != JNI_OK)
        ALOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)//销毁前面创建额jvm
        ALOGW("Warning: VM did not shut down cleanly\n");
}

从代码中得知,start方法主要做了:启动虚拟机,注册jni,通过反射的方法找到zygoteInit类的main方法去创建systemServer,创建完成后关闭虚拟机释放字符串所占空间。所以我们先来看zygoteInit的main方法里面做了哪些事情:代码如下:

    @UnsupportedAppUsage
    public static void main(String[] argv) {
        ZygoteServer zygoteServer = null;

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        //调用native函数,功能是确保此时没有其他线程启动
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
        try {
			//设置zygote自己的用户组pid
            Os.setpgid(0, 0);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        Runnable caller;
        try {
			//读取系统是否已经启动完成
            // Store now for StatsLogging later.
            //系统启动到现在的时间,包含设备深度休眠的时间
            final long startTime = SystemClock.elapsedRealtime();
		//该属性值在设备物理重启时为空,reboot重启后为1
		final boolean isRuntimeRestarted = "1".equals(
                    SystemProperties.get("sys.boot_completed"));

			//将行为写入trace log 标记目前正处于ZygoteInit阶段 ,设置boot时间打印log
            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
			//通过systrace来追踪
			TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                    Trace.TRACE_TAG_DALVIK);
			//追踪开始,每个traceBegin()对应一个traceEnd()
			bootTimingsTraceLog.traceBegin("ZygoteInit");
			//使能DDMS,注册所有已知的Java vm 的处理块的监听器
			//线程监听、内存监听、native堆内存监听、debug模式监听
			RuntimeInit.preForkInit();

            boolean startSystemServer = false;
			//zygote进程就是一个socket,名称就叫做zygote
			String zygoteSocketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
				//从AndroidRuntime.cpp中传递上来,已经包含了start-system-server
				//所以startSystemServer= true
                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]);
                }
            }
			//为true,是私有zygote
            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
            if (!isRuntimeRestarted) {
                if (isPrimaryZygote) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
                            startTime);
                } else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
                            startTime);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                        SystemClock.uptimeMillis());
				//预加载
				//这里的预加载是指将java类、资源文件、图像资源等公共资源在zygote启动的时候就进行加载。
				//这样一来,根据fork的copy-on-write机制,其他由zygote fork出来的进程在使用这些资源的时候就不需要
				//再次加载了,而是直接使用。所以这是一种牺牲系统开机时间,来提高系统应用运行时的运行效率的手段
				preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                        SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            }

            // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

            bootTimingsTraceLog.traceEnd(); // ZygoteInit
			//初始化socket,从环境中获取套接字FD(ANDROID_SOCKET_ZYGOTE)
			//若获取不到则创建一个用于和systemServer通信的socket,当systemServer fork出来后socket进程将关闭
			Zygote.initNativeState(isPrimaryZygote);

            ZygoteHooks.stopZygoteNoThreadCreation();
			//根据环境变量(LocalServerSocket)获取zygote文件描述符并重新创建一个socket,可以从这里看到zygote其实就是一个
			//name为"zygote"的socket用来等待ActivityManagerService来请求zygote来fork出新的应用程序进程
			//所以ActivityManagerService 里启动应用程序(APP),都是由该zygote socket进行处理并fork出的子进程
            zygoteServer = new ZygoteServer(isPrimaryZygote);
			//默认为true,将启动systemServer
            if (startSystemServer) {
				//zygote就是一个孵化器,所以这里直接fork出systemServer
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
				//让SystemServer子进程运行起来
				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.
			//让zygote socket(注意不是systemServer zygote)循环运行
			//等待client 进程来请求调用,请求创建子进程(fork 出子进程(例如等待AMS的请求))
			caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with fatal exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
				//停止关于systemServer的socket,保留和AMS通信的socket
				//在initNativeState阶段创建了一个和sysemServer通信的socket
				//接着拿到systemServer socket文件描述符重新创建了一个可以和AMS通信的socket(/dev/socket/zygote)
                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方法主要做了一下工作:
1、禁止启动其他线程;
2、设置pid;
3、解析C/C++层传进来的参数argv;
4、 设置相关日志追踪
5、preload 预加载
6、gcAndFinalize 垃圾回收
7、初始化ZygoteServer
8、fork systemServer 创建systemServer进程
9、zygoteServer.runSelectLoop 让zygote socket循环运行,等待请求创建子进程
其中重点工作是5、preload预加载,6、gcAndFinalize 垃圾回收,8、fork systemServer 创建systemServer进程 9、zygoteServer.runSelectLoop ,

我们先来看看preload预加载主要做了哪些事情,有哪些东西被提前加载了

preload

    static void preload(TimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");
        bootTimingsTraceLog.traceBegin("BeginPreload");
		//调用ZygoteHooks.onBeginPreload()
		beginPreload();
        bootTimingsTraceLog.traceEnd(); // BeginPreload
        bootTimingsTraceLog.traceBegin("PreloadClasses");
		//预加载一些类
		preloadClasses();
        bootTimingsTraceLog.traceEnd(); // PreloadClasses
        bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
		//加载一些应用程序使用但不能放入引导类路径的jar包库,这些库过去是引导类路径的一部分,但必须删除。
		//由于向后兼容性的原因,旧的系统应用仍然会使用它们,因此他们被缓存在这里以保持性能特征。
		cacheNonBootClasspathClassLoaders();
        bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
        bootTimingsTraceLog.traceBegin("PreloadResources");
		//加载常用资源,以便它们可以跨进程共享,比如apk开发常用的color,drawble等资源
        preloadResources();
        bootTimingsTraceLog.traceEnd(); // PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
		//一些被大多数app进程加载的内容,需要通过hal来添加(native)
		nativePreloadAppProcessHALs();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
		//根据属性ro.zygote.disable_gl_preload来判断是否禁止预加载图像驱动相关内容(native)
		maybePreloadGraphicsDriver();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
		//加载几个共享库:libandroid.so、libcompiler_rt.so、libjnigraphics.so
		preloadSharedLibraries();
		//启动字体缓存,设置Typeface
		preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
		//为了内存共享,webViewFactory执行所有必须在zygote进程在运行的初始化
		WebViewFactory.prepareWebViewInZygote();
        endPreload();
		//注册AndroidKeyStoreProvider并预热已经注册的provider
        warmUpJcaProviders();
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }

可以看到预加载一些Java类、资源文件、图像资源等公共资源在zygote启动的时候就进行加载。这样一来,根据fork的copy-on-write机制,其他由zygote fork出来的进程在使用这些资源的时候就不需要再次加载了,而是直接使用。所以这是一种牺牲系统开机时间,来提高系统应用运行时的运行效率的手段。
其中 preloadClasses是读取/system/etc/preloaded-classes文件。/system/etc/preloaded-classes这个文件中每行一个全限定名格式的类(#开头的注释行和空白行则自动跳过)。该文件是由文件frameworks\base\tools\preload\WritePreloadedClassFile.java自动生成,其对于哪些类需要预加载有明确的说明:

/*
* pie\frameworks\base\tools\preload\WritePreloadedClassFile.java
* The set of classes to preload. We preload a class if:
* a) it's loaded in the bootclasspath (i.e., is a system class)                1、即系统类
* b) it takes > MIN_LOAD_TIME_MICROS = 1250 us to load, and                    2、加载时长超过1250ms的类
* c) it's loaded by more than one process, or it's loaded by anapplication     3、不止一个进程会去加载的类
*/

###gcAndFinalize
gcAndFinalize()方法主要就是在预加载动作之后、后续从zygote fork其他进程的动作之前,进行的一次垃圾回收

 /**
     * Runs several special GCs to try to clean up a few generations of softly- and final-reachable
     * objects, along with any other garbage. This is only useful just before a fork().
     */
    private static void gcAndFinalize() {
        ZygoteHooks.gcAndFinalize();
    }
/libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
    @SystemApi(client = MODULE_LIBRARIES)
    @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
    public static void gcAndFinalize() {
        final VMRuntime runtime = VMRuntime.getRuntime();

        /* runFinalizationSync() lets finalizers be called in Zygote,
         * which doesn't have a HeapWorker thread.
         */
        System.gc();
        runtime.runFinalizationSync();
        System.gc();
    }

forkSystemServer()

forksystemServer方法就是创建systemServer进程。zygote首先fork出了它的第一个进程,然后将该进程改名为system_server。我将在下一篇文章中记录

runSelectLoop()

zygote除了fork出system_server进程这个任务外,还有一个重要的任务,那就是接收AMS(ActivityManagerService)发来创建java层应用程序的请求,fork出一个个进程,并在新进程中执行该请求中相关应用程序的main方法。上层的一个个应用程序就是这样通过zygote创建而来,因为应用程序都是由zygote孕育而来,所以就不难理解zygote(受精卵)的名称的由来了

  /**
     * 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.
     * @param abiList list of ABIs supported by this zygote.
     */
    Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
        ArrayList<ZygoteConnection> peers = new ArrayList<>();
		//拿到socket的文件描述符 ,先将server soket加入到这个socketFDS列表
        socketFDs.add(mZygoteSocket.getFileDescriptor());
        peers.add(null);

        mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;

        while (true) {//时间间隔持续轮询
            fetchUsapPoolPolicyPropsWithMinInterval();
            mUsapPoolRefillAction = UsapPoolRefillAction.NONE;

            int[] usapPipeFDs = null;
            StructPollfd[] pollFDs;

            // Allocate enough space for the poll structs, taking into account
            // the state of the USAP pool for this Zygote (could be a
            // regular Zygote, a WebView Zygote, or an AppZygote).
            if (mUsapPoolEnabled) {
                usapPipeFDs = Zygote.getUsapPipeFDs();
                pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
            } else {
                pollFDs = new StructPollfd[socketFDs.size()];
            }

            /*
             * For reasons of correctness the USAP pool pipe and event FDs
             * must be processed before the session and server sockets.  This
             * is to ensure that the USAP pool accounting information is
             * accurate when handling other requests like API deny list
             * exemptions.
             */

            int pollIndex = 0;
            for (FileDescriptor socketFD : socketFDs) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = socketFD;
                pollFDs[pollIndex].events = (short) POLLIN;
                ++pollIndex;
            }

            final int usapPoolEventFDIndex = pollIndex;

            if (mUsapPoolEnabled) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = mUsapPoolEventFD;
                pollFDs[pollIndex].events = (short) POLLIN;
                ++pollIndex;

                // The usapPipeFDs array will always be filled in if the USAP Pool is enabled.
                assert usapPipeFDs != null;
                for (int usapPipeFD : usapPipeFDs) {
                    FileDescriptor managedFd = new FileDescriptor();
                    managedFd.setInt$(usapPipeFD);

                    pollFDs[pollIndex] = new StructPollfd();
                    pollFDs[pollIndex].fd = managedFd;
                    pollFDs[pollIndex].events = (short) POLLIN;
                    ++pollIndex;
                }
            }

            int pollTimeoutMs;

            if (mUsapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) {
                pollTimeoutMs = -1;
            } else {
                long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp;

                if (elapsedTimeMs >= mUsapPoolRefillDelayMs) {
                    // The refill delay has elapsed during the period between poll invocations.
                    // We will now check for any currently ready file descriptors before refilling
                    // the USAP pool.
                    pollTimeoutMs = 0;
                    mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
                    mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;

                } else if (elapsedTimeMs <= 0) {
                    // This can occur if the clock used by currentTimeMillis is reset, which is
                    // possible because it is not guaranteed to be monotonic.  Because we can't tell
                    // how far back the clock was set the best way to recover is to simply re-start
                    // the respawn delay countdown.
                    pollTimeoutMs = mUsapPoolRefillDelayMs;

                } else {
                    pollTimeoutMs = (int) (mUsapPoolRefillDelayMs - elapsedTimeMs);
                }
            }

            int pollReturnValue;
            try {
                pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }

            if (pollReturnValue == 0) {
                // The poll returned zero results either when the timeout value has been exceeded
                // or when a non-blocking poll is issued and no FDs are ready.  In either case it
                // is time to refill the pool.  This will result in a duplicate assignment when
                // the non-blocking poll returns zero results, but it avoids an additional
                // conditional in the else branch.
                mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
                mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;

            } else {
                boolean usapPoolFDRead = false;

                while (--pollIndex >= 0) {
                    if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                        continue;
                    }

					//server socket 最先加入fds,因此这里是server socket收到的数据
                    if (pollIndex == 0) {
                        // Zygote server socket
						//acceptCommandPeer函数得到zygoteConnection类并添加到socket连接列表peers中
						//接着将该zygoteConnection的文件描述符添加到fd列表fds中,以便可以接收到ActivityManagerService发送过来的请求
            			ZygoteConnection newPeer = acceptCommandPeer(abiList);
						//加入到peer和fds,即下一次也开始监听
						peers.add(newPeer);
                        socketFDs.add(newPeer.getFileDescriptor());
                    } else if (pollIndex < usapPoolEventFDIndex) {//说明接收到AMS通过socket发送过来创建应用程序的请求
                        // Session socket accepted from the Zygote server socket

                        try {
							//有socket连接时创建zygoteConnection对象,并添加到pollFDS
                            ZygoteConnection connection = peers.get(pollIndex);
                            boolean multipleForksOK = !isUsapPoolEnabled()
                                    && ZygoteHooks.isIndefiniteThreadSuspensionSafe();
                            final Runnable command =
                                    connection.processCommand(this, multipleForksOK);

                            // 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 processCommand hasn't called "exec".
                                if (command == null) {
                                    throw new IllegalStateException("command == null");
                                }

                                return command;//依然是提供Runnable接口,通过反射机制执行目标应用程序的main方法
                            } 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 processCommand. This
                                // shows up as a regular POLLIN event in our regular processing
                                // loop.
                                //处理完后,关闭socket连接,并从peers和socketFDs列表中移除
                                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.  The `continue` statements below ensure that
                        // the messagePayload will always be valid if we complete the try block
                        // without an exception.
                        long messagePayload;

                        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;
                    }
                }

                if (usapPoolFDRead) {
                    int usapPoolCount = Zygote.getUsapPoolCount();

                    if (usapPoolCount < mUsapPoolSizeMin) {
                        // Immediate refill
                        mUsapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE;
                    } else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) {
                        // Delayed refill
                        mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
                    }
                }
            }

            if (mUsapPoolRefillAction != UsapPoolRefillAction.NONE) {
                int[] sessionSocketRawFDs =
                        socketFDs.subList(1, socketFDs.size())
                                .stream()
                                .mapToInt(FileDescriptor::getInt$)
                                .toArray();

                final boolean isPriorityRefill =
                        mUsapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE;

                final Runnable command =
                        fillUsapPool(sessionSocketRawFDs, isPriorityRefill);

                if (command != null) {
                    return command;
                } else if (isPriorityRefill) {
                    // Schedule a delayed refill to finish refilling the pool.
                    mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
                }
            }
        }
    }

循环间隔一段时间轮询连接socket消息,看是否有AMS客户端发过来创建应用程序的请求,有的话则通过pie\frameworks\base\core\java\com\android\internal\os\ZygoteConnection.processCommand()方法创建进程并启动目标应用程序。

###总结:zygote进程主要做了启动虚拟机、注册JNI函数、进入java世界,然后fork出system_server进程,之后作为守护进程监听并处理创建普通应用程序的工作。参考图片如下:添加链接描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值