Android5 Zygote 与 SystemServer 启动流程分析

Android5 Zygote 与 SystemServer 启动流程分析

  • Android5 Zygote 与 SystemServer 启动流程分析

    • 前言
    • zygote 进程
      • 解析 zygoterc
      • 启动 SystemServer
      • 执行 ZygoteInitrunSelectLoop
    • SystemServer 启动过程
    • Zygote 的 fork 本地方法分析
      • forkSystemServer

        • ZygoteHookspreFork
        • 创建 system_server 进程
        • ZygoteHookspostForkCommon
      • forkAndSpecialize

前言

Android5.0.1 的启动流程与之前的版本相比变化并不大,OK,变化虽然还是有:SystemServer 启动过程的 init1(), init2()没有了,但主干流程依然不变:Linux 内核加载完毕之后,首先启动 init 进程,然后解析 init.rc,并根据其内容由 init 进程装载 Android 文件系统、创建系统目录、初始化属性系统、启动一些守护进程,其中最重要的守护进程就是 Zygote 进程。Zygote 进程初始化时会创建 Dalvik 虚拟机、预装载系统的资源和 Java 类。所有从 Zygote 进程 fork 出来的用户进程都将继承和共享这些预加载的资源。init 进程是 Android 的第一个进程,而 Zygote 进程则是所有用户进程的根进程。SystemServer 是 Zygote 进程 fork 出的第一个进程,也是整个 Android 系统的核心进程。

zygote 进程

解析 zygote.rc

在文件中 /system/core/rootdir/init.rc 中包含了 zygote.rc:

import /init.${ro.zygote}.rc

${ro.zygote}是平台相关的参数,实际可对应到 init.zygote32.rc, init.zygote64.rc, init.zygote64_32.rc, init.zygote32_64.rc,前两个只会启动单一app_process(64) 进程,而后两个则会启动两个app_process进程:第二个app_process进程称为 secondary,在后面的代码中可以看到相应 secondary socket 的创建过程。为简化起见,在这里就不考虑这种创建两个app_process进程的情形。

以 /system/core/rootdir/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

第一行创建了名为 zygote 的进程,这个进程是通过 app_process 的 main 启动并以”-Xzygote /system/bin –zygote –start-system-server”作为main的入口参数。

app_process 对应代码为 framework/base/cmds/app_process/app_main.cpp。在这个文件的main函数中:

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

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args);
    }

根据入口参数,我们知道 zygote 为true,args参数中包含了”start-system-server”。

AppRuntime 继承自 AndroidRuntime,因此下一步就执行到 AndroidRuntime 的 start 函数。

void AndroidRuntime::start(const char* className, const Vector<String8>& options)
{
    /* start the virtual machine */ // 创建虚拟机
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env) != 0) {
        return;
    }
    onVmCreated(env);

    ...
    //调用className对应类的静态main()函数
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
    env->CallStaticVoidMethod(startClass, startMeth, strArray);
    ...
}

start函数主要做两件事:创建虚拟机和调用传入类名对应类的 main 函数。因此下一步就执行到 com.android.internal.os.ZygoteInit 的 main 函数。

    public static void main(String argv[]) {
        try {
            boolean startSystemServer = false;
            String socketName = "zygote";
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                }
                ...
            }

            registerZygoteSocket(socketName);
            ...
            preload();
            ...

            if (startSystemServer) {
                startSystemServer(abiList, socketName);
            }

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

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

它主要做了三件事情:

1. 调用 registerZygoteSocket 函数创建了一个 socket 接口,用来和 ActivityManagerService 通讯;

2. 调用 startSystemServer 函数来启动 SystemServer;

3. 调用 runSelectLoop 函数进入一个无限循环在前面创建的 socket 接口上等待 ActivityManagerService 请求创建新的应用程序进程。

这里要留意 catch (MethodAndArgsCaller caller) 这一行,android 在这里通过抛出一个异常来处理正常的业务逻辑。

    socket zygote stream 660 root system

