likes
comments
collection
share

Android 系统启动过程(二) —— zygote 进程

作者站长头像
站长
· 阅读数 27

1. zygote 进程概要

zygote 进程启动做了什么:

  1. 创建了 AppRuntime,并调用其 start 方法,启动 Zygote 进程。
  2. 创建 JVM,并为其注册 JNI 方法。
  3. 通过 JNI 调用 ZygoteInit 的 main 函数进入 Zygote 的 Java 框架层。
  4. 启动 SystemServer 进程。
  5. 创建服务器端 Socket,并通过 runSelectLoop 方法等待 AMS 的请求来创建新的应用程序进程。

本文将基于 android-14.0.0_r9 版本代码对以上内容进行详细讲解。

2. Native 层

zygote 进程是由 init 进程启动的,最初运行在 Native 层,后通过 JNI 调用 ZygoteInit 的 main 方法,从 Native 层进入了 Java 层。

2.1 init 进程启动 zygote 进程

zygote 进程是通过 init 进程启动的,那么 init 进程如何启动这个名为 zygote 的 Service?

在 zygote 的启动脚本中,以 init.zygote64.rc 为例:

# system/core/rootdir/init.zygote64.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
    ...

由此可知 Zygote 的进程名为 zygote,执行程序为 app_process ,classname 为 main。

在 init.rc 文件中使用 import 引入 zygote 的启动脚本。查看 init.rc :

...
import /system/etc/init/hw/init.${ro.zygote}.rc
on late-init
    ...
    # Now we can start zygote.
    trigger zygote-start
    ...

...
on zygote-start
    wait_for_prop odsign.verification.done 1
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier
    start statsd
    start netd
    start zygote
    start zygote_secondary

在 late-init 阶段触发了 zygote-start,接着执行 start zygote 命令启动 zygote 进程。

通过 builtins.cpp 中 builtin_functions 可知,start 是一个 Commend,对应的函数为 builtins.cpp 中的 do_start 函数:

// init/builtins.cpp
static Result<void> do_start(const BuiltinArguments& args) {
    Service* svc = ServiceList::GetInstance().FindService(args[1]);
    if (!svc) return Error() << "service " << args[1] << " not found";
    errno = 0;
    if (auto result = svc->Start(); !result.ok()) {
        return ErrorIgnoreEnoent() << "Could not start service: " << result.error();
    }
    return {};
}

通过 do_start 函数找到 zygote 对应的 Service,并调用其 Start 函数启动该 Service:

// system/core/init/service.cpp
Result<void> Service::Start() {
    ...
    // Service 正在运行,不启动
    if (flags_ & SVC_RUNNING) {
        if ((flags_ & SVC_ONESHOT) && disabled) {
            flags_ |= SVC_RESTART;
        }
        LOG(INFO) << "service '" << name_
                  << "' requested start, but it is already running (flags: " << flags_ << ")";
        // It is not an error to try to start a service that is already running.
        reboot_on_failure.Disable();
        return {};
    }
    ...
    pid_t pid = -1;
    // 创建子进程
    if (namespaces_.flags) {
        pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }
    
    // 当前代码逻辑在子线程中运行
    if (pid == 0) {
        umask(077);
        cgroups_activated.CloseWriteFd();
        setsid_finished.CloseReadFd();
        // 启动 Service 子进程
        RunService(descriptors, std::move(cgroups_activated), std::move(setsid_finished));
        _exit(127);
    } else {
        cgroups_activated.CloseReadFd();
        setsid_finished.CloseWriteFd();
    }
   ...
}

在 Start 函数中,init 进程创建 zygote 子进程,在 zygote 子进程中通过 RunService 进入到 zygote 的 main 函数中:

void Service::RunService(const std::vector<Descriptor>& descriptors,
                         InterprocessFifo cgroups_activated, InterprocessFifo setsid_finished) {
    ...
    if (!ExpandArgsAndExecv(args_, sigstop_)) {
        PLOG(ERROR) << "cannot execv('" << args_[0]
                    << "'). See the 'Debugging init' section of init's README.md for tips";
    }
}

static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) {
    ...
    return execv(c_strings[0], c_strings.data()) == 0;
}

由 init.zygote64.rc 可知 zygote 的执行程序路径是 /system/bin/app_process64,对应的入口文件为 /frameworks/base/cmds/app_process/app_main.cpp

// frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
    ...
    // 创建 Android 运行时对象,AppRuntime 是 AndroidRuntime 的子类
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ...
    while (i < argc) {
        const char* arg = argv[i++];
        // 如果当前运行在 zygote 进程中
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } 
        ...
    }
    ...
    // 如果运行在zygote 进程中,调用 runtime 的 start 函数
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } 
    ...
}

如果 app_main.cpp 的 main 函数运行在 zygote 进程中,则调用 AndroidRuntime 的 start 函数。

2.2 AndroidRuntime::start

AndroidRuntime 的 start 函数调用 ZygoteInit 的 main 方法,首先看一下 AndroidRuntime 的 start 方法:

// frameworks/base/core/jni/AndroidRuntime.cpp
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;
    }
    ...
    
    // className 为 com.android.internal.os.ZygoteInit
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

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

    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    // 找到 ZygoteInit
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        // 找到 ZygoteInit 的 main 方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            // 通过 JNI 调用 ZygoteInit 的 main 方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
    ...
}

AndroidRuntime::start 函数中主要进行了:

  1. 启动虚拟机
  2. 注册 JNI
  3. 通过 JNI 调用 ZygoteInit 的 main 方法

3. Java 层

ZygoteInit 的 main 方法是由 java 编写的,通过 JNI 调用 ZygoteInit 的 main 方法,zygote 进程从 Native 层进入了 Java 层,所以 zygote 进程可以成为称为 java 进程的鼻祖 :

// com.android.internal.os.ZygoteInit
public static void main(String[] argv) {
    ...
    try {
        ...
        if (!enableLazyPreload) {
            ...
            // 1. 预加载类和资源
            preload(bootTimingsTraceLog);
            ...
        }

        ...
        // 2. 创建 ZygoteServer,创建服务器端 Socket
        zygoteServer = new ZygoteServer(isPrimaryZygote);

        if (startSystemServer) {
            // 3. 启动 SystemServer 进程
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
           ...
        }

        ...
        // 4. 死循环,等待 AMS 请求
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        ...
    } finally {
        ...
    }
    ...
}

ZygoteInit main 方法主要做了:

  1. 预加载相关资源
  2. 创建了 ZygoteServer,创建服务器端 Socket
  3. 创建了 SystemServer 进程
  4. 执行 runSelectLoop

3.1 创建 Server 端 Socket:

// core/java/com/android/internal/os/ZygoteServer.java
ZygoteServer(boolean isPrimaryZygote) {
    mUsapPoolEventFD = Zygote.getUsapPoolEventFD();

    if (isPrimaryZygote) {// PRIMARY_SOCKET_NAME = "zygote"
        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();
}
// core/java/com/android/internal/os/Zygote.java
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
    int fileDesc;
    // 拼接 Socket 的名称,ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_",socketName = "zygote"
    final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;// ANDROID_SOCKET_zygote

    try {
        // 得到 Socket 的环境变量的值
        String env = System.getenv(fullSocketName);
        // 将 Socket 环境变量的值转换为文件描述符的参数
        fileDesc = Integer.parseInt(env);
    } catch (RuntimeException ex) {
        throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
    }

    try {
        // 创建文件描述符
        FileDescriptor fd = new FileDescriptor();
        fd.setInt$(fileDesc);
        // 创建服务器端 Socket
        return new LocalServerSocket(fd);
    } catch (IOException ex) {
        throw new RuntimeException(
            "Error building socket from file descriptor: " + fileDesc, ex);
    }
}

通过 LocalServerSocket 创建了服务器端的 Socket,用来等待 AMS 请求 zygote,以创建新的应用程序进程。

3.2 创建 SystemServer 进程

forkSystemServer 创建 SystemServer 进程:

// com.android.internal.os.ZygoteInit
private static Runnable forkSystemServer(String abiList, String socketName,
        com.android.internal.os.ZygoteServer zygoteServer) {
    ...
    // 创建 args 数组,用来保存启动 SystemServer 的启动参数
    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;

    int pid;

    try {
        ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
        try {
            parsedArgs = ZygoteArguments.getInstance(commandBuffer);
        } catch (EOFException e) {
            throw new AssertionError("Unexpected argument error for forking system server", e);
        }
        commandBuffer.close();
        Zygote.applyDebuggerSystemProperty(parsedArgs);
        Zygote.applyInvokeWithSystemProperty(parsedArgs);
        ...
        /* Request to fork the system server process */
        // 创建子进程 SystemServer
        pid = Zygote.forkSystemServer(
                parsedArgs.mUid, parsedArgs.mGid,
                parsedArgs.mGids,
                parsedArgs.mRuntimeFlags,
                null,
                parsedArgs.mPermittedCapabilities,
                parsedArgs.mEffectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    // 当前代码运行在子线程中
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }

        zygoteServer.closeServerSocket();
        // 处理 SystemServer 进程
        return handleSystemServerProcess(parsedArgs);
    }

    return null;
}

forkSystemServer 内部调用 nativeForkSystemServer 方法,通过 fork 函数在当前进程创建 SystemServer 进程:

// core/java/com/android/internal/os/Zygote.java
static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
        int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
    ZygoteHooks.preFork();

    int pid = nativeForkSystemServer(
            uid, gid, gids, runtimeFlags, rlimits,
            permittedCapabilities, effectiveCapabilities);

    // Set the Java Language thread priority to the default value for new apps.
    Thread.currentThread().setPriority(Thread.NORM_PRIORITY);

    ZygoteHooks.postForkCommon();
    return pid;
}

具体有关 SystemServer 进程的内容在 SystemServer 进程的启动流程中进行详细分析。

3.3 死循环等待 AMS 请求

Zygote 进程将 SystemServer 进程启动后,就会在在这个服务端的 Socket 上等待 AMS 请求 Zygote 进程来创建新的应用程序进程。

执行 runSelectLoop,循环等待 AMS 请求:

// core/java/com/android/internal/os/ZygoteServer.java
Runnable runSelectLoop(String abiList) {
    ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
    ArrayList<ZygoteConnection> peers = new ArrayList<>();
    // mZygoteSocket 为 createManagedSocketFromInitSocket 创建的服务端 Socket,获得该 Socket 的 fd 字段的值并添加到 fd 列表中
    socketFDs.add(mZygoteSocket.getFileDescriptor());
    peers.add(null);

    mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
    // 循环等待 AMS 请求 Zygote 进程创建新的应用程序
    while (true) {
        ...
        int pollIndex = 0;
        // 通过遍历将 socketFDs 存储的信息转移到 pollFDs 中
        for (FileDescriptor socketFD : socketFDs) {
            pollFDs[pollIndex] = new StructPollfd();
            pollFDs[pollIndex].fd = socketFD;
            pollFDs[pollIndex].events = (short) POLLIN;
            ++pollIndex;
        }

        ...
        int pollReturnValue;
        try {
            // 处理轮询状态,当pollFDs有事件到来则往下执行,否则阻塞在这里
            pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
        } catch (ErrnoException ex) {
            throw new RuntimeException("poll failed", ex);
        }
        if (pollReturnValue == 0) {
            ...
        } else {
            boolean usapPoolFDRead = false;
            // 优先处理已建立连接的信息
            while (--pollIndex >= 0) {
                // 接收到请求继续执行,否则tao
                if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                    continue;
                }

                if (pollIndex == 0) {
                    // Zygote server socket
                    // 得到 ZygoteConnection 添加到 Socket 的连接列表 peers 中
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    // 将 ZygoteConnection 的 fd 添加到 socketFDs 中,以便可以接收到 AMS 发送过来的请求。
                    socketFDs.add(newPeer.getFileDescriptor());
                } else if (pollIndex < usapPoolEventFDIndex) {// pollIndex 不为 0
                    // Session socket accepted from the Zygote server socket

                    try {
                        // 创建一个新的应用进程
                        ZygoteConnection connection = peers.get(pollIndex);
                        boolean multipleForksOK = !isUsapPoolEnabled()
                                && ZygoteHooks.isIndefiniteThreadSuspensionSafe();
                        final Runnable command =
                                connection.processCommand(this, multipleForksOK);

                        // TODO (chriswailes): Is this extra check necessary?
                        if (mIsForkChild) {
                            ...

                            return command;
                        } else {
                            ...
                            if (connection.isClosedByPeer()) {
                            // 清除相关信息
                                connection.closeSocket();
                                peers.remove(pollIndex);
                                socketFDs.remove(pollIndex);
                            }
                        }
                    } 
    ...
}

当 AMS 的请求数据到来时,会调用 ZygoteConnection 的 processCommand 方法:

// java/com/android/internal/os/ZygoteConnection.java
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
    ZygoteArguments parsedArgs;

    try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) {
        while (true) {
            try {
                parsedArgs = ZygoteArguments.getInstance(argBuffer);
                // Keep argBuffer around, since we need it to fork.
            } 
            ...

            if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
                    || !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
                // 创建应用程序进程
                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.mIsTopApp, parsedArgs.mPkgDataInfoList,
                        parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
                        parsedArgs.mBindMountAppStorageDirs);

                try {
                    // 当前代码逻辑运行在子进程中
                    if (pid == 0) {
                        // in child
                        // pid == 0 表示创建成功,则进入子进程中,即应用程序进程
                        zygoteServer.setForkChild();

                        zygoteServer.closeServerSocket();
                        IoUtils.closeQuietly(serverPipeFd);
                        serverPipeFd = null;
                        // 处理应用程序进程,进入子进程执行相关操作
                        return handleChildProc(parsedArgs, childPipeFd,
                                parsedArgs.mStartChildZygote);
                    } else {
                        // In the parent. A pid < 0 indicates a failure and will be handled in
                        // handleParentProc.
                        // pid < 0表示创建失败,则进入父进程返回消息给Client Socket表示启动失败
                        IoUtils.closeQuietly(childPipeFd);
                        childPipeFd = null;
                        handleParentProc(pid, serverPipeFd);
                        return null;
                    }
                } finally {
                    IoUtils.closeQuietly(childPipeFd);
                    IoUtils.closeQuietly(serverPipeFd);
                }
            } 
            ...
        }
    }
    ...
}

调用 Zygote 的 forkAndSpecialize 方法来创建应用程序进程,参数为 parsedArgs 中存储的应用进程启动参数,返回值为 pid。forkAndSpecialize 方法通过 fork 当前进程来创建一个子进程,如果 pid = 0,则说明当前代码逻辑运行在新创建的子进程(应用程序进程)中,这时会调用 handleParentProc 方法来处理应用程序进程。

本文主要讲解 zygote 进程的启动过程,具体的应用程序启动过程不在本文进行过多介绍,相关内容会在应用程序启动过程文章中进行详细描述。

到此 zygote 进程就介绍完了,接下来我们看看 SystemServer 进程。

转载自:https://juejin.cn/post/7384617995874009125
评论
请登录