android zygote之启动过程分析

源码基于:Android R

0. 前言

之前一篇博文(Android 的init过程详解)中记录了init启动过程,后来另一篇(Android init.rc详解 )中记录了init.rc的解析过程,android详细的启动过程,就需要将所有的init rc文件解剖之后,从action到service挨个分析。这里记录一下zygote的启动过程。

1. zygote起点

system/core/rootdir/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
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh MaxPerformance

service 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
    socket usap_pool_secondary stream 660 root system
    onrestart restart zygote
    task_profiles ProcessCapacityHigh MaxPerformance

Android 5.0 系统开始,zygote 不再是一个进程,而是两个进程,一个是 32 位 zygote,负责孵化 32 位进程(为了兼容使用了 armeabi 和 armeabi-v7a 等 32 位架构的本地动态库的应用),另一个是 64 位 zygote 进程,负责孵化 64 位应用进程(可加载 arm64-v8a 等 64 位架构本地库)。 

通过上述 init.*.rc 得知,通过 app_process64 和 app_process32 两个程序分别引导启动zygote64 和 zygote,后面的命令行参数会在代码中解析。

平台启动完成后,可以查看到两个 zygote 进程:

root            392      1 13338156 36416 poll_schedule_timeout 0 S zygote64
root            393      1 1291412   6516 poll_schedule_timeout 0 S zygote

 针对app_process64 看到了什么:

  • 注意命令行参数,以及参数的顺序,其中包括需要启动system server 的参数
  • 创建了socket zygote,权限是660 root system;
  • 创建了socket usap_pool_primart,权限660 root system;
  • 当 zygote64 进程重启的时候,会进行一系列操作,包括重启 audioserver、cameraserver、media、netd、wificond等;
  • task_profiles

针对app_process32 看到了什么:

  • 注意命令行参数,以及参数的顺序
  • 创建了socket zygote_secondary,权限660 root system;
  • 创建了usap_pool_secondary,权限660 root system;
  • 当zygote 进程重启时,会重启zygote64

通过 socket 关键字分别指定了四个 socket:

  • zygote
  • zygote_secondary
  • usap_pool_primary
  • usap_pool_secondary

平台启动完成,会在平台的 /dev/socket 目录下看到这四个 zygote 文件。AMS 就是通这些 socket来和 zygote 进程通信请求 fork 一个个应用程序进程。

关键字 onrestart 详细的可以参考 Android init.rc详解

2. zygote 代码入口

/frameworks/base/cmds/app_process/Androd.bp

cc_binary {
    name: "app_process",

    srcs: ["app_main.cpp"],

    multilib: {
        lib32: {
            version_script: ":art_sigchain_version_script32.txt",
            suffix: "32",
        },
        lib64: {
            version_script: ":art_sigchain_version_script64.txt",
            suffix: "64",
        },
    },

详细的bp 规则这里不过多叙述了,感兴趣的同学可以自行查看。这里就是编译出app_process32 和app_process64 的地方,详细的代码目录 frameworks/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对象
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;

    //后面解析-cp或-classpath的参数
    const char* spaced_commands[] = { "-cp", "-classpath" };
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    bool known_command = false;

    //for循环主要解析'-'和'--'参数,注意for循环中的两次break
    //显然,对比init.*.rc这里解析的是/system/bin之前的参数
    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.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    //++i跳过/system/bin 这个参数
    ++i;  // Skip unused "parent dir" argument.

    //while循环解析zygote进程的名称,确定该进程是否会启动system_server进程
    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;
        }
    }

    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 { //进入zygote模式
        //创建/data/dalvik-cache目录,后期的classes.art 都在这里
        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]));
        }
    }

    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }

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

代码比较长,下面逐步剖析。

2.1 runtime 实例创建

AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

这里的第二个参数是通过 computerArgBlockSize() 函数计算出args 的 data length,这里是强制认为args 占用了连续的空间:

static size_t computeArgBlockSize(int argc, char* const argv[]) {
    uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
    uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
    end += strlen(argv[argc - 1]) + 1;
    return (end - start);
}

接下来,来看下AppRuntime 类以及其构造:

class AppRuntime : public AndroidRuntime
{
public:
    AppRuntime(char* argBlockStart, const size_t argBlockLength)
        : AndroidRuntime(argBlockStart, argBlockLength)
        , mClass(NULL)
    {
    }

AppRuntime 继承自AndroidRuntime 类,这里就是ART 在framework 中的管理类,ART 的创建、初始化都是从这里开始。

下面先来看下AndroidRuntime 的构造函数:

frameworks/base/core/jni/AndroidRuntime.cpp

static AndroidRuntime* gCurRuntime = NULL;
...
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
        mExitWithoutCleanup(false),
        mArgBlockStart(argBlockStart),
        mArgBlockLength(argBlockLength)
{
    ...
    assert(gCurRuntime == NULL);        // one per process
    gCurRuntime = this;
}

将argBlockStart 和argBlockLength 存放在AndroidRuntime 中,最主要的是创建了一个进程一个的gCurRuntime 实例。后期如果想要获取这个实例可以通过函数AndroidRuntime::getRuntim() 获取:

AndroidRuntime* AndroidRuntime::getRuntime()
{
    return gCurRuntime;
}

2.2 for 循环解析命令行参数