系统启动脚本文件 init.rc 是由 init 进程来解释执行的,而 init 进程的源代码位于 system/core/init 目录中,在 init.c 文件中,是由 service_start 函数来解释 init.zygote32.rc 文件中的 service 命令的:

    void service_start(struct service *svc, const char *dynamic_args)
    {
        ...
        pid = fork();

        if (pid == 0) {
            struct socketinfo *si;
            ...

            for (si = svc->sockets; si; si = si->next) {
                int socket_type = (
                        !strcmp(si->type, "stream") ? SOCK_STREAM :
                            (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
                int s = create_socket(si->name, socket_type,
                                      si->perm, si->uid, si->gid, si->socketcon ?: scon);
                if (s >= 0) {
                    publish_socket(si->name, s);
                }
            }
            ...
        }
        ...
    }

每一个 service 命令都会促使 init 进程调用 fork 函数来创建一个新的进程,在新的进程里面,会分析里面的 socket 选项,对于每一个 socket 选项,都会通过 create_socket 函数来在 /dev/socket 目录下创建一个文件,在 zygote 进程中 socket 选项为“socket zygote stream 660 root system”,因此这个文件便是 zygote了,然后得到的文件描述符通过 publish_socket 函数写入到环境变量中去:

    static void publish_socket(const char *name, int fd)
    {
        char key[64] = ANDROID_SOCKET_ENV_PREFIX;
        char val[64];

        strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
                name,
                sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
        snprintf(val, sizeof(val), "%d", fd);
        add_environment(key, val);

        /* make sure we don‘t close-on-exec */
        fcntl(fd, F_SETFD, 0);
    }

这里传进来的参数name值为”zygote”,而 ANDROID_SOCKET_ENV_PREFIX 在 system/core/include/cutils/sockets.h 定义为:

#define ANDROID_SOCKET_ENV_PREFIX   "ANDROID_SOCKET_"
#define ANDROID_SOCKET_DIR          "/dev/socket"

因此,这里就把上面得到的文件描述符写入到以 “ANDROID_SOCKET_zygote” 为 key 值的环境变量中。又因为上面的 ZygoteInit.registerZygoteSocket 函数与这里创建 socket 文件的 create_socket 函数是运行在同一个进程中,因此,上面的 ZygoteInit.registerZygoteSocket 函数可以直接使用这个文件描述符来创建一个 Java层的LocalServerSocket 对象。如果其它进程也需要打开这个 /dev/socket/zygote 文件来和 zygote 进程进行通信,那就必须要通过文件名来连接这个 LocalServerSocket了。也就是说创建 zygote socket 之后,ActivityManagerService 就能够通过该 socket 与 zygote 进程通信从而 fork 创建新进程,android 中的所有应用进程都是通过这种方式 fork zygote 进程创建的。在 ActivityManagerService中 的 startProcessLocked 中调用了Process.start()方法,进而调用 Process.startViaZygote 和 Process.openZygoteSocketIfNeeded。

启动 SystemServer

socket 创建完成之后,紧接着就通过 startSystemServer 函数来启动 SystemServer 进程。

    private static boolean startSystemServer(String abiList, String socketName)
    {
        long capabilities = posixCapabilitiesAsBits(
            OsConstants.CAP_BLOCK_SUSPEND,
            OsConstants.CAP_KILL,
            OsConstants.CAP_NET_ADMIN,
            OsConstants.CAP_NET_BIND_SERVICE,
            OsConstants.CAP_NET_BROADCAST,
            OsConstants.CAP_NET_RAW,
            OsConstants.CAP_SYS_MODULE,
            OsConstants.CAP_SYS_NICE,
            OsConstants.CAP_SYS_RESOURCE,
            OsConstants.CAP_SYS_TIME,
            OsConstants.CAP_SYS_TTY_CONFIG
        );
        /* 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,1032,3001,3002,3003,3006,3007",
            "--capabilities=" + capabilities + "," + capabilities,
            "--runtime-init",
            "--nice-name=system_server",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ...

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

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

            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

这里我们可以从参数推测出:创建名为“system_server”的进程,其入口是: com.android.server.SystemServer 的 main 函数。zygote 进程通过 Zygote.forkSystemServer 函数来创建一个新的进程来启动 SystemServer 组件,返回值 pid 等 0 的地方就是新的进程要执行的路径,即新创建的进程会执行 handleSystemServerProcess 函数。hasSecondZygote 是针对 init.zygote64_32.rc, init.zygote32_64.rc 这两者情况的,在这里跳过不谈。接下来来看 handleSystemServerProcess:

    /**
     * Finish remaining work for the newly forked system server process.
     */
    private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller
    {
        closeServerSocket();

        // set umask to 0077 so new files and directories will default to owner-only permissions.
        Os.umask(S_IRWXG | S_IRWXO);

        if (parsedArgs.niceName != null) {
            Process.setArgV0(parsedArgs.niceName);
        }

        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");

        ClassLoader cl = null;
        if (systemServerClasspath != null) {
            cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
            Thread.currentThread().setContextClassLoader(cl);
        }

        /*
         * Pass the remaining arguments to SystemServer.
         */
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);

        /* should never reach here */
    }

handleSystemServerProcess 会抛出 MethodAndArgsCaller 异常,前面提到这个异常其实是处理正常业务逻辑的,相当于一个回调。由于由 zygote 进程创建的子进程会继承 zygote 进程在前面创建的 socket 文件描述符,而这里的子进程又不会用到它,因此,这里就调用 closeServerSocket 函数来关闭它。SYSTEMSERVERCLASSPATH 是包含 /system/framework/framework.jar 的环境变量,它定义在 system/core/rootdir/init.environ.rc.in 中:

    on init
        export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
        export ANDROID_BOOTLOGO 1
        export ANDROID_ROOT /system
        export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
        export LD_PRELOAD libsigchain.so

handleSystemServerProcess 函数接着调用 RuntimeInit.zygoteInit 函数来进一步执行启动 SystemServer 组件的操作。

    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {

        commonInit();
        nativeZygoteInit();

        applicationInit(targetSdkVersion, argv, classLoader);
    }

commonInit 设置线程未处理异常handler,时区等,JNI 方法 nativeZygoteInit 实现在 frameworks/base/core/jni/AndroidRuntime.cpp 中:

static AndroidRuntime* gCurRuntime = NULL;

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}

AndroidRuntime 是个带虚函数的基类,真正的实现是在 app_main.cpp 中的 AppRuntime:

class AppRuntime : public AndroidRuntime
{
    virtual void onStarted()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();

        AndroidRuntime* ar = AndroidRuntime::getRuntime();
        ar->callMain(mClassName, mClass, mArgs);

        IPCThreadState::self()->stopProcess();
    }

    virtual void onZygoteInit()
    {
        // Re-enable tracing now that we‘re no longer in Zygote.
        atrace_set_tracing_enabled(true);

        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
    }

    virtual void onExit(int code)
    {
        if (mClassName.isEmpty()) {
            // if zygote
            IPCThreadState::self()->stopProcess();
        }

        AndroidRuntime::onExit(code);
    }
};

