按下电源键后竟然发生了这一幕 —— Android 系统启动流程分析

作为一名 Android 程序员,你有没有想过:那么复杂的 Android 系统,它是怎样运行起来的,我们的 App 又是怎样被 Android 系统加载后呈现在屏幕上的呢?Android 系统的启动是一个比较复杂的过程,涉及到了一些我们没有接触过的知识,本文将基于 Android Nougat 最新的代码上讲述 Android 系统的启动流程。

Bootloader —— 第一个程序

当按下电源键(加电)或者系统重启(复位)的时候,引导芯片会从 ROM(这里一般指 Flash ROM,即闪存)中预定义的位置将 Bootloader 载入到 RAM 中,接着,Bootloader 将会把 Linux 内核载入到 RAM 中并启动。

ROM

Bootloader 是在系统内核运行之前运行的一段小程序,也是系统运行的第一个程序,它的主要作用是:

  1. 初始化 RAM(一般指内存)
  2. 初始化硬件设备
  3. 加载内核和内存空间影像图
  4. 跳转到内核

init 进程 —— 1 号进程

Linux 内核启动过程中会创建 init 进程,init 进程是用户空间的第一个进程(pid=1),对应的可执行程序的源文件文件为 /system/core/init/Init.cpp,它的 main 方法如下:

int main(int argc, char** argv) {
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
    if (!strcmp(basename(argv[0]), "watchdogd")) {
        return watchdogd_main(argc, argv);
    }
    umask(0);
    add_environment("PATH", _PATH_DEFPATH);
    bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
    // 创建文件并挂载
    if (is_first_stage) {
        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
        mkdir("/dev/pts", 0755);
        mkdir("/dev/socket", 0755);
        mount("devpts", "/dev/pts", "devpts", 0, NULL);
        #define MAKE_STR(x) __STRING(x)
        mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
        mount("sysfs", "/sys", "sysfs", 0, NULL);
    }
    open_devnull_stdio();
    klog_init();
    klog_set_level(KLOG_NOTICE_LEVEL);
    NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
    if (!is_first_stage) {
        // Indicate that booting is in progress to background fw loaders, etc.
        close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
        // 初始化属性相关资源
        property_init();
        process_kernel_dt();
        process_kernel_cmdline();
        export_kernel_boot_props();
    }
    ...
    // 启动属性服务
    start_property_service();
    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);
    Parser& parser = Parser::GetInstance();
    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
    parser.AddSectionParser("on", std::make_unique<ActionParser>());
    parser.AddSectionParser("import", std::make_unique<ImportParser>());
    // 解析init.rc配置文件
    parser.ParseConfig("/init.rc");
    ...   
    while (true) {
        if (!waiting_for_exec) {
            am.ExecuteOneCommand();
            restart_processes();
        }
        int timeout = -1;
        if (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * 1000;
            if (timeout < 0)
                timeout = 0;
        }
        if (am.HasMoreCommands()) {
            timeout = 0;
        }
        bootchart_sample(&timeout);
        epoll_event ev;
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
        if (nr == -1) {
            ERROR("epoll_wait failed: %s\n", strerror(errno));
        } else if (nr == 1) {
            ((void (*)()) ev.data.ptr)();
        }
    }
    return 0;
}

init 进程的职责主要有四个:

  1. 解析和运行所有 init.rc 文件
  2. 生成设备驱动节点
  3. 处理子进程的终结
  4. 提供属性服务

这里重点看第一点,init.rc 是一个配置文件,内容大概如下:

import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc

on early-init
    # Set init and its forked children's oom_adj.
    write /proc/1/oom_score_adj -1000
    # Disable sysrq from keyboard
    write /proc/sys/kernel/sysrq 0
    # Set the security context of /adb_keys if present.
    restorecon /adb_keys
    # Shouldn't be necessary, but sdcard won't start without it. http://b/22568628.
    mkdir /mnt 0775 root system
    # Set the security context of /postinstall if present.
    restorecon /postinstall
    start ueventd
    
