Android源码阅读 --- Zygote

457 阅读5分钟

一. Zygote 简介

Zygote英文为“受精卵”,它是Android系统中十分重要的进程。在Android中Zygote负责孵化新的进程,Android的应用程序进程都是通过zygote孵化启动。Linux 创建应用程序通过写时拷贝(copy on write),先调用fork 创建子进程,执行系统调用exec。而zygote 创建应用程序,只用了fork ,没有调用exec,因为Android应用执行的是java代码。zygote fork出子进程后,子进程只要装载APK文件中的字节码就可以运行了。

zygote通过共享系统库和资源大大加快了应用的启动速度。zygote 初始化时会创建虚拟机,同时把需要的系统库和资源文件加载到内存。zygote fork出子进程后,子进程已经有了各种系统资源,只要装载APK文件中的字节码就可以运行了。

二. Zygote 进程启动过程

1. 启动流程图

image.png

2. Init启动 app_process

Zygote进程实际是由app_process进程执行,app_process进程不仅可以启动Zygote,还可以启动其他系统进程。

1.)Init 启动app_process

init 启动 app_process进程服务

Zygote进程由用户的第一个进程Init进程以service的方式启动。在init.c 中则通过import的方式引入文件:import /init.${ro.zygote}.rc,其中ro.zygote 可能的取值:zygote32, zygote32_64, zygote64, zygote64_32 对应不同的文件有不同的模式配置。

例如:init.zygote32.rc文件

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

2.)启动可执行文件时传递的参数格式

app_process 源码目录frameworks/base/cmds/app_process/app_main.cpp

启动app_process 需要传递一些参数,app_process启动参数格式:app_process [虚拟机参数] 运行目录 参数 [Java类]

虚拟机参数:以符号’-‘ 开头。启动dalvik 虚拟机时传递给虚拟机,用来区分要在虚拟机中运行的类是Zygote,还是在Zygote中运行的其他Android 应用程序。

运行目录:程序的运行目录,通常是/system/bin。(要运行的app_process程序所在的目录)

参数:以符号’—-‘ 开头。参数’--zygote’ 表示要启动zygote进程,参数’--application’ 表示要以普通进程的方式执行java 代码。

Java 类:将要执行的java 类,必须有一个静态方法main。使用参数’—-Zygote’ 时不会执行这个类,而是固定执行ZygoteInit类。

3. app_process main方法主要代码流程

1)创建AppRuntime对象,并保存参数。继承了系统的AndroidRuntime类。AndroidRuntime主要作用是创建和初始化虚拟机


int main(int argc, char* const argv[])

{

    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {

        if (errno != EINVAL) {

            LOG_ALWAYS_FATAL(“PR_SET_NO_NEW_PRIVS failed: %s”, strerror(errno));

            return 12;

        }

    }

AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // 代码(1)

argc—;

argv++;

// 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) { //代码(2)

        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] != ‘-‘) { //代码(3)

        break;

    }

    if (argv[i][1] == ‘-‘ && argv[i][2] == 0) { //代码(4)

        ++i; //skip —-.

        break;

    }

    runtime.addOption(strdup(argv[i])); //代码(5)

}

...

}

代码(1): 创建AppRuntime 对象

代码(2): 这段代码处理以上定义的app_process参数规则的例外情况。在spaced_commands 数组中保存的命令的参数会保存在AppRuntime中,同样会传给虚拟机。

代码(3): 表示如果参数的第一个字母 不是以’-’ 开头(以’-’ 开头表示是虚拟机参数) 结束循环,因为本循环目的是获取虚拟机参数并存储。

代码(4): 表示跳过前缀为"--"的参数。根据app_process参数的定义,前缀为"--"的是app_process启动运行参数

代码(5): 保存获取的参数到AppRuntime 对象中

以上代码主要创建AppRuntime对象,并解析传给app_process的参数,将和虚拟机相关的参数保存到AppRuntime对象中。

2.)解析app_process启动参数


...

// Parse runtime arguments. Stop at first unrecognized option.

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;

        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;

    }

}

解析app_process启动使用的参数。如果启动的是zyogte进程,则strcmp(arg, “--zygote”) == 0,zygote = true ,并niceName固定设置为静态常量ZYGOTE_NICE_NAME。ZYGOTE_NICE_NAME值为zygote64或者zygote,根据不同的系统有不同的取值。niceName会被设置为虚拟机进程的名称。