通过执行 AppRuntime::onZygoteInit 函数,这个进程的 Binder 进程间通信机制基础设施就准备好了,参考代码 frameworks/native/libs/binder/ProcessState.cpp。

接下来,看 applicationInit :

    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {

        final Arguments args;
        try {
            args = new Arguments(argv);
        } catch (IllegalArgumentException ex) {
            Slog.e(TAG, ex.getMessage());
            // let the process exit
            return;
        }

        // Remaining arguments are passed to the start class‘s static main
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

applicationInit 仅仅是转调 invokeStaticMain:

    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller
    {
        Class cl;
        cl = Class.forName(className, true, classLoader);
        Method m;
        m = cl.getMethod("main", new Class[] { String[].class });

        /*
         * 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.
         */
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }

invokeStaticMain 也很简单,通过反射找到参数 className 对应的类的静态 main 方法,然后将该方法与参数生成 ZygoteInit.MethodAndArgsCaller 对象当做异常抛出,这个异常对象在 ZygoteInit 的 main 函数被捕获并执行该对象的 run 方法。

    /**
     * Helper exception class which holds a method and arguments and
     * can call them. This is used as part of a trampoline to get rid of
     * the initial process setup stack frames.
     */
    public static class MethodAndArgsCaller extends Exception
            implements Runnable {

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

这么复杂的跳转,其实就做了一件简单的事情:根据 className 反射调用该类的静态 main 方法。这个类名是 ZygoteInit.startSystemServer 方法中写死的 com.android.server.SystemServer。 从而进入 SystemServer 类的 main()方法。

执行 ZygoteInit.runSelectLoop

在 startSystemServer 函数中,创建 system_server 进程之后,pid 等于 0 时在该新进程中执行 SystemServer.main,否则回到 zygote 进程进行执行 ZygoteInit.runSelectLoop:

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        FileDescriptor[] fdArray = new FileDescriptor[4];

        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);

        int loopCount = GC_LOOP_COUNT;
        while (true) {
            int index;

            /*
             * Call gc() before we block in select().
             * It‘s work that has to be done anyway, and it‘s better
             * to avoid making every child do it.  It will also
             * madvise() any free memory as a side-effect.
             *
             * Don‘t call it every time, because walking the entire
             * heap is a lot of overhead to free a few hundred bytes.
             */
            if (loopCount <= 0) {
                gc();
                loopCount = GC_LOOP_COUNT;
            } else {
                loopCount--;
            }

            try {
                fdArray = fds.toArray(fdArray);
                index = selectReadable(fdArray);
            } catch (IOException ex) {
                throw new RuntimeException("Error in select()", ex);
            }

            if (index < 0) {
                throw new RuntimeException("Error in select()");
            } else if (index == 0) {
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDescriptor());
            } else {
                boolean done;
                done = peers.get(index).runOnce();

                if (done) {
                    peers.remove(index);
                    fds.remove(index);
                }
            }
        }
    }