...(省略)...

service flash_recovery /system/bin/install-recovery.sh
    class main
    oneshot

rc 文件由 Android 初始化语言编写,rc 文件主要包含 Action、Service、Command、Options 等,这些操作都由特殊的命令组成。

在开头几行代码中,import 导入了几个 rc 文件,事实上,在 system/core/rootdir 目录下,有多个 init.XXX.rc 文件,在不同的硬件环境下,相应的 init.XXX.rc 文件会被导入,比如在 64 位操作系统中,init.zygote64.rc 文件将会被导入,它的内容如下:

service zygote /system/bin/app_process64 -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 audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks

这几行代码表示启动一个名字为 zygote、 执行文件路径为 /system/bin/app_process64、参数为 -Xzygote /system/bin --zygote --start-system-server 的进程。

除了 zygote 进程,还有许多关键进程都是由 init 进程通过读取相应的 rc 文件进行启动的,如 servicemanager、surfaceflinger 和 mediaserver 进程等等,这些进程都是保证系统运行必不可少的。限于篇幅,下面只列举出比较关键的部分。

servicemanager 进程 —— Binder 服务的总管

我在文章借助 AIDL 理解 Android Binder 机制——Binder 来龙去脉中讲到“Binder 通信模型和通信过程”的时候提到过 ServerManager,它是 Binder IPC 的核心,是上下文的管理者,Binder 服务端必须先向 ServerManager 注册才能够为客户端提供服务,Binder 客户端在与服务端通信之前需要从 ServerManager 中查找并获取 Binder 服务端的引用。然而 ServerManager 在向 Binder 驱动申请成为上下文管理者的时候又涉及到了 Binder IPC 过程,这时候应该怎么处理呢?答案在后文讲解。

servicemanager 进程是通过解析 servicemanager.rc 文件来启动的,对应的代码如下:

service servicemanager /system/bin/servicemanager
    class core
    user system
    group system readproc
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart audioserver
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart inputflinger
    onrestart restart drm
    onrestart restart cameraserver
    writepid /dev/cpuset/system-background/tasks

servicemanager 进程对应可执行程序的源文件为 framework/native/cmds/servicemanager/service_manager.c,简化后的代码如下:

int main(int argc, char **argv) {
    struct binder_state *bs;
    // 打开binder驱动,申请 128k 字节大小的内存空间
    bs = binder_open(128*1024);
    ...

    // 成为上下文管理者
    if (binder_become_context_manager(bs)) {
        return -1;
    }

    // 验证 selinux 权限,判断进程是否有权注册或查看指定服务
    selinux_enabled = is_selinux_enabled();
    sehandle = selinux_android_service_context_handle();
    selinux_status_open(true);

    if (selinux_enabled > 0) {
        if (sehandle == NULL) {  
            abort();
        }
        if (getcon(&service_manager_context) != 0) {
            abort();
        }
    }
    ...

    // 进入无限循环,处理 client 端发来的请求 
    binder_loop(bs, svcmgr_handler);
    return 0;
}

这里重点关注两点,首先,在申请了一块大小为 128k 的内存空间并验证 selinux 权限后,接着调用 framework/native/cmds/servicemanager/binder.c 中的 binder_become_context_manager 方法:

int binder_become_context_manager(struct binder_state *bs) {
    // 通过ioctl,发送 BINDER_SET_CONTEXT_MGR 指令
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}

然后,调用 binder_loop 方法进入循环来处理 client 发来的请求,注意第二个参数是一个方法体,用于处理各种状态回调:

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;
    ...
    
    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);
    ...

    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE: 
        // 获取服务名
        s = bio_get_string16(msg, &len); 
        // 根据名称查找相应服务
        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
        bio_put_ref(reply, handle);
        return 0;

    case SVC_MGR_ADD_SERVICE: 
        // 获取服务名
        s = bio_get_string16(msg, &len);
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
         // 注册指定服务
        if (do_add_service(bs, s, len, handle, txn->sender_euid,
            allow_isolated, txn->sender_pid))
            return -1;
        break;
    }
}