3.) 解析准备传给ZygoteInit类或者RuntimeInit类的参数


Vector<String8> args;

if (!className.isEmpty()) { //说明启动的是非zygote 的java类

    // 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 {// zygote 模式

    // We're in zygote mode.

    maybeCreateDalvikCache();

    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.

    for (; i < argc; ++i) {

        args.add(String8(argv[i]));

    }

}

如果启动的是zygote模式则className是空值。如果解析的参数中存在className,则说明启动的是非zygote的java类。

startSystemServer为true 则设置将“start-system-server”字符串加入到参数列表args中。

在zygote模式下,本段代码将“start-system-server”,abiFlag,以及所有剩余参数保存到容器args中,并最终会传给ZygoteInit的main方法。

4.) 设置进程名称


if (!niceName.isEmpty()) {

    runtime.setArgv0(niceName.string(), true /* setProcName */);

}

将上面代码获取的niceName设置到AppRuntime中。最终将本进程名称设置为niceName指定的值。

5.) 启动ZygoteInit类

如果启动参数带有”--zygote“,执行ZygoteInit类。所以zygote进程最终执行的java类是ZygoteInit类。ZygoteInit类执行后会进入等待socket事件的无限循环,创建并启动新应用程序。

以下代码可以看到 app_process 除了可以启动Zygote进程,也可以使用它执行系统的Java类


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.");

}

由于ZygoteInit是java代码,所以AndroidRuntime类的start方法在执行ZygoteInit类之前需要做一件很重要的事,初始化整个Java运行环境。

4. AndroidRuntime类的start方法做了哪些事

1.) 启动虚拟机


void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)

{

...

/* start the virtual machine */

JniInvocation jni_invocation;

jni_invocation.Init(NULL);

JNIEnv* env;

if (startVm(&mJavaVM, &env, zygote) != 0) {

    return;

}

onVmCreated(env);

...

}

startVm方法中会根据传入的参数,创建虚拟机并启动虚拟机。如果返回0表示虚拟机创建成功,-1表示创建失败。

其中参数&env为JNIEnv类的接口指针(JNIEnv**),方便访问虚拟机。

2.)调用onVmCreated()

onVmCreated是虚函数,实际调用的是子类AppRuntime 中的重载函数

如果是zygote,则此方法直接返回,不做任何处理


virtual void onVmCreated(JNIEnv* env)

{

if (mClassName.isEmpty()) {

    return; // Zygote. Nothing to do here.

}

/*

* This is a little awkward because the JNI FindClass call uses the

* class loader associated with the native method we're executing in.

* If called in onStarted (from RuntimeInit.finishInit because we're

* launching "am", for example), FindClass would see that we're calling

* from a boot class' native method, and so wouldn't look for the class

* we're trying to look up in CLASSPATH. Unfortunately it needs to,

* because the "am" classes are not boot classes.

*

* The easiest fix is to call FindClass here, early on before we start

* executing boot class Java code and thereby deny ourselves access to

* non-boot classes.

*/

char* slashClassName = toSlashClassName(mClassName.string());

mClass = env->FindClass(slashClassName);

if (mClass == NULL) {

    ALOGE("ERROR: could not find class '%s'\n", mClassName.string());

}

free(slashClassName);

mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));

}

3.) 注册android系统的JNI函数


/*

* Register android functions.

*/

if (startReg(env) < 0) {

    ALOGE("Unable to register all android natives\n");

    return;

}

startReg通过调用register_jni_procs() 函数将全局数组gRegJNI中的JNI本地函数注册到虚拟机中。


/*AndroidRuntime 全局数组*/

static const RegJNIRec gRegJNI[] = {

REG_JNI(register_com_android_internal_os_RuntimeInit),

REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),

REG_JNI(register_android_os_SystemClock),

REG_JNI(register_android_util_EventLog),

REG_JNI(register_android_util_Log),

REG_JNI(register_android_util_MemoryIntArray),

REG_JNI(register_android_util_PathParser),

REG_JNI(register_android_util_StatsLog),

REG_JNI(register_android_util_StatsLogInternal),

REG_JNI(register_android_app_admin_SecurityLog),

REG_JNI(register_android_content_AssetManager),

