安卓启动流程梳理之 Zygote 进程启动

安卓启动流程梳理之 Zygote 进程

安卓系统从开机到桌面显示是一个长而复杂的流程,本文参考安卓源码记录安卓启动流程的梳理学习。(文章涉及的源码基于 Android 10.0)由于 Android 启动流程很长,所以分几篇来记录,本篇记录安卓系统进程之父 Zygote 进程的启动过程。

[TOC]

zygote 进程是在 Init 进程启动时创建的,通过 init.zygotexx.rc 脚本启动,zygote 进程可以通过调用 fork() 函数创建应用程序进程和 system server 进程,所以 zygote 进程通常被称为进程孵化器。 zygote 进程在启动的时候会创建 JVM,因此通过 zygote 进程创建的进程可以在进程内部获取一个 JVM 实例副本。

zygote 进程入口

zygote 进程通过 init.zygotexx.rc 脚本启动,这些脚本存放在 system/core/rootdir 目录下。

1 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
...
17 service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
...

上面代码是 init.zygote63_32.rc 文件中截取的,从中可以看出,这里通过 service 语句启动了两个 zygote 进程,一个是名为 zygote,执行程序为 app_process64 的主模式 zygote 进程,另一个是名为 zygote_secondary,执行程序为 app_precess32 的辅模式 zygote 进程。app_prcessxx 会执行到 /framework/base/cmds/app_process/app_main.cpp 文件中的 main() 方法中。

while (i < argc) {
    const char* arg = argv[i++];
    if (strcmp(arg, "--zygote") == 0) { // 1
        zygote = true;
        niceName = ZYGOTE_NICE_NAME;
    } else if (strcmp(arg, "--start-system-server") == 0) { // 2
        startSystemServer = true;
    } else if (strcmp(arg, "--application") == 0) {
        application = true;
    }
    ...
    if (startSystemServer) {
        args.add(String8("start-system-server"));
    }
    ...
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote); // 3
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    }
}

从 main 方法中可以看出,通过入参 '--zygote' 指定了启动 zygote 进程, 通过 '--start-system-server' 指定了在 zygote 进程中启动 system server 进程。最后是执行到 AppRuntime.start() 方法中,而 AppRuntime 继承自 AndroidRuntime,所以接下来执行 AndroidRuntime.start() 方法。

AndroidRuntime.start()

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
    JniInvocation jni_invocation; 
    jni_invocation.Init(NULL); // 1
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) { // 2
        return;
    }
    onVmCreated(env);
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    ...
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
    } 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); // 3
        }
    }
    free(slashClassName);
}

start() 方法中主要执行了:

  1. 初始化并注册 JNI接口方法
  2. 启动 JVM 虚拟机
  3. 由入参 'com.android.internal.os.ZygoteInit' 找到 ZygoteInit 类,并通过 JNI 调用 ZygoteInit.main() 方法。

ZygoteInit.main()

public static void main(String argv[]) {
    Runnable caller;
    try {
        boolean startSystemServer = false;
        String zygoteSocketName = "zygote";
        boolean enableLazyPreload = false;
        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(SOCKET_NAME_ARG)) {
                zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } 
        }
        if (!enableLazyPreload) {
            preload(bootTimingsTraceLog); // 1
        } else {
            Zygote.resetNicePriority();
        }
        ...
        final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
        zygoteServer = new ZygoteServer(isPrimaryZygote); // 2
        if (startSystemServer) {
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // 3
            if (r != null) {
                r.run();
                return;
            }
        }
        caller = zygoteServer.runSelectLoop(abiList);
    }
    ...
}

ZygoteInit.main 方法中主要执行了:

  1. preload() 预加载虚拟机运行时所需的各类资源,包括常用的 classes、资源库、sharedLibraries 等。这个过程支持通过 ‘--enable-lazy-preload’ 参数控制延后加载。
  2. 创建 zygote 进程通信服务端 Socket mZygoteSocket,用于监听所有请求和 zygote 进程通信的消息。
  3. 通过 forkSystemServer() 启动 system server 进程。

最后调用到 ZygoteServer 中的 runSelectLoop 方法中,一直循环等待其他进程的创建请求。

ZygoteServer.runSelectLoop()

Runnable runSelectLoop(String abiList) {
    ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    socketFDs.add(mZygoteSocket.getFileDescriptor());  // 1
    peers.add(null);
    while (true) {
        boolean usapPoolFDRead = false;
        while (--pollIndex >= 0) {
            if (pollIndex == 0) { // 2
                // Zygote server socket
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                socketFDs.add(newPeer.getFileDescriptor());

            } else if (pollIndex < usapPoolEventFDIndex) { // 3
                // Session socket accepted from the Zygote server socket
                try {
                    ZygoteConnection connection = peers.get(pollIndex);
                    final Runnable command = connection.processOneCommand(this);
                    if (mIsForkChild) {
                        return command;
                    } else {
                        if (connection.isClosedByPeer()) {
                            connection.closeSocket();
                            peers.remove(pollIndex);
                            socketFDs.remove(pollIndex);
                        }
                    }
                }
            } else { // 4
                // Either the USAP pool event FD or a USAP reporting pipe.
                long messagePayload = -1;
                try {
                    byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
                    int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
                    if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
                        DataInputStream inputStream =
                            new DataInputStream(new ByteArrayInputStream(buffer));
                        messagePayload = inputStream.readLong();
                    }
                }
                if (pollIndex > usapPoolEventFDIndex) {
                    Zygote.removeUsapTableEntry((int) messagePayload);
                }
                usapPoolFDRead = true;
            }
        }

        // Check to see if the USAP pool needs to be refilled.
        if (usapPoolFDRead) {
            int[] sessionSocketRawFDs =
                socketFDs.subList(1, socketFDs.size())
                .stream()
                .mapToInt(fd -> fd.getInt$())
                .toArray();
            final Runnable command = fillUsapPool(sessionSocketRawFDs); // 5
            if (command != null) {
                return command;
            }
        }
    }
}

runSelectLoop() 是一个无限循环,也就是 zygote 进程起来之后会一直在后台等待 socket 消息。在注释 1 处 ZygoteServer 新建了两个 list, 用于保存所有 ZygoteConnection 和对应 ZygoteSocket 的句柄标识。对应 zygote 进程启动时创建的 mZygoteSocket 连接存放在 index 为 0 的位置,仅用于监听新建连接的消息。

循环里主要是在处理三类 socket 消息:

  1. 注释2处,这类消息是已有进程 (例如 system server) 发送给 mZygoteSocket ,请求建立新的连接,收到之后 zygote 进程会创建 SocketConnection 并更新 list。
  2. 注释3处,这类消息是第一步新建的 SocketConnection 中发来的消息,收到之后 zygote 进程通过 processOneCommand 处理,这里就是通常应用程序进程创建的入口。(注释2和注释3这个地方比较绕,思考了很久,两眼冒 +_+)
  3. USAP 类消息处理。USAP 是谷歌在安卓10.0上引进的一种新的进程 fork() 机制,借鉴了线程池的思想,通过 prefork() 提前创建一批进程,当有进程启动时直接从已创建好的进程中分配,加快应用启动速度。在注释4处通过调用 fillUsapPool() 处理这类消息。

总结

Zygote 启动流程

zygote 进程启动流程主要包括以下步骤:

  1. 解析 init.zygotexx.rc 脚本,创建 AndroidRuntime 实例,并调用其 start() 方法。
  2. 初始化 JNI 接口、启动 JVM,并通过 JNI 调用 ZygoteInit.java 中 main() 方法,进入到 Java Framework 层。
  3. 加载 JVM 运行时资源,并创建 ZygoteServer 和服务端 Socket 对象。
  4. 创建 system server 进程,最后进入 ZygoteServer.runSelectLoop() 无限循环,等待接收处理 Socket 消息。
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容