Android系統啟動過程分析


Android系統啟動過程分析

一、Android平台架構

首先貼一張Android系統架構圖方便理解整個Android架構,這可以讓我們從整體上對整個啟動流程有個大概認知。

Android系統架構圖

可以看出整個架構由5部分構成,從下到上分別為:
1. Linux內核層
Android 的核心系統服務基於Linux 內核,在此基礎上添加了部分Android專用的驅動。系統的安全性、內存管理、進程管理、網絡協議棧和驅動模型等都依賴於該內核。
2. 硬件抽象層(HAL)
硬件抽象層是位於操作系統內核與硬件電路之間的接口層,其目的在於將硬件抽象化,為了保護硬件廠商的知識產權,它隱藏了特定平台的硬件接口細節,為操作系統提供虛擬硬件平台,使其具有硬件無關性,可在多種平台上進行移植。 HAL 由多個庫模塊組成,每個模塊都為特定類型的硬件組件實現了一個接口,例如相機或藍牙模塊。 當框架 API 調用設備硬件時,Android 系統為該硬件組件加載庫模塊。
3. 系統運行庫層(Native)
系統運行庫層分為兩部分,分別是C/C++程序庫和Android運行時庫。 C/C++程序庫被Android中不同的部分使用 runtime庫主要是Java核心庫(提供了Java語言核心功能因此開發者可以使用Java編寫應用)和ART(Android 5.0 之前是Dalvik)該虛擬機不同於JVM是專門用於移動設備的虛擬機 允許在有限的內存內運行多個虛擬機實例 並且每個應用都是獨立的linux進程這樣可以防止虛擬機崩潰時不會導致所有的進程被關閉。ART和Dalvik的區別是 后者在應用每次啟動時才會通過即時編譯把字節碼轉化為機器碼 (這會影響應用運行效率)ART則是在應用第一次安裝的時候就會把字節碼文件轉換為機器碼 這樣雖然會在安裝時耗時增加 但app每次啟動的時間會減少
4. 應用框架層(Java Framework)
應用框架層為開發人員提供了可以開發應用程序所需要的API,我們平常開發應用程序都是調用的這一層所提供的API,當然也包括系統的應用。這一層的是由Java代碼編寫的,可以稱為Java Framework
該層包含以下內容:

  • 一個豐富和可擴展的視圖系統
  • Resource Manager
  • Notification Manager
  • Activity Manager
  • Content Providers
  1. 應用層
    系統內置的應用程序以及非系統級的應用程序都是屬於應用層。負責與用戶進行直接交互,通常都是用Java進行開發的

二、Android系統的啟動流程

Android系統的啟動流程大致分為三個階段:

  1. 電源鍵按下后加載引導程序Bootloader到RAM 然后Bootloader把OS拉起
  2. Linux 內核層面的啟動
  3. Android系統層面的啟動

本文主要分析Android系統層面的啟動

一、Bootloader的加載

當電源鍵被按下后會去加載Bootloader,這個程序會把OS拉活,然后就會進入OS的啟動過程。

二、Linux內核的啟動

Android底層是基於Linux內核的並做了一些擴展,添加一些驅動比如binder。Linux內核的啟動流程是先啟動idle線程(整個Linux系統的初始線程 pid=0)然后idle線程會啟動init和kthread線程。init線程是負責啟動Android系統並且是Android系統其他進程的父進程。kthread線程則負責創建並管理Linux系統內核線程。

1、ildle進程

主要是完成Linux系統的啟動然后完成一些初始化任務之后會進入一個死循環,不斷判斷是否有新的進程需要啟動如果沒有則會讓cpu和系統時鍾進入休眠狀態 當有新進程需要創建時在喚醒cpu

2、kthread進程

主要負責創建Linux系統內核相關線程 並始終運行在內核線程中 作為內核線程中其他線程的父類 負責內核線程的調度和管理

3、init進程

它是Linux系統第一個用戶進程,主要工作分為兩部分。首先會完成內核的創建和初始化這部分內容跟Linux內核相關, 其次就是用戶空間的創建和啟動這部分內容跟Android系統的啟動相關

init進程第一階段做的主要工作是掛載分區,創建設備節點和一些關鍵目錄,初始化日志輸出系統,啟用SELinux安全策略