....

}

4.) 准备调用Java类的main函数的参数


/*

* 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

strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);

assert(strArray != NULL);

classNameStr = env->NewStringUTF(className);

assert(classNameStr != NULL);

// 将classNameStr字符串设置到数组里,即传递过来的参数“com.android.internal.os.ZygoteInit”

env->SetObjectArrayElement(strArray, 0, classNameStr);

// 将传递过来的参数列表中的剩下的参数全部设置到strArray数组中

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

}

如果当前启动的是zygote,那么strArray数组中设置的classNameStr为“com.android.internal.os.ZygoteInit”,其他为app_process解析后传入start方法中的,如“--abi-list=xxx”,“start-system-server”等。

5.)调用ZygoteInit的main方法


/*

* Start VM. This thread becomes the main thread of the VM, and will

* not return until the VM exits.

*/

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 {

        env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0

        if (env->ExceptionCheck())

            threadExitUncaughtException(env);

#endif

}

}

toSlashClassName的作用是将类名中的’.’ 替换成’/'。先通过env->FindClass(slashClassName),找到系统中加载的ZygoteInit类。然后找到main方法的jmethodID,如果不为空,则执行ZygoteInit类的main方法,并将数组strArray作为main函数的参数传入ZygoteInit中。至此,Zygote的初始化过程将转到java层代码。

总结,zygote进程中,AndroidRuntime的start方法主要工作:创建启动虚拟机,注册系统JNI,执行ZygoteInit类的main方法,进入java运行环境。

5. ZygoteInit类main方法的执行过程

ZygoteInit main 方法主要工作有以下几个方面:

1.)解析传递给main函数调用的参数

2.)加载加载Android Application Framework 使用的类与资源


// 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());

    preload(bootTimingsTraceLog);

    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis());

    bootTimingsTraceLog.traceEnd(); // ZygotePreload

} else {

    Zygote.resetNicePriority();

}

正常情况下enableLazyPreload为false,调用preload方法。在preload方法中加载类和资源。分别会调用preloadClasses()和preloadResources()方法。

下面是preload方法主要代码。


static void preload(TimingsTraceLog bootTimingsTraceLog) {

...

preloadClasses();

...

preloadResources();

...

nativePreloadAppProcessHALs();

...

maybePreloadGraphicsDriver();

...

preloadSharedLibraries();

preloadTextResources();

// Ask the WebViewFactory to do any initialization that must run in the zygote process,

// for memory sharing purposes.

WebViewFactory.prepareWebViewInZygote();

endPreload();

...

}

preloadClasses方法加载类到虚拟机。Android将所有需要预加载的Java类存放在文本文件"preload-classes"中。PRELOADED_CLASSES=“/system/etc/preloaded-classes”。preloadClasses主要工作:读取preload-classes文件,使用Class.forName加载类。


private static void preloadClasses() {

final VMRuntime runtime = VMRuntime.getRuntime();

InputStream is;

try {

    is = new FileInputStream(PRELOADED_CLASSES);

} catch (FileNotFoundException e) {

    Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");

    return;

}

...

try {

    BufferedReader br = new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);

    int count = 0;

    String line;

    while ((line = br.readLine()) != null) {

        // Skip comments and blank lines.

        line = line.trim();

        if (line.startsWith("#") || line.equals("")) {

            continue;

        }

        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);

        try {

            if (false) {

                Log.v(TAG, "Preloading " + line + "...");

            }

            // Load and explicitly initialize the given class. Use

            // Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups

            // (to derive the caller's class-loader). Use true to force initialization, and

            // null for the boot classpath class-loader (could as well cache the

            // class-loader of this class in a variable).

            Class.forName(line, true, null);

            count++;

        } catch (ClassNotFoundException e) {

            ...

        }

    ...

} finally {

    IoUtils.closeQuietly(is);

    // Restore default.

    runtime.setTargetHeapUtilization(defaultUtilization);

    // Fill in dex caches with classes, fields, and methods brought in by preloading.

    Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadDexCaches");

    runtime.preloadDexCaches();

    Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

    // Bring back root. We'll need it later if we're in the zygote.

    if (droppedPriviliges) {

        try {

            Os.setreuid(ROOT_UID, ROOT_UID);

            Os.setregid(ROOT_GID, ROOT_GID);

        } catch (ErrnoException ex) {

            throw new RuntimeException("Failed to restore root", ex);

        }

    }

}

}