runSelectLoop函数的逻辑比较简单,主要有两点:

1、 处理客户端的连接和请求。前面创建的 LocalServerSocket 对象保存 sServerSocket,这个 socket 通过 selectReadable 等待 ActivityManagerService(简写 AMS) 与之通信。selectReadable 是一个native函数,内部调用select等待 AMS 连接,AMS 连接上之后就会返回: 返回值 < 0:内部发生错误;返回值 = 0:第一次连接到服务端 ;返回值 > 0:与服务端已经建立连接,并开始发送数据。每一个链接在 zygote 进程中使用 ZygoteConnection 对象表示。

2、 客户端的请求由 ZygoteConnection.runOnce 来处理,这个方法也抛出 MethodAndArgsCaller 异常,从而进入 MethodAndArgsCaller.run 中调用根据客户请求数据反射出的类的 main 方法。

    private String[] readArgumentList()
    {
        int argc;

        try {
            String s = mSocketReader.readLine();

            if (s == null) {
                // EOF reached.
                return null;
            }
            argc = Integer.parseInt(s);
        } catch (NumberFormatException ex) {
            Log.e(TAG, "invalid Zygote wire format: non-int at argc");
            throw new IOException("invalid wire format");
        }

        String[] result = new String[argc];
        for (int i = 0; i < argc; i++) {
            result[i] = mSocketReader.readLine();
            if (result[i] == null) {
                // We got an unexpected EOF.
                throw new IOException("truncated request");
            }
        }

        return result;
    }

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        String args[];
        Arguments parsedArgs = null;
        args = readArgumentList();
        parsedArgs = new Arguments(args);

        ...
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
        ...
    }

SystemServer 启动过程

在前面启动 SystemServer一节讲到,通过反射调用类 com.android.server.SystemServer main() 函数,从而开始执行 SystemServer 的初始化流程。

SystemServer.main()

    /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }

main 函数创建一个 SystemServer 对象,调用其 run() 方法。

    private void run() {
        // If a device‘s clock is before 1970 (before 0), a lot of
        // APIs crash dealing with negative numbers, notably
        // java.io.File#setLastModified, so instead we fake it and
        // hope that time from cell towers or NTP fixes it shortly.
        if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
            Slog.w(TAG, "System clock is before 1970; setting to 1970.");
            SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
        } // 检测时间设置

        // Here we go!
        Slog.i(TAG, "Entered the Android system server!");
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());

        // In case the runtime switched since last boot (such as when
        // the old runtime was removed in an OTA), set the system
        // property so that it is in sync. We can‘t do this in
        // libnativehelper‘s JniInvocation::Init code where we already
        // had to fallback to a different runtime because it is
        // running as root and we need to be the system user to set
        // the property. http://b/11463182
        SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

        // Enable the sampling profiler.
        if (SamplingProfilerIntegration.isEnabled()) {
            SamplingProfilerIntegration.start();
            mProfilerSnapshotTimer = new Timer();
            mProfilerSnapshotTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    SamplingProfilerIntegration.writeSnapshot("system_server", null);
                }
            }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
        } // 启动性能分析采样

        // Mmmmmm... more memory!
        VMRuntime.getRuntime().clearGrowthLimit();

        // The system server has to run all of the time, so it needs to be
        // as efficient as possible with its memory usage.
        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

        // Some devices rely on runtime fingerprint generation, so make sure
        // we‘ve defined it before booting further.
        Build.ensureFingerprintProperty();

        // Within the system server, it is an error to access Environment paths without
        // explicitly specifying a user.
        Environment.setUserRequired(true);

        // Ensure binder calls into the system always run at foreground priority.
        BinderInternal.disableBackgroundScheduling(true);

        // Prepare the main looper thread (this thread).
        android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
        android.os.Process.setCanSelfBackground(false);
        Looper.prepareMainLooper(); // 准备主线程循环

        // Initialize native services.
        System.loadLibrary("android_servers");
        nativeInit();

        // Check whether we failed to shut down last time we tried.
        // This call may not return.
        performPendingShutdown();

        // Initialize the system context.
        createSystemContext();

        // Create the system service manager.
        mSystemServiceManager = new SystemServiceManager(mSystemContext);
        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

        // Start services.  // 启动服务
        try {
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        }

        // For debug builds, log event loop stalls to dropbox for analysis.
        if (StrictMode.conditionallyEnableDebugLogging()) {
            Slog.i(TAG, "Enabled StrictMode for system server main thread.");
        }

        // Loop forever.
        Looper.loop();  // 启动线程循环,等待消息处理
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

在这个 run 方法中,主要完成三件事情,创建 system context 和 system service manager,启动一些系统服务,进入主线程消息循环。

Zygote 的 fork 本地方法分析

接下来我们仔细分析 Zygote.forkSystemServer 与 Zygote.forkAndSpecialize 两个方法。

forkSystemServer

    private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();

    public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        VM_HOOKS.preFork();
        int pid = nativeForkSystemServer(
                uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
        VM_HOOKS.postForkCommon();
        return pid;
    }

在调用 nativeForkSystemServer 创建 system_server 进程之前与之后,都会调用 ZygoteHooks 进行一些前置与后置处理。

ZygoteHooks.preFork

前置处理 ZygoteHooks.preFork:

    public void preFork() {
        Daemons.stop();
        waitUntilAllThreadsStopped();
        token = nativePreFork();
    }

Daemons.stop(); 停止虚拟机中一些守护线程操作:如引用队列、终接器、GC等

    public static void stop() {
        ReferenceQueueDaemon.INSTANCE.stop();
        FinalizerDaemon.INSTANCE.stop();
        FinalizerWatchdogDaemon.INSTANCE.stop();
        HeapTrimmerDaemon.INSTANCE.stop();
        GCDaemon.INSTANCE.stop();
    }