init進程第二階段主要工作是初始化屬性系統,解析SELinux的匹配規則,處理子進程終止信號,啟動系統屬性服務,可以說每一項都很關鍵,如果說第一階段是為屬性系統,SELinux做准備,那么第二階段就是真正去把這些落實的。

其實init進程在完成第二階段工作的時候就已經涉及到Android系統層面的啟動了 因為init進程會去加載init.rc配置文件然后啟動Zygote進程。
Init的啟動入口是在其main函數中

int main(int argc, char** argv) {
    ......
    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
    if (is_first_stage) {
        boot_clock::time_point start_time = boot_clock::now();
        umask(0);
        //創建和掛載啟動所需要的文件目錄
        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));
        chmod("/proc/cmdline", 0440);
        gid_t groups[] = { AID_READPROC };
        setgroups(arraysize(groups), groups);
        mount("sysfs", "/sys", "sysfs", 0, NULL);
        mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
        mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
        mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
        mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
        ......
       // Set up SELinux, loading the SELinux policy.啟動SELinux
        selinux_initialize(true);
        ......
    }
    ......
    //對屬性服務進行初始化
    property_init();
    ......

    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        PLOG(ERROR) << "epoll_create1 failed";
        exit(1);
    }
    //用於設置子進程信號處理函數,如果子進程異常退出,init進程會調用該函 
    //數中設置的信號處理函數進行處理。
    signal_handler_init();
    ......
    //啟動屬性服務
    start_property_service();
    ......
    if (bootscript.empty()) {
        //解析init.rc配置文件
        parser.ParseConfig("/init.rc");
        parser.set_is_system_etc_init_loaded(
                parser.ParseConfig("/system/etc/init"));
        parser.set_is_vendor_etc_init_loaded(
                parser.ParseConfig("/vendor/etc/init"));
        parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
    } 
    ......
    while (true) {
        ......
        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            //重啟死去的服務
            restart_processes();
        }
        ......
    }
    return 0;
}

我們注意下init.rc文件,它的路徑為:system/core/rootdir/init.rc。它是一個非常重要的配置文件,是由Android初始化語言編寫的腳本。Android8.0對該文件進行來拆分,每個服務對應一個rc文件,啟動Zygote的腳本在init.zygoteXX.rc中定義,代表多少位處理器。這里以64位為例。

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

我們只需要知道上面的命令就是創建名為zygote的進程即可。實際創建是通過app_process64完成的,對應的文件為app_main.cpp,創建完成后會調用zygote的mian函數。

int main(int argc, char* const argv[])
{
...

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

 // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;//2
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
...

 if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//3
    } 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.");
    }
    

首先在注釋1處聲明了一個AppRuntime類型的runtime,然后在注釋2處將zygote置為true,最后在注釋3處用runtime.start()啟動zygote。

三、Android 系統的啟動

之前我們跟蹤到zygote進程的啟動,zygote可以看做是Android系統所有進程的父進程,DVM和ART、應用程序進程以及運行系統的關鍵服務SystemServer進程都是由Zygote進程通過fork創建的。Zygote預加載初始化核心庫類,讓DVM和ART虛擬機共享代碼、降低內存占用和啟動時間,因此只要Zygote裝載好了這些類和資源后,新的進程就不需要在裝載這些類和資源了,它們共享Zygote進程的資源和類。

那接下來我們看下AppRuntime的start方法
frameworks/base/core/jni/AndroidRuntime.cpp

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;
    //1 啟動Java虛擬機
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     *
     */
    if (startReg(env) < 0) {//2 注冊jni方法
        ALOGE("Unable to register all android natives\n");
        return;
    }
/*
     * We want to call main() with a String array with arguments in it.
     * At present we have two arguments, the class name and an option string.
     * Create an array to hold them.
     */
    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傳過來的參數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);
    }

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");//3 找到ZygoteInit的main函數,該函數是要啟動的函數
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);//4 通過Jni調用ZygoteInit的main函數

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

在start方法中我們看到先是在注釋1處啟動虛擬機然后在注釋2處注冊jni.之后就是通過傳入的類名找到要啟動的class最終在注釋3處將其賦值給startMeth(此時表示要啟動ZygoteInit的main函數),最終的啟動是在注釋4處。