preloadResources加载系统资源


private static void preloadResources() {

final VMRuntime runtime = VMRuntime.getRuntime();

try {

    mResources = Resources.getSystem();

    mResources.startPreloading();

    if (PRELOAD_RESOURCES) {

        ...

        TypedArray ar = mResources.obtainTypedArray(com.android.internal.R.array.preloaded_drawables);

        int N = preloadDrawables(ar);

        ar.recycle();

        ...

        ar = mResources.obtainTypedArray(com.android.internal.R.array.preloaded_color_state_lists);

        N = preloadColorStateLists(ar);

        ar.recycle();

        Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis() - startTime) + "ms.");

        if (mResources.getBoolean(com.android.internal.R.bool.config_freeformWindowManagement)) {

            startTime = SystemClock.uptimeMillis();

            ar = mResources.obtainTypedArray(com.android.internal.R.array.preloaded_freeform_multi_window_drawables);

            N = preloadDrawables(ar);

            ar.recycle();

            Log.i(TAG, "...preloaded " + N + " resource in " + (SystemClock.uptimeMillis() - startTime) + "ms.");

        }

}

mResources.finishPreloading();

} catch (RuntimeException e) {

    Log.w(TAG, "Failure preloading resources", e);

}

}

通过preloadDrawables和preloadColorStateLists加载了Framework的drawable资源和状态颜色定义资源。

除了类和资源之外preload方法还加载共享库preloadSharedLibraries,文本资源preloadTextResources,WebViewFactory初始化工作等。

3.) 创建Zygote的LocalServerSocket,用于接收启动应用程序的消息。


...

Zygote.initNativeState(isPrimaryZygote);

ZygoteHooks.stopZygoteNoThreadCreation();

zygoteServer = new ZygoteServer(isPrimaryZygote);

...

在ZygoteServer构造方法中调用Zygote.createManagedSocketFromInitSocket方法创建LocalServerSocket,并将其保存在变量mZygoteSocket中。

以下是ZygoteServer的构造方法


ZygoteServer(boolean isPrimaryZygote) {

    mUsapPoolEventFD = Zygote.getUsapPoolEventFD();

    if (isPrimaryZygote) {

        mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);

        mUsapPoolSocket =

        Zygote.createManagedSocketFromInitSocket(

        Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);

    } else {

        mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);

        mUsapPoolSocket =

        Zygote.createManagedSocketFromInitSocket(

        Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);

    }

    fetchUsapPoolPolicyProps();

    mUsapPoolSupported = true;

}

以下是Zygote.createManagedSocketFromInitSocket方法代码,在这里获取系统中的文件描述符,绑定套接字生成LocalServerSocket对象。用于接收socket信息。


static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {

    int fileDesc;

    final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;

    try {

        String env = System.getenv(fullSocketName);

        fileDesc = Integer.parseInt(env);

    } catch (RuntimeException ex) {

            throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);

    }

    try {

        FileDescriptor fd = new FileDescriptor();

        fd.setInt$(fileDesc);

        return new LocalServerSocket(fd);

    } catch (IOException ex) {

        throw new RuntimeException("Error building socket from file descriptor: " + fileDesc, ex);

    }

}

4.)调用forkSystemServer启动SystemServer进程


...

if (startSystemServer) {

    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;

    }

}

...

forkSystemServer方法调用了Zygote.forkSystemServer方法,而Zygote.forkSystemServer最终调用native方法nativeForkSystemServer来启动SystemServer进程。forkSystemServer方法返回一个Runnable 对象,如果当前是父进程则r为空。如果是子进程,则运行r.run();

4.调用runSelectLoop方法,进入监听和接收消息的循环。


....

    Log.i(TAG, "Accepting command socket connections");

    // The select loop returns early in the child process after a fork and

        // loops forever in the zygote.

    caller = zygoteServer.runSelectLoop(abiList);

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

}

}

ZygoteInit类main函数的的最后,调用zygoteServer.runSelectLoop(abiList) 方法,zygote进入监听和处理启动应用程序的请求循环。如果当前是zygote进程,则循环永不退出,zygoteServer.runSelectLoop(abiList) 永不返回,一直处于无限循环中,如果是zygote fork出的子进程,zygoteServer.runSelectLoop(abiList) 返回后caller 不为空,最后执行caller的run方法。

至此,Zygote进程启动完成,接下来等待启动应用程序的请求,fork出应用程序进程并启动。

三. Zygote 启动应用程序

zygote 如何启动应用程序的?

1.)发送启动信息给zygote

Android 启动一个新进程是通过ActivityManagerService中调用startProcessLocket方法完成的。startProcessLocket准备好参数后,最终调用Process类的start方法。start方法调用ZygoteProcess类的startViaZygote方法。如下代码:


startResult = Process.start(entryPoint,

                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,

                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,

                        app.info.dataDir, invokeWith, app.info.packageName,

                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
                        

private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,

                                        @Nullable final String niceName,

                                        final int uid, final int gid,

                                        @Nullable final int[] gids,

                                        int runtimeFlags, int mountExternal,

                                        int targetSdkVersion,

                                        @Nullable String seInfo,

                                        @NonNull String abi,

                                        @Nullable String instructionSet,

                                        @Nullable String appDataDir,

                                        @Nullable String invokeWith,

                                        boolean startChildZygote,

                                        @Nullable String packageName,

                                        boolean useUsapPool,

                                        @Nullable String[] extraArgs)

                                            throws ZygoteStartFailedEx {

    ArrayList<String> argsForZygote = new ArrayList<>();

    // --runtime-args, --setuid=, --setgid=,

    // and --setgroups= must go first

    argsForZygote.add("--runtime-args");

    argsForZygote.add("--setuid=" + uid);

    argsForZygote.add("--setgid=" + gid);

    argsForZygote.add("--runtime-flags=" + runtimeFlags);

    if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {

        argsForZygote.add("--mount-external-default");

    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {

        argsForZygote.add("--mount-external-read");

    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {

        argsForZygote.add("--mount-external-write");

    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {

        argsForZygote.add("--mount-external-full");

    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {

        argsForZygote.add("--mount-external-installer");

    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {

        argsForZygote.add("--mount-external-legacy");

    }

    argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

    // --setgroups is a comma-separated list

    if (gids != null && gids.length > 0) {

        StringBuilder sb = new StringBuilder();

        sb.append("--setgroups=");

        int sz = gids.length;

        for (int i = 0; i < sz; i++) {

            if (i != 0) {

                sb.append(',');

            }

            sb.append(gids[i]);

        }

        argsForZygote.add(sb.toString());

    }

    if (niceName != null) {

        argsForZygote.add("--nice-name=" + niceName);

    }

    if (seInfo != null) {

        argsForZygote.add("--seinfo=" + seInfo);

    }

    if (instructionSet != null) {

        argsForZygote.add("--instruction-set=" + instructionSet);

    }

    if (appDataDir != null) {

        argsForZygote.add("--app-data-dir=" + appDataDir);

    }

    if (invokeWith != null) {

        argsForZygote.add("--invoke-with");

        argsForZygote.add(invokeWith);

    }

    if (startChildZygote) {

        argsForZygote.add("--start-child-zygote");

    }

    if (packageName != null) {

        argsForZygote.add("--package-name=" + packageName);

    }

    argsForZygote.add(processClass);

    if (extraArgs != null) {

        Collections.addAll(argsForZygote, extraArgs);

    }

    synchronized(mLock) {

        // The USAP pool can not be used if the application will not use the systems graphics

        // driver. If that driver is requested use the Zygote application start path.

        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), useUsapPool, argsForZygote);

    }

}

zygoteSendArgsAndGetResult第一个参数调用openZygoteSocketIfNeeded方法,并返回ZygoteState对象,openZygoteSocketIfNeeded方法最终通过ZygoteState.connect创建链接用于通信的LocalSocket,并保存于primaryZygoteState类中,这个primaryZygoteState会被openZygoteSocketIfNeeded方法返回给zygoteSendArgsAndGetResult作为一个参数。


private void attemptConnectionToPrimaryZygote() throws IOException {

    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {

        primaryZygoteState = ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);

        maybeSetApiBlacklistExemptions(primaryZygoteState, false);

        maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);

        maybeSetHiddenApiAccessStatslogSampleRate(primaryZygoteState);

    }

}

//创建socket代码

static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress, @Nullable LocalSocketAddress usapSocketAddress) throws IOException {

    DataInputStream zygoteInputStream;

    BufferedWriter zygoteOutputWriter;

    final LocalSocket zygoteSessionSocket = new LocalSocket();

    if (zygoteSocketAddress == null) {

        throw new IllegalArgumentException("zygoteSocketAddress can't be null");

    }

    try {

        zygoteSessionSocket.connect(zygoteSocketAddress);

        zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());

        zygoteOutputWriter = new BufferedWriter(new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),

        Zygote.SOCKET_BUFFER_SIZE);

    } catch (IOException ex) {

        try {

            zygoteSessionSocket.close();

        } catch (IOException ignore) { }

            throw ex;

        }

        return new ZygoteState(zygoteSocketAddress, usapSocketAddress, zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter, getAbiList(zygoteOutputWriter, zygoteInputStream));

    }
    