waitUntilAllThreadsStopped 保证被 fork 的进程是单线程,这样可以确保通过 copyonwrite fork 出来的进程也是单线程,从而节省资源。与前面提到的在新建 system_server 进程中调用 closeServerSocket 关闭 sockect 有异曲同工之妙。

    /**
     * We must not fork until we‘re single-threaded again. Wait until /proc shows we‘re
     * down to just one thread.
     */
    private static void waitUntilAllThreadsStopped() {
        File tasks = new File("/proc/self/task");
        while (tasks.list().length > 1) {
            try {
                // Experimentally, booting and playing about with a stingray, I never saw us
                // go round this loop more than once with a 10ms sleep.
                Thread.sleep(10);
            } catch (InterruptedException ignored) {
            }
        }
    }

本地方法 nativePreFork 实现在 art/runtime/native/dalvik_system_ZygoteHooks.cc 中。

    static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) {
      Runtime* runtime = Runtime::Current();
      CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";

      runtime->PreZygoteFork();

      // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
      Thread* self = Thread::Current();
      return reinterpret_cast<jlong>(self);
    }

ZygoteHooks_nativePreFork 通过调用 Runtime::PreZygoteFork 来完成 gc 堆的一些初始化,这部分代码在 art/runtime/runtime.cc 中:

    heap_ = new gc::Heap(...);
    void Runtime::PreZygoteFork() {
        heap_->PreZygoteFork();
    }

创建 system_server 进程:

nativeForkSystemServer 实现在 framework/base/core/jni/com_android_internal_os_Zygote.cpp 中:

    static jint com_android_internal_os_Zygote_nativeForkSystemServer(
            JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
            jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
            jlong effectiveCapabilities) {
        pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                        debug_flags, rlimits,
                        permittedCapabilities, effectiveCapabilities,
                        MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL,
                        NULL, NULL);
        if (pid > 0) {
            // The zygote process checks whether the child process has died or not.
            ALOGI("System server process %d has been created", pid);
            gSystemServerPid = pid;
            // There is a slight window that the system server process has crashed
            // but it went unnoticed because we haven‘t published its pid yet. So
            // we recheck here just to make sure that all is well.
            int status;
            if (waitpid(pid, &status, WNOHANG) == pid) {
                ALOGE("System server process %d has died. Restarting Zygote!", pid);
                RuntimeAbort(env);
            }
        }
        return pid;
    }

它转调 ForkAndSpecializeCommon 来创建新进程,并确保 system_server 创建成功,若不成功便成仁:重启 zygote,因为没有 system_server 就干不了什么事情。ForkAndSpecializeCommon 实现如下:

    static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
    gZygoteClass = (jclass) env->NewGlobalRef(env->FindClass(kZygoteClassName));
    gCallPostForkChildHooks = env->GetStaticMethodID(gZygoteClass, "callPostForkChildHooks",
                                           "(ILjava/lang/String;)V");

    // Utility routine to fork zygote and specialize the child process.
    static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                     jint debug_flags, jobjectArray javaRlimits,
                     jlong permittedCapabilities, jlong effectiveCapabilities,
                     jint mount_external,
                     jstring java_se_info, jstring java_se_name,
                     bool is_system_server, jintArray fdsToClose,
                     jstring instructionSet, jstring dataDir)
    {
        SetSigChldHandler();

        pid_t pid = fork();

        if (pid == 0) {
            // The child process.
            ...
            rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
            ...
            UnsetSigChldHandler();
            ...
            env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                          is_system_server ? NULL : instructionSet);
        }
        else if (pid > 0) {
            // the parent process
        }

        return pid;
    }

ForkAndSpecializeCommon 首先设置子进程异常处理handler,然后 fork 新进程,在新进程中设置 SELinux,并清除它的子进程异常处理 handler,然后调用 Zygote.callPostForkChildHooks 方法。

    private static void callPostForkChildHooks(int debugFlags, String instructionSet) {
        long startTime = SystemClock.elapsedRealtime();
        VM_HOOKS.postForkChild(debugFlags, instructionSet);
        checkTime(startTime, "Zygote.callPostForkChildHooks");
    }