我們看下ZygoteInit的main函數

   public static void main(String argv[]) {
   ...
           ZygoteServer zygoteServer = new ZygoteServer();//1 構造zygoteServer實例

...
boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            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(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }
            zygoteServer.registerServerSocket(socketName);//2 注冊服務端的scoket
             if (startSystemServer) {//通過fork啟動SystemServer進程
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);//3

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();//此處調用的run方法是MethodAndArgsCaller類的run 該類是RuntimeInit的一個靜態內部類
                    return;
                }
            }

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

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            caller = zygoteServer.runSelectLoop(abiList);//4等待客戶端請求 fork進程

        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {

            zygoteServer.closeServerSocket();
        }

在注釋1處構造了一個zygoteServer實例,之后在注釋2處注冊服務端的scoket,這里scoket的類型是loaclscoket它是Android對Linuxscoket的一種封裝。Local Socket 是Linux提供的一種基於Socket的進程間通信方式,對Server端來講,唯一的區別就是bind到一個本地的文件描述符(fd)而不是某個IP地址和端口號。Android里很多地方用到了Local Socket做進程間的通信。scoket創建完成后就等待用來相應客戶端fork的請求,即在注釋3處通過fork啟動SystemServer進程,在注釋4處等待客戶端fork進程的請求。

總結來說ZygoteInit主要做了兩件事:
1、注冊了服務端的scoket
2、fork進程 啟動SystemServer進程

此處說下zygoteinit這個類 Android8.0發生了一些改動。之前在main函數會先預加載(preload)一些東西然后注冊服務端socket。在8.0版本預加載的操作放在了靜態代碼塊中,下面是preload的靜態代碼塊。preload主要做了兩件事 preloadClasses(); preloadResources();
preloadClassess 將framework.jar里的preloaded-classes 定義的所有class load到內存里,preloaded-classes 編譯Android后可以在framework/base下找到。而preloadResources 將系統的Resource(不是在用戶apk里定義的resource)load到內存。

資源preload到Zygoted的進程地址空間,所有fork的子進程將共享這份空間而無需重新load, 這大大減少了應用程序的啟動時間,但反過來增加了系統的啟動時間。通過對preload 類和資源數目進行調整可以加快系統啟動。

static void preload(TimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");
        bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
        beginIcuCachePinning();
        bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
        bootTimingsTraceLog.traceBegin("PreloadClasses");
        preloadClasses();
        bootTimingsTraceLog.traceEnd(); // PreloadClasses
        bootTimingsTraceLog.traceBegin("PreloadResources");
        preloadResources();
        bootTimingsTraceLog.traceEnd(); // PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
        nativePreloadAppProcessHALs();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
        preloadOpenGL();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        preloadSharedLibraries();
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        endIcuCachePinning();
        warmUpJcaProviders();
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }

上面我們總結了ZygoteInit會先注冊一個五福段的Scoket,我們來看下具體是如何注冊的。

void registerServerSocket(String socketName) {
        if (mServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; //1
            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);
             
                mServerSocket = new LocalServerSocket(fd);//2
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

注釋1處的fullSocketName是該scoket的全名,在注釋2處new了一個LocalServerSocket實例並傳入文件描述符fd最后賦值給mServerSocket,它就是我們啟動的scoket。當Zygote進程將SystemServer進程啟動后, 就會在這個服務端的Socket上來等待ActivityManagerService請求Zygote進程來創建新的應用程序進程。

在創建完scoket之后便通過fork方式創建SystemServer進程,具體看main函數的注釋3。最后在注釋4處調用runSelectLoop函數。先看下注釋3處是如何創建SystemServer進程,具體是通過forkSystemServer方法

 private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
 
        /* Containers run without this capability, so avoid setting it in that case */
        if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
            capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
        }
        /* Hardcoded command line to start the system server
          */
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,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);//1//將啟動的參數解析成parsedArgs
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

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

        /* For child process
        */
        if (pid == 0) {//pid=0代表fork成功 並在子線程中啟動system server進程
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);//3啟動system server進程 system server在這個函數進行初始化

        }

        return null;
    }

首先是構造一個字符串數組來設置用戶和用戶組id然后在注釋1處將其解析成parsedArgs。在注釋2處通過fork創建SystemServer進程並傳入一些參數
啟動system server進程,進程的最終創建是通過native方法nativeForkSystemServer完成的。
最后在注釋3處啟動了system server進程。

接下來看下注釋4處的runSelectLoop作用 runSelectLoop函數如下所示

    Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