servicemanager 进程在启动过程的工作内容如下:

  1. 调用 binder_open 方法打开 Binder 驱动,并申请分配一块 128k 的内存空间
  2. 调用 binder_become_context_manager 方法发送 BINDER_SET_CONTEXT_MGR 给 Binder 驱动,使自己成为上下文管理者
  3. 验证 selinux 权限,判断进程是否有注册或查看指定服务的权限
  4. 调用 binder_loop 方法进入循环状态,等待 Client 请求
  5. 根据服务名称注册服务·
  6. 接收 Binder 死亡通知
servicemanager

zygote 进程 —— Java 进程的始祖

通过解析 init.rc 文件,
zygote 进程对应的可执行程序的源文件为 frameworks/base/cmds/app_process/App_main.cpp,它的 main 方法如下:

int main(int argc, char* const argv[])
{
    ...
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ...
    Vector<String8> args;
    if (!className.isEmpty()) {
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
    } else {
        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);
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }
    if (zygote) {
        // 调用 AppRuntime 父类 AndroidRuntime 的 start 方法创建 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.");
        return 10;
    }
}

调用 frameworks/base/core/jni/AndroidRuntime.cpp 的 start 方法:

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;
    // 启动 DVM
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);
    // 注册 JNI 方法
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    // 创建数组
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
    // 从 app_main 的 main 函数得知 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);
    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 (env->ExceptionCheck())
                threadExitUncaughtException(env);
        }
    }
  ...
}

通过 JNI 的方式进入 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static void main(String argv[]) {
    ...
    try {
        ...       
        // 注册Zygote用的Socket
        registerZygoteSocket(socketName);
        ...
        // 预加载类和资源
        preload();//2
        ...
        if (startSystemServer) {
            // 启动SystemServer进程
            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;
    }
}

ZygoteInit.java 的 registerZygoteSocket 方法:

private static void registerZygoteSocket(String socketName) {
    if (sServerSocket == null) {
        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(fullSocketName + " unset or invalid", ex);
        }
        try {
            FileDescriptor fd = new FileDescriptor();
            fd.setInt$(fileDesc);
            // 创建 Socket 客户端
            sServerSocket = new LocalServerSocket(fd);
        } catch (IOException ex) {
            throw new RuntimeException(
                "Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

ZygoteInit.java 的 startSystemServer 方法:

private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
    ...
    /* Hardcoded command line to start the system server */
    // SystemServer 启动参数
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server",
        "--runtime-args",
        "com.android.server.SystemServer",
    };
    ZygoteConnection.Arguments parsedArgs = null;

    int pid;

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

        // 调用 Zygote.java fock 出新线程,名字叫 system_server
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }
    // pid 为 0 则为 fock 出来的子线程
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }
        // 启动 SystemServer 进程
        handleSystemServerProcess(parsedArgs);
    }

    return true;
}

frameworks/base/core/java/com/android/internal/os/Zygote.java 的 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) {
    VM_HOOKS.preFork();
    // 调用 Native 层的方法 fock 出子线程
    int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits, 
                mountExternal, seInfo, niceName, fdsToClose, instructionSet, appDataDir);
    // Enable tracing as soon as possible for the child process.
    if (pid == 0) {// fock 出来的子线程中执行
        Trace.setTracingEnabled(true);
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
    }
    VM_HOOKS.postForkCommon();
    return pid;
}