callPostForkChildHooks 又转调 ZygoteHooks.postForkChild :

    public void postForkChild(int debugFlags, String instructionSet) {
        nativePostForkChild(token, debugFlags, instructionSet);
    }

本地方法 nativePostForkChild 又进到 dalvik_system_ZygoteHooks.cc 中:

    static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags,
                                            jstring instruction_set) {
        Thread* thread = reinterpret_cast<Thread*>(token);
        // Our system thread ID, etc, has changed so reset Thread state.
        thread->InitAfterFork();
        EnableDebugFeatures(debug_flags);

        if (instruction_set != nullptr) {
            ScopedUtfChars isa_string(env, instruction_set);
            InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
            Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
            if (isa != kNone && isa != kRuntimeISA) {
                action = Runtime::NativeBridgeAction::kInitialize;
            }
            Runtime::Current()->DidForkFromZygote(env, action, isa_string.c_str());
        } else {
            Runtime::Current()->DidForkFromZygote(env, Runtime::NativeBridgeAction::kUnload, nullptr);
        }
    }

thread->InitAfterFork(); 实现在 art/runtime/thread.cc 中,设置新进程主线程的线程id: tid。DidForkFromZygote 实现在 Runtime.cc 中:

    void Runtime::DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa) {
        is_zygote_ = false;

        switch (action) {
        case NativeBridgeAction::kUnload:
            UnloadNativeBridge();
            break;

        case NativeBridgeAction::kInitialize:
            InitializeNativeBridge(env, isa);
            break;
        }

        // Create the thread pool.
        heap_->CreateThreadPool();

        StartSignalCatcher();

        // Start the JDWP thread. If the command-line debugger flags specified "suspend=y",
        // this will pause the runtime, so we probably want this to come last.
        Dbg::StartJdwp();
    }

首先根据 action 参数来卸载或转载用于跨平台桥接用的库。然后启动 gc 堆的线程池。StartSignalCatcher 设置信号 处理 handler,其代码在 signal_catcher.cc 中。

ZygoteHooks.postForkCommon

后置处理 ZygoteHooks.postForkCommon:

    public void postForkCommon() {
        Daemons.start();
    }

postForkCommon 转调 Daemons.start,以初始化虚拟机中引用队列、终接器以及 gc 的守护线程。

    public static void start() {
        ReferenceQueueDaemon.INSTANCE.start();
        FinalizerDaemon.INSTANCE.start();
        FinalizerWatchdogDaemon.INSTANCE.start();
        HeapTrimmerDaemon.INSTANCE.start();
        GCDaemon.INSTANCE.start();
    }

forkAndSpecialize

Zygote.forkAndSpecialize 方法

    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
          String instructionSet, String appDataDir) {
        long startTime = SystemClock.elapsedRealtime();
        VM_HOOKS.preFork();
        checkTime(startTime, "Zygote.preFork");
        int pid = nativeForkAndSpecialize(
                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                  instructionSet, appDataDir);
        checkTime(startTime, "Zygote.nativeForkAndSpecialize");
        VM_HOOKS.postForkCommon();
        checkTime(startTime, "Zygote.postForkCommon");
        return pid;
    }

前置处理与后置处理与 forkSystemServer 中一样的,这里就跳过不讲了。本地方法 nativeForkAndSpecialize 实现在 framework/base/core/jni/com_android_internal_os_Zygote.cpp 中:

static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
        JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
        jint debug_flags, jobjectArray rlimits,
        jint mount_external, jstring se_info, jstring se_name,
        jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
    // Grant CAP_WAKE_ALARM to the Bluetooth process.
    jlong capabilities = 0;
    if (uid == AID_BLUETOOTH) {
        capabilities |= (1LL << CAP_WAKE_ALARM);
    }

    return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
            rlimits, capabilities, capabilities, mount_external, se_info,
            se_name, false, fdsToClose, instructionSet, appDataDir);
}