//mServerSocket 就是之前注冊的server scoket ,在這里得到它的fd並放到fd列表中
        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null);

        while (true) {
            //遍歷Fds列表把其中的信息放到pollFds 中
            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;
                }
//i=0表示服務端Socket與客戶端連接上,也就是當前Zygote進程與ActivityManagerService建立了連接
                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    //將ZygoteConnection的fd添加到fds列表中 以便接受AMS發送的創建應用的請求
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    //如果i>0表示有創建新應用進程的請求
                    try {
                        ZygoteConnection connection = peers.get(i);
                        //根據請求創建新的應用進程
                        final Runnable command = connection.processOneCommand(this);

                        if (mIsForkChild) {
                            // We're in the child. We should always have a command to run at this
                            // stage if processOneCommand hasn't called "exec".
                            if (command == null) {
                                throw new IllegalStateException("command == null");
                            }

                            return command;
                        } else {
                            // We're in the server - we should never have any commands to run.
                            if (command != null) {
                                throw new IllegalStateException("command != null");
                            }

                            // We don't know whether the remote side of the socket was closed or
                            // not until we attempt to read from it from processOneCommand. This shows up as
                            // a regular POLLIN event in our regular processing loop.
                            if (connection.isClosedByPeer()) {
                                connection.closeSocket();
                                peers.remove(i);
                                fds.remove(i);
                            }
                        }
                    } catch (Exception e) {
                        if (!mIsForkChild) {
                            // We're in the server so any exception here is one that has taken place
                            // pre-fork while processing commands or reading / writing from the
                            // control socket. Make a loud noise about any such exceptions so that
                            // we know exactly what failed and why.

                            Slog.e(TAG, "Exception executing zygote command: ", e);

                            // Make sure the socket is closed so that the other end knows immediately
                            // that something has gone wrong and doesn't time out waiting for a
                            // response.
                            ZygoteConnection conn = peers.remove(i);
                            conn.closeSocket();

                            fds.remove(i);
                        } else {
                            // We're in the child so any exception caught here has happened post
                            // fork and before we execute ActivityThread.main (or any other main()
                            // method). Log the details of the exception and bring down the process.
                            Log.e(TAG, "Caught post-fork exception in child process.", e);
                            throw e;
                        }
                    }
                }
            }
        }
    }

新進程的創建是通過processOneCommand完成的。下面貼下processOneCommand函數

 Runnable processOneCommand(ZygoteServer zygoteServer) {
 ...
   //創建應用進程
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
 ...

Zygote的forkAndSpecialize函數最終是通過native方法完成進程創建。

 int pid = nativeForkAndSpecialize(
                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                  fdsToIgnore, instructionSet, appDataDir);

好了,到此init和zygote進程的創建和啟動流程以及它過程中都做了哪些事我們都梳理了一遍。現在簡單總結下:
1、init進程

  • 創建一些文件夾並掛載設備
  • 初始化和啟動屬性服務
  • 解析init.rc配置文件並啟動zygote進程
    2、zygote進程
  • 創建VM
  • 創建並啟動system server進程

zygote啟動流程簡單總結:首先通過AndroidRunTime.start來啟動zygoteinit的main函數,在main函數中通過ZygoteServer注冊了scoket並通過runSelectLoop進行監聽AMS是否有啟動新進程的請求,如果有就通過native方法創建新進程。並且創建了systemserver進程。

system server進程的啟動

我們知道在zygote進程當中創建並啟動system server進程。那么接下來我們一起看下system server進程啟動過程都干了什么。

我們知道system server進程的啟動是通過handleSystemServerProcess該函數位於com.android.internal.os.ZygoteInit

 private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
 ...
 
        if (parsedArgs.invokeWith != null) {
            String[] args = parsedArgs.remainingArgs;
            // If we have a non-null system server class path, we'll have to duplicate the
            // existing arguments and append the classpath to it. ART will handle the classpath
            // correctly when we exec a new process.
            if (systemServerClasspath != null) {
                String[] amendedArgs = new String[args.length + 2];
                amendedArgs[0] = "-cp";
                amendedArgs[1] = systemServerClasspath;
                System.arraycopy(args, 0, amendedArgs, 2, args.length);
                args = amendedArgs;
            }

            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);

            throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);

                Thread.currentThread().setContextClassLoader(cl);
            }

            /*
             * Pass the remaining arguments to SystemServer.
             */
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);//1
        }
 }