    for (i = 0; i < argc; i++) {
        if (known_command == true) {
          runtime.addOption(strdup(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]));
        ...
    }

注意for 循环中的两次 break,进而得知,这里主要是将 '-' 和 '--' 跟着参数添加到 gCurRuntime 的option 中。

对于这里的命令就是将/system/bin 之前的参数添加到option 中。

2.3 while 循环解析zygote进程名

    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;
        }
    }
  • 通过指定参数--zygote 指定是启动zygote 进程,并且根据编译参数,确认(根据niceName)启动的是zygote64 还是 zygote;
  • 通过指定参数--start-system-server 确认是否启动system_server 进程;
  • 通过指定参数--application 确认是否是应用进程;
  • 通过指定参数--nice-name= 可以强制指定这个进程名,这里就需要注意与--zygote 是否冲突;
  • 如果参数不是 '--' 开头,则退出while循环

这里注意的是参数 --zygote,如果设定该参数,在cast 中会指定niceName 为ZYGOTE_NICE_NAME

#if defined(__LP64__)
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif

从Android.bp 中获悉,最终会根据编译选项不同,app_main.cpp 会被编译出zygote64 和zygote(32位),这里也是根据编译选项不同,ZYGOTE_NICE_NAME 也是分别对应。

2.4 进入zygote 模式

    if (!className.isEmpty()) {
        ...
    } else {
        // We're in zygote mode.
        maybeCreateDalvikCache();  //创建/data/dalvik-cache

        if (startSystemServer) {
            args.add(String8("start-system-server")); 
        }

        ...
    }
    
    if (!niceName.isEmpty()) { //指定进程名
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }

    if (zygote) { //启动zygote
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    }
    ...

详细看代码注释,主要是四点:

  • 创建/data/dalvik-cache,后期的classes.art 都在这里;
  • 解析命令行其他参数,指定到args,在后面启动 zygote java时传入;
  • 指定进程名,niceName 在第 2.3 节解析出来,进程名为zygote64 还是zygote
  • 启动 zygote java,className 为 com.android.internal.os.ZygoteInit,args是上面解析好的;

2.5 AndroidRuntime.start()

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

    //之前做了些准备工作,这里开始创建虚拟机
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);

    //注册一些JNI方法
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    //JNIenv和JNI方法初始化、注册完成,就可以使用java了
    //因为运行java 的main函数需要传入string数组的参数,下面会进行转换
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

    ...
    
    //java端需要的参数解析完成后,准备启动虚拟机
    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);

    ...
}

代码比较多,大致分为:

  • 初始化 JNI 调用,详细看 JniInvocation;
  • 调用 startVm(),创建 JAVA 虚拟机;
  • 调用 startReg(),注册JNI 方法,java需要调用c/c++接口,都是通过JNI 的方法完成的,这里也就打通了 java到native 的屏障了;
  • 调用 2.4 节传入的com.android.internal.os.ZygoteInit 的 main() 函数;

3. ZygoteInit.main()

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

    public static void main(String argv[]) {
        //step1, 设置限定,期间不允许创建线程,不然会抛出error,一直到stop截止
        ZygoteHooks.startZygoteNoThreadCreation();

        try {
            Os.setpgid(0, 0);  //step2, 设置zygote 的进程组信息
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }
        ...

        Runnable caller;
        try {
            ...
            RuntimeInit.preForkInit(); //step3, enable DDMS

            ...
            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]);
                }
            }

            ...

            //step4, 对于primary zygote,即zygote64进程,进行preload
            if (!enableLazyPreload) {
                ...
                preload(bootTimingsTraceLog);
                ...
            }
            ...

            //step5, fork 前的gc 和finalization 工作
            gcAndFinalize();

            //step6, 初始化zygote 的状态
            Zygote.initNativeState(isPrimaryZygote);

            //step7, 解除最开始的 startZygoteNoThreadCreation 限定
            ZygoteHooks.stopZygoteNoThreadCreation();

            //step8, 创建ZygoteServer 实例
            zygoteServer = new ZygoteServer(isPrimaryZygote);

            //step9, fork system_server进程,注意创建成功时子进程(system_server)会将携带
            //  过来的socket关闭,详细可以查看forkSystemServer()函数
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                //如果system server 成功fork,此时处于子进程,直接运行进入system_server进程
                if (r != null) {
                    r.run();
                    return;
                }
            }

            ...
            //step10, 如果fork system_server成功,主进程会
            //  继续流程,进入Zygote 循环,普通进程的fork 从这里获取
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {//创建的子进程都会将携带的socket关闭
                zygoteServer.closeServerSocket();
            }
        }

        //step11,对于普通进程来说,通过runSelectLoop 成功获得进程后,从这里进入该进程
        if (caller != null) {
            caller.run();
        }
    }

看代码中的注释,代码太长,大致分11步,下面来分别解析。

3.1 startZygoteNoThreadCreation()

libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java

    @libcore.api.CorePlatformApi
    public static native void startZygoteNoThreadCreation();
    
    @libcore.api.CorePlatformApi
    public static native void stopZygoteNoThreadCreation();

这个是native 的接口,来看下JNI 的代码:

art/runtime/native/dalvik_system_ZygoteHooks.cc

static void ZygoteHooks_startZygoteNoThreadCreation(JNIEnv* env ATTRIBUTE_UNUSED,
                                                    jclass klass ATTRIBUTE_UNUSED) {
  Runtime::Current()->SetZygoteNoThreadSection(true);
}

static void ZygoteHooks_stopZygoteNoThreadCreation(JNIEnv* env ATTRIBUTE_UNUSED,
                                                   jclass klass ATTRIBUTE_UNUSED) {
  Runtime::Current()->SetZygoteNoThreadSection(false);
}

其实说白了,就是设置Runtime 中的一个变量:

art/runtime/runtime.h

  void SetZygoteNoThreadSection(bool val) {
    zygote_no_threads_ = val;
  }

  bool IsZygoteNoThreadSection() const {
    return zygote_no_threads_;
  }

start 时候会标记为true,stop 的时候会标记为false,默认值为false。

如果这个时候在zygote 中创建线程会如何:

art/runtime/native/java_lang_Thread.cc

static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size,
                                jboolean daemon) {
  // There are sections in the zygote that forbid thread creation.
  Runtime* runtime = Runtime::Current();
  if (runtime->IsZygote() && runtime->IsZygoteNoThreadSection()) {
    jclass internal_error = env->FindClass("java/lang/InternalError");
    CHECK(internal_error != nullptr);
    env->ThrowNew(internal_error, "Cannot create threads in zygote");
    return;
  }

  Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE);
}

代码很清晰,如果是zygote 进程,如果创建线程会抛 Cannot create threads in zygote 的错误。

3.2 Os.setpgid()

        try {
            Os.setpgid(0, 0);  //step2, 设置zygote 的进程组信息
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

指定当前进程的信息;

3.3 RuntimeInit.preForkInit()

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

    public static void preForkInit() {
        if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
        RuntimeHooks.setThreadPrioritySetter(new RuntimeThreadPrioritySetter());
        RuntimeInit.enableDdms();
        ...
        MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create);
    }

    private static void enableDdms() {
        // Register handlers for DDM messages.
        android.ddm.DdmRegister.registerHandlers();
    }

这里不做过多说明,主要是zygote 启动前的准备工作,包括DDMS,enableDdms 可以查看:frameworks/base/core/java/android/ddm/DdmRegister.java

3.4 preload()

通过代码得知如果zygote 启动时配置了参数 --enable-lazy-preload,则不会进行preload 操作,如第 1 节所示,一般会在 zygote_primary 进程中会preload,而在 zygote_secondary 是不会进行preload:

    static void preload(TimingsTraceLog bootTimingsTraceLog) {
        ...

        preloadClasses();

        cacheNonBootClasspathClassLoaders();

        preloadResources();

        nativePreloadAppProcessHALs();

        maybePreloadGraphicsDriver();

        preloadSharedLibraries();
        preloadTextResources();

        WebViewFactory.prepareWebViewInZygote();

        warmUpJcaProviders();
        sPreloadComplete = true;
    }
  • 通过 preloadClasses() 加载 /system/etc/preloaded-classes 里的所有class,其中以 # 开头或空白行忽略。主要通过 Class.forName() 进行加载;
  • 通过 preloadResources() 创建一个Resources 实例,加载系统资源;
  • 通过 nativePreloadAppProcessHALs() 进行HAL 预加载;
  • 通过 maybePreloadGraphicsDrive() 对driver 进行预加载,详细看 jni_runtime.cpp;
  • 通过 preloadSharedLibraries() 进行动态库的预加载,包括 libandroid.so、libcompiler_rt.so、libjnigraphics.so、libsfplugin_ccodec.so、libperformance_jni.so 等;
  • 通过 preloadTextResources() 加载字体资源;

3.5 gcAndFinalize()

    private static void gcAndFinalize() {
        ZygoteHooks.gcAndFinalize();
    }
libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java

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

在zygote 之前进行一些GC 操作。

3.6 initNativeState()

frameworks/base/core/java/com/android/internal/os/Zygote.java

    static void initNativeState(boolean isPrimary) {
        nativeInitNativeState(isPrimary);
    }

    protected static native void nativeInitNativeState(boolean isPrimary);

接着来看下JNI 中的处理:

frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jclass,
                                                                 jboolean is_primary) { 
  gZygoteSocketFD =
      android_get_control_socket(is_primary ? "zygote" : "zygote_secondary");
  ...

  gUsapPoolSocketFD =
      android_get_control_socket(is_primary ? "usap_pool_primary" : "usap_pool_secondary");
  ...

  initUnsolSocketToSystemServer();

  gIsSecurityEnforced = security_getenforce();

  selinux_android_seapp_context_init();
  ...
  • 创建zygote 和USAP 的socket,保存在各自的FD 中;
  • 确认selinux 状态并check

3.7 stopZygoteNoThreadCreation()

详细代码见上文第 3.1 节,这里主要解除最开始的 startZygoteNoThreadCreation 限定。

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

        mUsapPoolSupported = true;
        fetchUsapPoolPolicyProps();
    }
  • 为 USAP(unspecialized app process) 创建event fd;
  • 创建socket 并 listen;
  • 初始化USAP pool 的一些prop;

3.9 forkSystemServer()

    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        ...

        /* Hardcoded command line to start the system server */
        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);

            ...

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

如果fork 成功,会分别进入子进程和父进程的逻辑,对于父进程是直接返回上一级继续执行后续,对于子进程则进入 handleSystemServerProcess,如下:

        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket(); //将父进程中的socket 关闭,不再需要了
            return handleSystemServerProcess(parsedArgs); //子进程进入内部处理函数
        }

对于子进程来说,从zygote 中携带过来的socket不会使用,直接close掉。后面通过 AMS 申请创建的应用进程都会将携带过来的 socket 都关掉。

另外,函数中具体的handleSystemServerProcess() 这里不再列出,其中主要操作是调用 ZygoteInit.zygoteInit()

    public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        ...
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    }

这里不再过多分析,详细看system server 的启动过程分析。

3.10 zygoteServer.runSelectLoop()

在 3.9 节中会调用 forkSystemServer(),并且子进程会返回一个Runnable,而父进程返回NULL,所以,对于Zygote 进程来说,是返回NULL,继续会执行zygoteServer.runSelectLoop。

这里的代码比较多,对于zygote 来说,会在poll 触发的时候,创建ZygoteConnection:

    if (pollIndex == 0) {
        // Zygote server socket

        ZygoteConnection newPeer = acceptCommandPeer(abiList);
        peers.add(newPeer);
        socketFDs.add(newPeer.getFileDescriptor());
    }

其他详细的可以查看应用启动过程分析。

4. 总结

这样,Zygote进程就启动完成了,学习到这里,我们终于都对Android系统中的进程有了一个深刻的认识了,这里总结一下:

  • 系统启动时init 进程会创建 zygote 进程,这是Android 系统的核心进程,用以孵化Android 中所有的应用程序,包括 system_server;
  • 在 zygote 进程运行过程中分 native 部分和 java 部分:
    • native 部分用以准备 java 所需的一切环境,核心是虚拟机的创建、JNIenv 初始化,以及JNI method 的注册。当 java 所需环境准备完成,最终会启动 zygote 的java 端代码;
    • java 部分主要会预加载一些进程所需的资源(classes 和 resource 等),并创建 ZygoteServer 实例,该实例用以管理 socket 通信,最后根据需要会 fork system_server 进程并运行,然后通过 zygoteserver.runSelectLoop() 函数等待Android 普通应用进程的创建;

5. Q&A

为什么zygote使用socket通信而不使用binder?

答案是没必要

zygote 创建socket 进行消息通信,以此来孵化一个应用进程,而且采用了 LocalSocket 相对于网络Socket,减少了数据验证等环节,所以其实效率相对于正常的网络Socket会大幅的提升。虽然还是要经过两次拷贝,但是由于数据量并不大,所以其实影响并不明显。

而使用 binder,则需要做到:

  • 优先启动 servicemanager,至少要早于 zygote;
  • zygote 创建 BBinder,并将其binder 添加到 servicemanager 中;
  • zygote fork 出 system_server 之后,需要在AMS 中创建 client 端的 binder 对象,便于与 zygote 通信,则需要通过 servicemanager 进行getService();
  • AMS 通过binder 驱动,与 zygote 通信;

zygote 创建的 BBinder 内存会被携带到孵化的每个进程,包括 system_server;

zygote 创建BBinder 就意味着多线程,fork 出来的进程天生就是多线程,需要考虑死锁问题;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

私房菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值