// 创建socket 地址代码

public ZygoteProcess() {

    mZygoteSocketAddress =

    new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);

    ...

}

zygoteSendArgsAndGetResult方法内部会调用attemptZygoteSendArgsAndGetResult,在这个方法中将参数写入到前面创建的LocalSocket中。这时就将信息发送给了zygote。


private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {

    try {

        final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;

        final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;

        zygoteWriter.write(msgStr);

        zygoteWriter.flush();

        // Always read the entire result from the input stream to avoid leaving

        // bytes in the stream for future process starts to accidentally stumble

        // upon.

        Process.ProcessStartResult result = new Process.ProcessStartResult();

        result.pid = zygoteInputStream.readInt();

        result.usingWrapper = zygoteInputStream.readBoolean();

        if (result.pid < 0) {

            throw new ZygoteStartFailedEx("fork() failed");

        }

        return result;

    } catch (IOException ex) {

        zygoteState.close();

        Log.e(LOG_TAG, "IO Exception while communicating with Zygote - " + ex.toString());

        throw new ZygoteStartFailedEx(ex);

    }

}

2.)zygote进程处理启动请求

首先在zygoteServer.runSelectLoop方法中监听Socket请求,在acceptCommandPeer方法中等待socket链接,并生成ZygoteConnection


/**

* Runs the zygote process's select loop. Accepts new connections as

* they happen, and reads commands from connections one spawn-request's

* worth at a time.

*/

Runnable runSelectLoop(String abiList) {

ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();

ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

socketFDs.add(mZygoteSocket.getFileDescriptor());

peers.add(null);

while (true) {

    fetchUsapPoolPolicyPropsWithMinInterval();

    int[] usapPipeFDs = null;

    StructPollfd[] pollFDs = null;

    ...

    /*

    * 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 blacklist

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

    ...

    boolean usapPoolFDRead = false;

    while (--pollIndex >= 0) {

        if ((pollFDs[pollIndex].revents & POLLIN) == 0) {

            continue;

        }

        if (pollIndex == 0) {

            // Zygote server socket

            ZygoteConnection newPeer = acceptCommandPeer(abiList);

            peers.add(newPeer);

            socketFDs.add(newPeer.getFileDescriptor());

        } else if (pollIndex < usapPoolEventFDIndex) {

            // Session socket accepted from the Zygote server socket

            try {

                ZygoteConnection connection = peers.get(pollIndex);

                final 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.

    ... }

    }

    ...

}

}

调用mZygoteSocket.accept()直到有socket 链接请求进入,然后唤醒进程创建ZygoteConnection类,这个类保存了读写socket的流。

调用acceptCommandPeer来和客户端建立一个socket链接。然后把这个socket加入监听数组中,等待这个socket上的命令的到来。


/**

* Waits for and accepts a single command connection. Throws

* RuntimeException on failure.

*/

private ZygoteConnection acceptCommandPeer(String abiList) {

    try {

        return createNewConnection(mZygoteSocket.accept(), abiList);

    } catch (IOException ex) {

        throw new RuntimeException("IOException during accept()", ex);

    }

}

protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList) throws IOException {

    return new ZygoteConnection(socket, abiList);

}

当socket接收到数据后会执行ZygoteConnection类的connection.processOneCommand(this);方法


Runnable processOneCommand(ZygoteServer zygoteServer) {

    String args[];

    ZygoteArguments parsedArgs = null;

    FileDescriptor[] descriptors;

    try {

        args = Zygote.readArgumentList(mSocketReader);

        // TODO (chriswailes): Remove this and add an assert.

        descriptors = mSocket.getAncillaryFileDescriptors();

    } catch (IOException ex) {

        throw new IllegalStateException("IOException on command socket", ex);

    }

    // readArgumentList returns null only when it has reached EOF with no available

    // data to read. This will only happen when the remote socket has disconnected.

    if (args == null) {

        isEof = true;

        return null;

    }

    int pid = -1;

    FileDescriptor childPipeFd = null;

    FileDescriptor serverPipeFd = null;

    parsedArgs = new ZygoteArguments(args);

    ...

    Zygote.applyUidSecurityPolicy(parsedArgs, peer);

    Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);

    Zygote.applyDebuggerSystemProperty(parsedArgs);

    Zygote.applyInvokeWithSystemProperty(parsedArgs);

    ...

    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) {

            // in child

            zygoteServer.setForkChild();

            zygoteServer.closeServerSocket();

            IoUtils.closeQuietly(serverPipeFd);

            serverPipeFd = null;

            return handleChildProc(parsedArgs, descriptors, 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, descriptors, serverPipeFd);

            return null;

        }

    } finally {

        IoUtils.closeQuietly(childPipeFd);

        IoUtils.closeQuietly(serverPipeFd);

    }

}

processOneCommand首先调用Zygote.readArgumentList(mSocketReader),读取参数行,并按照格式解析出来保存到args数组中。再参数进行检查。

检查无误后调用Zygote.forkAndSpecialize方法fork子进程。在Zygote.forkAndSpecialize方法中调用native方法nativeForkAndSpecialize来完成fork工作。

fork 出子进程后,调用handleChildProc方法完成子进程的初始化工作。

handleChildProc关闭监听socket和从Zygote中继承的文件描述符,设置进程名称,成功则返回Runnable对象。注意当前是子进程则pid==0 调用handleChildProc,当前是zygote进程则pid 不为0,调用handleParentProc方法。也就是当运行完fork之后,代码会分别运行2个分支,子进程执行pid == 0 分支,zygote进程执行else分支。

handleChildProc最终调用RuntimeInit类的findStaticMain方法。


/**

* Invokes a static "main(argv[]) method on class "className".

* Converts various failing exceptions into RuntimeExceptions, with

* the assumption that they will then cause the VM instance to exit.

*

* @param className Fully-qualified class name

* @param argv Argument vector for main()

* @param classLoader the classLoader to load {@className} with

*/

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

}

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

}

findStaticMain方法首先加载子进程要启动的java类到虚拟机中。然后找到该类的main方法的Method对象m。再将m和解析的参数argv以参数的形式传递给生成的MethodAndArgsCaller类的对象,MethodAndArgsCaller是Runnable子类。

子进程最终从zygoteServer.runSelectLoop方法的无限循环中退出后,执行caller.run()进入子进程运行换行


// loops forever in the zygote.

    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();

}

调用caller.run()其实调用的是子类MethodAndArgsCaller的run方法


public void run() {

try {

    mMethod.invoke(null, new Object[] { mArgs });

} catch (IllegalAccessException ex) {

    throw new RuntimeException(ex);

} catch (InvocationTargetException ex) {

    Throwable cause = ex.getCause();

    if (cause instanceof RuntimeException) {

        throw (RuntimeException) cause;

    } else if (cause instanceof Error) {

        throw (Error) cause;

    }

    throw new RuntimeException(ex);

}

}

在caller.run方法中只是执行了前面传入的main方法的Method对象。这才开始真正调用ActivityThread的main方法。

至此zygote启动应用程序完成,应用进入其本身的启动流程。

总结:

流程图

Zygote 启动应用程序过程.jpg

  1. 监听socket等待处理socket链接请求

  2. 处理socket请求,解析参数

  3. fork子进程,将应用程序的启动类加载到子进程中,并执行main方法

四. 源代码路径

以上代码基于Android10.0源码

app_process:frameworks/base/cmds/app_process/app_main.cpp

AndroidRuntime:frameworks/base/core/jni/AndroidRuntime.cpp

ActivityManagerServic:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

ZygoteProcess:frameworks/base/core/java/android/os/ZygoteProcess.java

ZygoteInit:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

ZygoteConnection: frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java