可以看出最后調用ZygoteInit.zygoteInit

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();
        ZygoteInit.nativeZygoteInit(); //調用native方法對Zygote進行init
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); //1
    }

ZygoteInit.zygoteInit調用RuntimeInit.applicationInit

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
            ...
               nativeSetExitWithoutCleanup(true);

        // We want to be fairly aggressive about heap utilization, to avoid
        // holding on to a lot of memory that isn't needed.
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

        final Arguments args = new Arguments(argv);

        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        // Remaining arguments are passed to the start class's static main
        return findStaticMain(args.startClass, args.startArgs, classLoader);//1
    }

RuntimeInit.applicationInit又會調用findStaticMain方法

    private static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;

        try {
            cl = Class.forName(className, true, classLoader);//1
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }

        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });//2
        } 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();//3
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }

        /*
         * This throw gets caught in ZygoteInit.main(), which responds
         * by invoking the exception's run() method. This arrangement
         * clears up all the stack frames that were required in setting
         * up the process.
         */
        return new MethodAndArgsCaller(m, argv);
    }

注釋2處根據傳入的類名獲取Class對象,注釋2處則獲取該類的main方法。注釋3處獲取main方法的修飾判斷是否符合要求(必須是pubilc static)最終返回一個MethodAndArgsCaller對象。
它是RuntimeInit類的 一個靜態內部類並且實現了runnable接口。

 static class MethodAndArgsCaller implements Runnable {
        /** method to call */
        private final Method mMethod;

        /** argument array */
        private final String[] mArgs;

        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }
       
        public void run() {//1
            try {
                
                mMethod.invoke(null, new Object[] { mArgs });//2
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Error) {
                    throw (Error) cause;
                }
                throw new RuntimeException(ex);
            }
        }
    }

首先看下在它的run方法中的注釋2處執行了傳進來的main方法,這個其實就是SystemServer的main方法。那么還剩一個問題是它的run函數(注釋1)在哪里執行的呢? 你是否還記得ZygoteInit類的main函數中有如下調用

    public static void main(String argv[]) {
...
 if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);//創建SystemServer進程

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();//1
                    return;
                }
            }

我們看forkSystemServer返回了一個runnable對象然后如果它不為空就調用它的run方法。其實這個runnable就是一個MethodAndArgsCaller實例。由此我們就進入到了SystemServer類的main方法中。

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

該main方法非常簡單就是調用自身的run方法。

 private void run() {
        try {
        //手機時間早於1970 會重新設置為1970
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                Slog.w(TAG, "System clock is before 1970; setting to 1970.");
                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
            }
...
 // Prepare the main looper thread (this thread).
            android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            Looper.prepareMainLooper();//1准備主線程looper


            // Initialize native services. 
            System.loadLibrary("android_servers");//2初始化native相關服務

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

            // Initialize the system context. 
            createSystemContext();//3初始化系統context

            // Create the system service manager. 
            mSystemServiceManager = new SystemServiceManager(mSystemContext);//4創建system service manager
            mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // Prepare the thread pool for init tasks that can be parallelized
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();  // InitBeforeStartServices
        }

        // Start services.
        try {
            traceBeginAndSlog("StartServices");
            //5啟動各種服務
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }
        ...
        
        // Loop forever.
        Looper.loop();//6
        throw new RuntimeException("Main thread loop unexpectedly exited");

run方法信息量還是很大的,先看下注釋1處初始化主線程的looper,注釋2初始化了native相關服務,注釋3初始化system context,注釋4創建system service manager,注釋5則先后初始化了各種服務,注釋6調用了Looper.loop()。
注釋3處system context其實最終是返回contextimpl實例。注釋4處創建的SystemServiceManager主要是用在稍后初始化各種服務時用來啟動的服務的。

一個Service啟動需要的幾個步驟:
1. 初始化Service 對象,獲得IBinder對象。
2. 啟動后台線程,並進入Loop等待。
3. 將自己注冊到Service Manager, 讓其他進程通過名字可以獲得遠程調用必須的IBinder的對象。
注釋5處先后啟動了多種系統服務,這些服務分為3類:引導服務、系統服務、其他服務。毫無疑問,這么多服務之間是有依賴關系的,比如說,ActivityManager Service 在WindowManager Service 初始化完成之前是不能啟動應用的。那如何控制這些先后順序的?這里由System server的啟動線程通過SystemReady()接口來完成。每個系統服務必須實現一個SystemReady() 接口,當被調用,表明系統已經OK, 該服務可以訪問(直接或間接)其他服務的資源。 最后一個被調到的服務就是AcitivyManager Service. AM的SystemReady()。

