按下電源鍵後竟然發生了這一幕 —— Android 系統啟動流程分析

guanpj發表於2019-01-16

作為一名 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 是一個配置檔案,它由 Android 初始化語言編寫,zygote 程式和 servicemanager 程式都是由 init 程式解析 init.rc 中特定的語句啟動的,比如,啟動 zygote 程式的程式碼格式如下:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc
    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
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks
複製程式碼

事實上,在 system/core/rootdir 目錄下,有多個 init.rc 檔案,在不同的硬體環境下,相應的 init.rc 檔案會被匯入,比如在 64 位作業系統中,上面啟動 zygote 程式的程式碼是從 init.zygote64.rc 檔案中匯入的。

servicemanager 程式 —— Binder 服務的總管

我在文章藉助 AIDL 理解 Android Binder 機制——Binder 來龍去脈中講到“Binder 通訊模型和通訊過程”的時候提到過 ServerManager,它是 Binder IPC 的核心,是上下文的管理者,Binder 服務端必須先向 ServerManager 註冊才能夠為客戶端提供服務,Binder 客戶端在與服務端通訊之前需要從 ServerManager 中查詢並獲取 Binder 服務端的引用。然而 ServerManager 在向 Binder 驅動申請成為上下文管理者的時候又涉及到了 Binder IPC 過程,這時候應該怎麼處理呢?

servicemanager 程式是由 init 程式通過解析 init.rc 檔案來啟動的,對應的程式碼如下:

service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm
複製程式碼

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 技術內幕

如果你對文章內容有疑問或者有不同的意見,歡迎留言,我們一同探討。

相關文章