这个函数与 com_android_internal_os_Zygote_nativeForkSystemServer 非常类似,只不过少了一个确保子进程创建成功的步骤。

时间: 2024-10-03 22:15:25

Android5 Zygote 与 SystemServer 启动流程分析的相关文章

Zygote进程的启动流程

Zygote进程时由Android系统的第一个进程init启动起来的.init进程时在内核加载完成之后就启动起来的,它在启动的过程中,会读取根目录下的一个脚本文件init.rc,以便可以将其他需要开机启动的进程也一起启动起来. Zygote进程在脚本文件init.rc中的启动脚本如下: service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server socket zygote s

Android启动流程分析(一)

############################################# 本文为极度寒冰原创,转载请注明出处 ############################################# Android的启动流程绝大部分人都知道,但是大多数人都是这样描述的: Android启动,首先是启动Bootloader,然后挂载kernel,挂载完kernel之后,会启动android的init进程,init进程会去孵化Zygote,Zygote是android的重要支柱之

u-boot启动流程分析(2)_板级(board)部分

转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global data介绍以及背后的思考 5. 前置的板级初始化操作 6. u-boot的relocation 7. 后置的板级初始化操作 1. 前言 书接上文(u-boot启动流程分析(1)_平台相关部分),本文介绍u-boot启动流程中和具体版型(board)有关的部分,也即board_init_f/board_i

Cocos2d-x3.3RC0的Android编译Activity启动流程分析

本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXV4aWt1b18x/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" > watermark/2/text/aHR0cDov

u-boot启动流程分析(1)_平台相关部分

转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—>cpu”框架,介绍u-boot中平台相关部分的启动流程.并通过对启动流程的简单分析,掌握u-boot移植的基本方法. 注1:本文所使用的u-boot版本,是2016/4/23从u-boot官网(git://git.denx.de/u-boot.git)导入的一个快照,具体可参考“https://github

ubuntu upstart启动流程分析

ubuntu自从6.10版本之后就使用了较新的upstart机制来进行系统的初始化. upstart是一种基于事件驱动的服务启动机制,可以使多个系统任务在保持依赖关系的前提下并发启动(据说这样这样启动会比较快,理论上应当如此).使用upstart机制时,我们通过/etc/init下的一系列 *.conf 配置文件来指定各种系统服务的依赖关系(启动时机).系统启动时,upstart主进程/sbin/init会解析这些配置文件,按照指定的依赖关系并发启动各种服务与应用. 主要程序 upstart有三

Android -- Audio Native服务之启动流程分析(一)

Android -- Audio Native服务之启动流程分析(一) Android中的Audio系统是比较庞大.繁杂的一部分内容, 其中会涉及较多的音频编解码.多媒体制式与Android Audio HAL设备管理的知识.随着Android的发展,其所支持的音频设备也变得越来丰富,如扬声器.耳机.听筒等等:这种变化也为Android管理如此丰富的音频设备以及如何正确.合理地切换音频输出提出了更高的要求.面对如此繁杂的管理要求,我们分析Android Audio服务的历程想必也不会轻松.接下来

YARN Container 启动流程分析

YARN Container 启动流程分析 本文档从代码出发,分析了 YARN 中 Container 启动的整个过程,希望给出这个过程的一个整体的概念. 文档分为两个部分:第一部分是全局,从头至尾地把 Container 启动的整个流程串联起来:第二部分是细节,简要分析了 Container 启动流程中涉及到的服务.接口和类. 注意: 基于 hadoop-2.6.0 的代码 只写了与 Container 启动相关的逻辑,并且还大量忽略了很多细节,目的是为了得到一个整体的概念. 为了让分析更具体

STB 参考Linux启动流程分析

STB启动流程 1. uboot启动(Fastboot启动) 硬件资源检测(如CPU,DDR Size,Nand  flash,mem size,flash size) print Version(如HW Version,Boot Version,Loader Version) boot设置模型的选择(autoboot or stop) 2. Starting kernel 各种接口驱动的启动() Creating 10 MTD partitions on “hinand” 网卡驱动,USB驱动