系統的啟動方式有兩種:

  • 第一種是通過SystemServiceManager.startService啟動,下面以PowerManager啟動為例:
  private void startBootstrapServices() {
          mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
}
 public <T extends SystemService> T startService(Class<T> serviceClass) {
        try {
        try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);
            } catch (InstantiationException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service could not be instantiated", ex);
            } catch (IllegalAccessException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service must have a public constructor with a Context argument", ex);
            } catch (NoSuchMethodException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service must have a public constructor with a Context argument", ex);
            } catch (InvocationTargetException ex) {
                throw new RuntimeException("Failed to create service " + name
                        + ": service constructor threw an exception", ex);
            }

            startService(service);//1
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }

可以看出首先會用反射得到一個service實例然后調用同名startService方法

private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();

 public void startService(@NonNull final SystemService service) {
        // Register it.
        mServices.add(service);//1
        // Start it.
        long time = SystemClock.elapsedRealtime();
        try {
            service.onStart();//2
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        }
        warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
    }

startService首先會把當前的service添加到一個名為mServices的list中
之后便調用service.onStart()來啟動service。
以上就是通過SystemServiceManager.startService啟動系統服務的過程,總結來說就是通過反射來構造service然后再調用其onStart()來啟動。

  • 第二種啟動系統服務的方式是通過調用服務的main方法啟動即XXService.main(),以PackageManagerService為例來說明下
  mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);

調用了PackageManagerService的main函數

 public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // Self-check for initial settings.
        PackageManagerServiceCompilerMapping.checkProperties();

        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);//1
        m.enableSystemUserPackages();
        ServiceManager.addService("package", m);//2
        final PackageManagerNative pmn = m.new PackageManagerNative();
        ServiceManager.addService("package_native", pmn);
        return m;
    }

在注釋1處構造了一個 PackageManagerService實例,然后在注釋2處添加到ServiceManager啟動。
ServiceManager它是用來管理系統中各種Service的,由它管理的服務都實現了IBinder,所以在ServiceManager中注冊的服務是用於進程間通信的:用於系統C/S架構中的Binder通信機制。客戶端要使用某個Service,需要先到ServiceManager中查詢Service的信息,然后根據該信息與Service所在的Server進程建立通信,這樣客戶端就可以使用Service了。

至此SystemServer的啟動流程完成,我們來簡單總結下:
1、zygote會通過forkSystemServe來創建SystemServer進程。
2、之后通過handleSystemServerProcess來啟動SystemServer進程。
3、啟動過程是通過反射調用SystemServer的main函數。
4、SystemServer的main函數會調用run方法,在run方法中初始化了主線程的looper、系統的context等,之后啟動了引導、核心、其他等三類系統服務。

Launcher的啟動

SystemServer的startOtherServices()方法的最后調用了AMS的systemReady
這個調用會啟動launcher進程。
launcher通俗講就是我們開機看到的桌面,它向我們展示安裝完成的app的圖標。並且當我們按下對應的圖標時啟動相應的app。好了 我們看下launcher啟動入口。

    private void startOtherServices() {
    ...
      mActivityManagerService.systemReady(() -> {//1
            Slog.i(TAG, "Making services ready");
            traceBeginAndSlog("StartActivityManagerReadyPhase");
            mSystemServiceManager.startBootPhase(
                    SystemService.PHASE_ACTIVITY_MANAGER_READY);
            traceEnd();
            traceBeginAndSlog("StartObservingNativeCrashes");
            try {
                mActivityManagerService.startObservingNativeCrashes();
            } catch (Throwable e) {
                reportWtf("observing native crashes", e);
            }
            traceEnd();

           //...
        }, BOOT_TIMINGS_TRACE_LOG);
    }

在startOtherServices中注釋1處調用ActivityManagerService(AMS)的systemReady方法。

  public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
  ...
          startHomeActivityLocked(currentUserId, "systemReady");
  ...
  }