ZygoteInit.java 的 runSelectLoop 方法:

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    // sServerSocket 对象就是刚才在 registerZygoteSocket 方法中创建的服务端 Socket
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    // 循环读取状态
    while (true) {
        StructPollfd[] pollFds = new StructPollfd[fds.size()];
        for (int i = 0; i < pollFds.length; ++i) {
            pollFds[i] = new StructPollfd();
            pollFds[i].fd = fds.get(i);
            pollFds[i].events = (short) POLLIN;
        }
        try {
            Os.poll(pollFds, -1);
        } catch (ErrnoException ex) {
            throw new RuntimeException("poll failed", ex);
        }
        for (int i = pollFds.length - 1; i >= 0; --i) {
            // 读取的状态不是客户端连接或者数据请求时,进入下一次循环
            if ((pollFds[i].revents & POLLIN) == 0) {
                continue;
            }
            if (i == 0) {// i = 0 表示跟客户端 Socket 连接上了
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {// i > 0 表示接收到客户端 Socket 发送过来的请求
                // runOnce 方法创建一个新的应用程序进程
                boolean done = peers.get(i).runOnce();
                if (done) {
                    peers.remove(i);
                    fds.remove(i);
                }
            }
        }
    }
}

frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java 的 runOnce 方法:

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;

    try {
        // 读取 socket 客户端发送过来的参数列表
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        // EOF reached.
        closeSocket();
        return true;
    }
    ...

    try {
        // 将 socket 客户端传递过来的参数,解析成 Arguments 对象格式
        parsedArgs = new Arguments(args);
        ...
        // 同样调用 Zygote.java 的 forkAndSpecialize 方法 fock 出子进程
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
    } catch (Exception e) {
        ...
    }

    try {
        if (pid == 0) {
            // 子进程执行
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            // 进入子进程流程
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
            return true;
        } else {
            // 父进程执行
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

从 App_main 开始,zygote 启动过程的时序图如下:


zygote

可以看到,这个过程中 zygote 首先启动了 AndroidRuntime 并通过它反射调用了 ZygoteInit.main() 方法,由此进入了 Java 的世界,因此 zygote 是 Java 层的第一个进程,也是其他 Java 进程的始祖,其他 Java 进程的创建必须依赖 zygote。

zygote 进程的任务分别是:

  1. 创建 AppRuntime(继承自 AndroidRuntime), 并调用它的 start 方法
  2. 调用 AndroidRuntime 的 startVM() 方法创建 DVM(Dalvik Virtual Machine),并调用 startReg() 方法为 DVM 注册 JNI
  3. 通过 JNI 调用 ZygoteInit.main() 方法,第一次进入 Java 的世界
  4. 调用 registerZygoteSocket() 函数建立 Socket 通道,使 zygote 进程成为 Socket 服务端,并通过 runSelectLoop() 函数等待 ActivityManagerService 发送请求创建新的应用程序进程
  5. 调用 startSystemServer() 函数 fock 出 system_server 进程

system_server 进程 —— 承载 framework 层核心业务

接下来分别讲解 system_server 进程的启动过程和 system_server 进程的执行过程。

1.system_server 进程的启动过程

在上一小节中我们已经知道,zygote 进程在启动的过程中会通过 startSystemServer 方法 fock 出了一个叫 system_server 的进程,然后再该方法内执行了 handleSystemServerProcess 方法:

private static void handleSystemServerProcess(
          ZygoteConnection.Arguments parsedArgs)
          throws ZygoteInit.MethodAndArgsCaller {
    /** 由于 fock 出来的 system_server 进程会复制 zygote 进程的地址空间,因此它也得到了 zygote
    进程中的 Socket,这个 Socket 对它来说并无用处,这里将其关闭 **/
    closeServerSocket();
    ...
    if (parsedArgs.invokeWith != null) {
        ...
    } else {
        ClassLoader cl = null;
        if (systemServerClasspath != null) {
            cl = createSystemServerClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
            Thread.currentThread().setContextClassLoader(cl);
        }
        // 出现新的类 RuntimeInit,调用了它的 zygoteInit 方法
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
    }
}

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java 的 zygoteInit 方法:

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
    if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
    redirectLogStreams();
    commonInit();
    /** 通过 Native 层中 AndroidRuntime.cpp 的 JNI 方法最终调用 app_main.cpp 的 onZygoteInit 方法
    启动 Binder 线程池, 使 system_server 进程可以使用 Binder 与其他进程通信 **/
    nativeZygoteInit();
    // 继续往下调用
    applicationInit(targetSdkVersion, argv, classLoader);
}

RuntimeInit 的 applicationInit 方法:

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
    ...
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

RuntimeInit 的 invokeStaticMain 方法:

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
         throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;
    try {
        /** className 为 ZygoteInit.java 中 startSystemServer 方法
        传递过来的 "com.android.server.SystemServer",这里通过反射得到 SystemServer 类 **/
        cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) {
        throw new RuntimeException(
            "Missing class when invoking static main " + className, ex);
    }
    Method m;
    try {
        // 找到 SystemServer 类的 main 方法
        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);
    }
    /** 将 main 方法包装在 ZygoteInit.MethodAndArgsCaller 类中并作为异常抛出
    捕获异常的地方在上一小节中 ZygoteInit.java 的 main 方法 **/
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 的 main 方法:

public static void main(String argv[]) {
    ...
    closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        // 接收到 caller 对象后调用它的 run 方法
        caller.run();
    } catch (RuntimeException ex) {
        Log.e(TAG, "Zygote died with exception", ex);
        closeServerSocket();
        throw ex;
    }
}

ZygoteInit 的 MethodAndArgsCaller 类是一个 Exception 类,同时也实现了 Runnable 接口:

public static class MethodAndArgsCaller extends Exception
        implements Runnable {
        
    private final Method mMethod;
    private final String[] mArgs;
        
    public MethodAndArgsCaller(Method method, String[] args) {
        mMethod = method;
        mArgs = args;
    }
    public void run() {
        try {
            // 调用传递过来的 mMethod
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        } catch (InvocationTargetException ex) {
            ...
        }
    }
}

这样,system_server 进程便启动起来并进入了 SystemServer.java 的 main 方法。

这里需要思考一下,为什么需要抛出异常到 ZygoteInit 中执行?官方解释就是抛出异常的时候 Android 虚拟机会清空该进程堆内存中的栈帧,因此前面一系列启动 system_server 进程的过程中方法调用过程就被清除了,节省了堆栈的空间,使 ZygoteInit.java 的 main 方法处于所有 Java 进程的方法栈中的栈顶。另外,从最新 Android Pie 的代码中看,这个过程已经变成在每一步中将包装好的 MethodAndArgsCaller 对象作为返回值返回,最后在 ZygoteInit 执行对象的 call 方法,这样每个方法都执行了返回过程,自然在堆栈中对应的栈帧也被弹出栈了。

2.system_server 进程的执行过程

查看 frameworks/base/services/java/com/android/server/SystemServer.java 的源码:

/**
 * The main entry point from zygote.
 */
public static void main(String[] args) {
    // 调用 run 方法
    new SystemServer().run();
}
private void run() {
    ...
    // 加载 libandroid_servers.so
    System.loadLibrary("android_servers");
    ...
    // 创建 SystemServiceManager
    mSystemServiceManager = new SystemServiceManager(mSystemContext);
    LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
    ...    
    try {
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
        // 启动引导服务
        startBootstrapServices();
        // 启动核心服务
        startCoreServices();
        // 启动其他服务
        startOtherServices();
    } catch (Throwable ex) {
        ...
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
    ...
}

可以看到,在 run 方法中,主要执行了启动引导服务、核心服务和其他服务的任务,这些服务加起来一共有 80 多个,它们对应这个各种不同的功能,部分服务如下:

引导服务 作用
Installer 系统安装apk时的一个服务类,启动完成Installer服务之后才能启动其他的系统服务
ActivityManagerService 负责四大组件的启动、切换、调度。
PowerManagerService 计算系统中和Power相关的计算,然后决策系统应该如何反应
LightsService 管理和显示背光LED
DisplayManagerService 用来管理所有显示设备
UserManagerService 多用户模式管理
SensorService 为系统提供各种感应器服务
PackageManagerService 用来对apk进行安装、解析、删除、卸载等等操作
核心服务 作用
BatteryService 管理电池相关的服务
UsageStatsService 收集用户使用每一个APP的频率、使用时常
WebViewUpdateService WebView更新服务
其他服务 作用
CameraService 摄像头相关服务
AlarmManagerService 全局定时器管理服务
InputManagerService 管理输入事件
WindowManagerService 窗口管理服务
VrManagerService VR模式管理服务
BluetoothService 蓝牙管理服务
NotificationManagerService 通知管理服务
DeviceStorageMonitorService 存储相关管理服务
LocationManagerService 定位管理服务
AudioService 音频相关管理服务
... ...

小结

system_server 进程在启动过程中完成的工作分别是:

  1. 启动 Binder 线程池,使进程可以通过 Binder 与其他进程进程通信
  2. 创建 SystemServiceManager
  3. 使用 SystemServiceManager 对各种系统服务进行创建、启动和生命周期管理

Launcher —— Android 系统的“桌面”

在上一节 frameworks/base/services/java/com/android/server/SystemServer.java 的 main 方法中,有一句:

private void startOtherServices() {
    ...
    // 调用 AMS 的 systemReady 方法
    mActivityManagerService.systemReady(new Runnable() {
        @Override
        public void run() {
            ...
        }
    }
    ...
}

继续跟踪:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public void systemReady(final Runnable goingCallback) {
    ...
    synchronized (this) {
        ...
        // 调用 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked 方法
        mStackSupervisor.resumeFocusedStackTopActivityLocked();
        mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
    }
}

frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean resumeFocusedStackTopActivityLocked(ActivityStack targetStack, ActivityRecord target,
        ActivityOptions targetOptions) {
    if (targetStack != null && isFocusedStack(targetStack)) {
        // 调用 ActivityStack 的 resumeTopActivityUncheckedLocked 方法
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }
    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
    if (r == null || r.state != RESUMED) {
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
    }
    return false;
}

ActivityStack

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
    if (mStackSupervisor.inResumeTopActivity) {
        return false;
    }

    boolean result = false;
    try {
        // Protect against recursion.
        mStackSupervisor.inResumeTopActivity = true;
        if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
            mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
            mService.updateSleepIfNeededLocked();
        }
        // 调用 resumeTopActivityInnerLocked 方法
        result = resumeTopActivityInnerLocked(prev, options);
    } finally {
        mStackSupervisor.inResumeTopActivity = false;
    }
    return result;
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
   ...
   // 回到 ActivityStackSupervisor 的 resumeHomeStackTask 方法
   return isOnHomeDisplay() && mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "prevFinished");
   ...                 
}

frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev, String reason) {
    ...
    if (r != null && !r.finishing) {
        mService.setFocusedActivityLocked(r, myReason);
        return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
    }
    // 再次回到 AMS 的 startHomeActivityLocked 方法
    return mService.startHomeActivityLocked(mCurrentUser, myReason);
}
boolean startHomeActivityLocked(int userId, String reason) {
    if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
            && mTopAction == null) {
        return false;
    }
    // 获取 Intent
    Intent intent = getHomeIntent();
    ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
        intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
        aInfo = new ActivityInfo(aInfo);
        aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
        ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                aInfo.applicationInfo.uid, true);
        if (app == null || app.instrumentationClass == null) {
            intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
            // 使用 mActivityStarter 启动 app,这里不再详细跟踪
            mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
        }
    } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
    }

    return true;
}

getHomeIntent 方法:

Intent getHomeIntent() {
    Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
    intent.setComponent(mTopComponent);
    intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
    if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
        // 添加 android.intent.category.HOME
        intent.addCategory(Intent.CATEGORY_HOME);
    }
    return intent;
}

可以看到,最后通过一个隐式 Intent 使用 Intent.FLAG_ACTIVITY_NEW_TASK 模式启动了一个带 Intent.CATEGORY_HOME 标签的 Activity,而带有 Intent.CATEGORY_HOME 标签的 Activity 正是 Launcher App,它的 AndroidManifest 文件如下:

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.launcher3">
    <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="16"/>
    
    ...
    
    <application
        android:allowBackup="@bool/enable_backup"
        android:backupAgent="com.android.launcher3.LauncherBackupAgentHelper"
        android:hardwareAccelerated="true"
        android:icon="@mipmap/ic_launcher_home"
        android:label="@string/app_name"
        android:largeHeap="@bool/config_largeHeap"
        android:restoreAnyVersion="true"
        android:supportsRtl="true" >
        <activity
            android:name="com.android.launcher3.Launcher"
            android:launchMode="singleTask"
            android:clearTaskOnLaunch="true"
            android:stateNotNeeded="true"
            android:theme="@style/Theme"
            android:windowSoftInputMode="adjustPan"
            android:screenOrientation="nosensor"
            android:configChanges="keyboard|keyboardHidden|navigation"
            android:resumeWhilePausing="true"
            android:taskAffinity=""
            android:enabled="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.MONKEY"/>
            </intent-filter>
        </activity>
        
        ...
        
    </application>
</manifest>

Launcher 启动后会将所有已安装的应用图标展示在一个网格布局的 RecyclerView 里面,这时候用户就可以通过点击这些图标来启动相应的 app 了。

整个过程的时序图如下:

Launcher

关于 Launcher 如何将 App 图标显示出来等更多工作细节,可以参考Android M Launcher3主流程源码浅析Android系统启动流程(四)Launcher启动过程与系统启动流程这两篇文章。

总结

最后,从整体上来看 Android 系统的启动流程:

  1. 按下电源,固化在 ROM 中预定位置的 Bootloader 将会被加载到内存中
  2. Bootloader 初始化完软硬件环境后将 Linux 内核启动起来
  3. Linux 内核启动时会做设置缓存、被保护存储器、计划列表和加载驱动等一些列操作,内核启动完成后会启动 init 进程
  4. init 进程会初始化并启动属性服务,并且解析并执行所有 init.rc 文件
  5. init 通过执行特定的 init.rc 文件启动 servermanager 进程,servermanager 被启动后会向 Binder 驱动发送命令让自己成为守护进程并管理所有上下文
  6. init 通过解析 init.rc 文件启动 zygote 进程
  7. zygote 进程启动的过程会创建 DVM 并为其注册 JNI 函数,然后创建服务端 Socket、启动 system_server 进程
  8. 启动 system_server 进程的过程会创建 Binder 线程池使其具有 IPC 能力,然后启动 AMS 等各种系统服务
  9. AMS 启动 Launcher,Launcher 被启动后会将已安装应用的图标显示在界面上

原来,一个复杂的 Android 系统就这么被运行起来了,碍于本人有限的水平,描述这个过程其实也还简化了很多操作,下面这个图比较全面地总结了这个流程:

android 系统启动流程

系列文章

按下电源键后竟然发生了这一幕 —— Android 系统启动流程分析(本文)

App 竟然是这样跑起来的 —— Android App/Activity 启动流程分析

屏幕上内容究竟是怎样画出来的 —— Android View 工作原理详解

参考文章

Gityuan 大神的系列文章

刘望舒老师的系列文章

嵌入式系统 Boot Loader 技术内幕

如果你对文章内容有疑问或者有不同的意见,欢迎留言,我们一同探讨。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容