省略無關內容,我們看在systemReady調用startHomeActivityLocked方法。

 boolean startHomeActivityLocked(int userId, String reason) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            // We are running in factory test mode, but unable to find
            // the factory test app, so just sit around displaying the
            // error message and don't try to start anything.
            return false;
        }
        Intent intent = getHomeIntent();//1
        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
        if (aInfo != null) {
            intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
            // Don't do this if the home app is currently being
            // instrumented.
            aInfo = new ActivityInfo(aInfo);
            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
            ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid, true);
            if (app == null || app.instr == null) {
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
                // For ANR debugging to verify if the user activity is the one that actually
                // launched.
                final String myReason = reason + ":" + userId + ":" + resolvedUserId;
                mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);//2
            }
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }

        return true;
    }

startHomeActivityLocked方法中在注釋1處調用
getHomeIntent,該方法返回一個intent實例,該實例是啟動launcher的intent。該intent的action和Category是匹配launcher的manifest的。

   Intent getHomeIntent() {
        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);//mTopAction = Intent.ACTION_MAIN
        intent.setComponent(mTopComponent);
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            intent.addCategory(Intent.CATEGORY_HOME);//該intent的Category是Intent.CATEGORY_HOME
        }
        return intent;
    }

下面貼下manifest文件

    <application
        android:backupAgent="com.android.launcher3.LauncherBackupAgent"
        android:fullBackupOnly="true"
        android:fullBackupContent="@xml/backupscheme"
        android:hardwareAccelerated="true"
        android:icon="@drawable/ic_launcher_home"
        android:label="@string/derived_app_name"
        android:theme="@style/LauncherTheme"
        android:largeHeap="@bool/config_largeHeap"
        android:restoreAnyVersion="true"
        android:supportsRtl="true" >

        <!--
        Main launcher activity. When extending only change the name, and keep all the
        attributes and intent filters the same
        -->
        <activity
            android:name="com.android.launcher3.Launcher"
            android:launchMode="singleTask"
            android:clearTaskOnLaunch="true"
            android:stateNotNeeded="true"
            android:windowSoftInputMode="adjustPan"
            android:screenOrientation="nosensor"
            android:configChanges="keyboard|keyboardHidden|navigation"
            android:resizeableActivity="true"
            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"/>
                <category android:name="android.intent.category.LAUNCHER_APP" />
            </intent-filter>
        </activity>

看出launcher的action和category是和上面的intent相符合的。

startHomeActivityLocked方法中的注釋2調用了startHomeActivityLocked方法把獲得的intent傳入來啟動launcher。
launcher啟動完成后我們就在看到了桌面程序,上面顯示了安裝完成的app的圖標。

我們在此簡單總結下launcher的啟動流程:
1、首先systemserver在啟動其他系統服務時會調用AMS的systemReady方法
2、systemReady方法中調用startHomeActivityLocked,在這個方法中我們會構造出啟動launcher的intent,然后通過startHomeActivityLocked去啟動launcher。
systemserver啟動launcher后會執行launcher的onCreate函數

 protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        LauncherAppState app = LauncherAppState.getInstance(this);//1

        // Load configuration-specific DeviceProfile
        mDeviceProfile = app.getInvariantDeviceProfile().getDeviceProfile(this);
        
        if (isInMultiWindowModeCompat()) {//2
            Display display = getWindowManager().getDefaultDisplay();
            Point mwSize = new Point();
            display.getSize(mwSize);
            mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
        }
//3
        mOrientation = getResources().getConfiguration().orientation;
        mSharedPrefs = Utilities.getPrefs(this);
        mIsSafeModeEnabled = getPackageManager().isSafeMode();
        mModel = app.setLauncher(this);
        mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout());
        mIconCache = app.getIconCache();
        mAccessibilityDelegate = new LauncherAccessibilityDelegate(this);

        mDragController = new DragController(this);
        mAllAppsController = new AllAppsTransitionController(this);
        mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, mAllAppsController);

        mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);

        mAppWidgetHost = new LauncherAppWidgetHost(this);
        if (Utilities.ATLEAST_MARSHMALLOW) {
            mAppWidgetHost.addProviderChangeListener(this);
        }
        mAppWidgetHost.startListening();

        // If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,
        // this also ensures that any synchronous binding below doesn't re-trigger another
        // LauncherModel load.
        mPaused = false;

        mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);

        setupViews();//4
        
        mDeviceProfile.layout(this, false /* notifyListeners */);
        loadExtractedColorsAndColorItems();//5

        mPopupDataProvider = new PopupDataProvider(this);

        ((AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE))
                .addAccessibilityStateChangeListener(this);

        lockAllApps();

        restoreState(savedInstanceState);

        if (LauncherAppState.PROFILE_STARTUP) {
            Trace.endSection();
        }

        // We only load the page synchronously if the user rotates (or triggers a
        // configuration change) while launcher is in the foreground
        int currentScreen = PagedView.INVALID_RESTORE_PAGE;
        if (savedInstanceState != null) {
            currentScreen = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, currentScreen);
        }
        
        if (!mModel.startLoader(currentScreen)) {//6
            // If we are not binding synchronously, show a fade in animation when
            // the first page bind completes.
            mDragLayer.setAlpha(0);
        } else {
            // Pages bound synchronously.
            mWorkspace.setCurrentPage(currentScreen);

            setWorkspaceLoading(true);
        }

        // For handling default keys
        //7
        mDefaultKeySsb = new SpannableStringBuilder();
        Selection.setSelection(mDefaultKeySsb, 0);

        mRotationEnabled = getResources().getBoolean(R.bool.allow_rotation);
        // In case we are on a device with locked rotation, we should look at preferences to check
        // if the user has specifically allowed rotation.
        if (!mRotationEnabled) {
            mRotationEnabled = Utilities.isAllowRotationPrefEnabled(getApplicationContext());
            mRotationPrefChangeHandler = new RotationPrefChangeHandler();
            mSharedPrefs.registerOnSharedPreferenceChangeListener(mRotationPrefChangeHandler);
        }

        if (PinItemDragListener.handleDragRequest(this, getIntent())) {
            // Temporarily enable the rotation
            mRotationEnabled = true;
        }

        // On large interfaces, or on devices that a user has specifically enabled screen rotation,
        // we want the screen to auto-rotate based on the current orientation
        setOrientation();

        setContentView(mLauncherView);

        // Listen for broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_USER_PRESENT); // When the device wakes up + keyguard is gone
        registerReceiver(mReceiver, filter);
        mShouldFadeInScrim = true;

        getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
                Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));

        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.onCreate(savedInstanceState);
        }
    }

整個launcher的啟動大致分為7步。
注釋1處執行第一步創建LauncherAppState 對象。不同的手機顯示的Launcher布局是一樣的,但是其中真正顯示的每個圖標,
每個畫面的像素點大小是不同的。Launcher需要根據手機的尺寸密度等參數,計算出更多的信息。第一步是將和手機硬件掛鈎的參數都獲取出來。

注釋2處執行第二步,分屏模式也叫做多屏模式,在多屏模式的時候,Launcher的布局有很多的變化。此處檢查當前是否處於分屏模式,若是則會做相應的處理。

注釋3執行第三步統一創建對象,Launcher啟動時需要用到的對象,在這里統一創建,為后面進行布局的顯示進行鋪墊。

注釋4執行第四步生成桌面分布局,將桌面的各個部分都創建對象,綁定一些事件監聽器等,這一步基本將桌面的各個UI子模塊都定義完成。

注釋5執行第五步,UI子模塊的細節規划,各個模塊的大小,真正的尺寸等等。這一步是采用第一步獲取的方案,把第四步的模塊細節進行完成

注釋6執行第六步,生成布局。Launcher不是一張圖片,因為不同的手機之間有區別。前五步完成不同手機的區別, 保證上至平板,下至翻蓋機,不同的分辨率下都能夠很好的顯示。而手機桌面的變化重點是桌面圖標布局不一樣,手機中安裝的軟件不一樣。第六步就是生成這種布局。

注釋7第七步,橫屏和CallBack等善后工作

至此launcher啟動完成我們已經可以在桌面看到安裝的app的icon,點擊icon就會啟動相應的應用。

其實在launcher內部我們看到的圖標排列是通過Android自定義的recycleview實現的,當我們點擊icon時會觸發onclicklistener監聽,而對點擊事件的處理則是在launcher的onclick函數中(launcher實現了onclicklistener接口),launcher收到點擊事件后會調用startAppShortcutOrInfoActivity啟動對應的應用。

至此Android從啟動到桌面顯示,然后點擊icon啟動app的流程已經梳理完成。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM