Zygote、System進(jìn)程的啟動(dòng)——基于API28

概述

Zygote,翻譯為中文是“受精卵”,它是Android系統(tǒng)中,所有Java進(jìn)程的父進(jìn)程,負(fù)責(zé)創(chuàng)建新進(jìn)程。System進(jìn)程,是Android系統(tǒng)中系統(tǒng)服務(wù)運(yùn)行所在的進(jìn)程,它負(fù)責(zé)創(chuàng)建、管理所有的系統(tǒng)服務(wù),包括AMS、PackageManagerServer等等十分重要的服務(wù),都運(yùn)行在System進(jìn)程中。

Zygote和System進(jìn)程的生命周期伴隨整個(gè)系統(tǒng),在系統(tǒng)啟動(dòng)時(shí)就會(huì)啟動(dòng)這兩個(gè)進(jìn)程,而直到系統(tǒng)關(guān)閉,它們才會(huì)被殺死。

值得一提的是,在Android5.0之后,Zygote進(jìn)程在系統(tǒng)中一共存在兩個(gè),這主要是為了適應(yīng)新增加的64位app而設(shè)計(jì)的,它們兩個(gè)的主要功能其實(shí)是一致的。

And,System進(jìn)程其實(shí)也是Zygote進(jìn)程的子進(jìn)程,它們啟動(dòng)的順序大概可以描述為,Linux系統(tǒng)的初始化進(jìn)程<init>通過讀取腳本,創(chuàng)建Zygote,Zygote創(chuàng)建完成之后,先啟動(dòng)了System進(jìn)程,然后自己再等待其他創(chuàng)建請求。

本文以API28的源碼為基礎(chǔ)進(jìn)行分析。


Zygote啟動(dòng)過程

總述

  1. init進(jìn)程加載腳本,啟動(dòng)app_process文件中的main函數(shù)
  1. 創(chuàng)建虛擬機(jī)實(shí)例,進(jìn)入ZygoteInit類的main方法中
  1. 創(chuàng)建一個(gè)Socket
  1. fork出System進(jìn)程
  1. 自己進(jìn)入死循環(huán)中,不斷從第3步創(chuàng)建的Socket中獲取是否有創(chuàng)建進(jìn)程的請求,并進(jìn)行處理。

Step1: app_main.main

frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    ...
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ...
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;
    
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            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);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    }
    ...
}

走這個(gè)方法的目的是解析啟動(dòng)腳本中傳進(jìn)來的參數(shù)并真正調(diào)用方法啟動(dòng)進(jìn)程。

  1. 創(chuàng)建一個(gè)AppRuntime對象,是AndroidRuntime的子類,它的定義就在app_main文件中。
  1. 做一些解析工作,解析從啟動(dòng)腳本傳過來的參數(shù),這里要啟動(dòng)的是zygote進(jìn)程,所以zygote變量為true。
  1. 調(diào)用runtime的start方法,runtime就是第一步創(chuàng)建的AppRuntime對象,但是它沒有重寫start方法,start方法是在它的父類AndroidRuntime中的。注意:傳入的參數(shù)是ZygoteInit類的全名以及要傳給這個(gè)類的參數(shù),以及最后一個(gè)判斷啟動(dòng)的是否是zygote進(jìn)程的bool值。

Step2: AndroidRuntime.start

frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    ...
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    。。。
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    ...
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    ...
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
    ...
    env->CallStaticVoidMethod(startClass, startMeth, strArray);
    ...
}

走這個(gè)方法的目的是從c++的世界轉(zhuǎn)入Java的世界。

  1. 初始化JNI
  1. 創(chuàng)建并開啟一個(gè)虛擬機(jī)實(shí)例
  1. 給這個(gè)虛擬機(jī)注冊JNI方法
  1. 各種解析之后,調(diào)用env->CallStaticVoidMethod方法,從而調(diào)起Java的方法,傳入的三個(gè)參數(shù)分別是要調(diào)用的Java類、要調(diào)用的方法、傳給方法的參數(shù),這里要調(diào)用的Java類正是從上一步傳進(jìn)來ZygoteInit類的全稱解析出來的,而startMeth參數(shù)是main方法,所以這里調(diào)用起來的是ZygoteInit的main方法。
**宣布進(jìn)入Java的世界!**

Step3: ZygoteInit.main

public static void main(String argv[]) {
    ZygoteServer zygoteServer = new 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.registerServerSocketFromEnv(socketName);
    ...
    if (startSystemServer) {
        Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
        // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
        // child (system_server) process.
        if (r != null) {
            r.run();
            return;
        }
    }
    ...
    caller = zygoteServer.runSelectLoop(abiList);
    ...
    if (caller != null) {
        caller.run();
    }
}
  1. 創(chuàng)建ZygoteServer,然后做各種標(biāo)記位的判斷,比如startSystemServer判斷是否要啟動(dòng)System進(jìn)程,這里為true。
  1. 調(diào)用zygoteServer.registerServerSocketFromEnv (詳見Step3.1),創(chuàng)建一個(gè)Server端Socket,用來等待AMS請求,以創(chuàng)建應(yīng)用程序進(jìn)程。但這時(shí)候只是創(chuàng)建,還沒開始等待。
  1. forkSystemServer (詳見Step3.2) 創(chuàng)建一個(gè)新的子進(jìn)程,這個(gè)新的子進(jìn)程就是System進(jìn)程,這里討論的是Zygote的創(chuàng)建,這個(gè)方法會(huì)返回null,具體原因見Step3.2
  1. 調(diào)用runSelectLoop方法,在這個(gè)方法中無限等待請求。

Step3.1: ZygoteServer.registerServerSocketFromEnv

void registerServerSocketFromEnv(String socketName) {
    if (mServerSocket == null) {
        int fileDesc;
        ...
        String env = System.getenv(fullSocketName);
        fileDesc = Integer.parseInt(env);
        ...
        FileDescriptor fd = new FileDescriptor();
        ...
        mServerSocket = new LocalServerSocket(fd);
        ...
    }
}

這是Step3的第2步,創(chuàng)建并注冊Socket。

通過socket的名字創(chuàng)建文件操作符,然后再通過文件操作符創(chuàng)建一個(gè)socket,其實(shí)這個(gè)socket在操作系統(tǒng)中的表現(xiàn)形式就是一個(gè)文件(這是關(guān)于Linux系統(tǒng)的知識(shí),這里不詳述)這個(gè)socket就存在成員變量mServerSocket中。

Step3.2: ZygoteInit.forkSystemServer

private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        ...
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
            "com.android.server.SystemServer",
        };
        ...
        pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.runtimeFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
                    
        ...
        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }
        return null;
}

這是Step3的第2步,它的目的是創(chuàng)建System進(jìn)程

  1. 首先是置頂了一些參數(shù),這些參數(shù)主要是針對即將創(chuàng)建的子進(jìn)程,即System進(jìn)程的,可以看到這里為System進(jìn)程設(shè)定了其UID、GID等等信息,而且指定了它的執(zhí)行類是com.android.server.SystemServer。
  1. 調(diào)用Zygote.forkSystemServer方法,這個(gè)方法會(huì)調(diào)用操作系統(tǒng)提供的fork方法,fork方法是Linux系統(tǒng)中創(chuàng)建一個(gè)新進(jìn)程的方式,是一個(gè)非常特殊的方法,父進(jìn)程執(zhí)行fork方法之后,會(huì)出現(xiàn)兩個(gè)幾乎完全一樣的進(jìn)程,即原先的父進(jìn)程和新建的子進(jìn)程,同時(shí)返回fork方法,而且繼續(xù)執(zhí)行的代碼是一致的,但是不同的是,fork的返回值不相同。在父進(jìn)程中,會(huì)返回子進(jìn)程的pid(ProcessID),而子進(jìn)程中會(huì)返回0。
  1. 然后看接下來的代碼,if語句判斷pid是否為0,所以if語句塊中的代碼是子進(jìn)程會(huì)執(zhí)行的,而對于父進(jìn)程,pid不為零,所以下面會(huì)返回null,這也就解釋了Step3中為什么是返回null。讀者看到這里可以重新返回去看看step3就會(huì)明白。(這種寫法是非常典型的fork子進(jìn)程之后的寫法)
  1. 這里重新理一理Step3最后的步驟,在父進(jìn)程,也就是Zygote進(jìn)程中,forkSystemServer方法返回了null,于是會(huì)執(zhí)行runSelectLoop方法,而子進(jìn)程,也就是System進(jìn)程,返回的是一個(gè)runnable,是由forkSystemServer方法中調(diào)用的handleSystemServerProcess方法返回的,它嵌套返回到main方法中后,會(huì)執(zhí)行run方法,然后main方法就返回掉了,因?yàn)檫@是System進(jìn)程了。

Step3.3: ZygoteServer.runSelectLoop

Runnable runSelectLoop(String abiList) {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
  
    fds.add(mServerSocket.getFileDescriptor());
    ...
    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;
        }
        ...
        Os.poll(pollFds, -1);
        ...
        for (int i = pollFds.length - 1; i >= 0; --i) {
            if ((pollFds[i].revents & POLLIN) == 0) {
                continue;
            }

            if (i == 0) {
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                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);
                        }
                    }
                }
                ...
            }
        }
    }
}

前面說到這里是Zygote進(jìn)程死循環(huán)等待的地方,是Zygote進(jìn)程fork出System進(jìn)程之后,自己等待別的請求的地方。

  1. 首先聲明了兩個(gè)數(shù)組,一個(gè)是文件描述符數(shù)組,第一個(gè)元素放的就是mServerSocket。另一個(gè)數(shù)組是ZygoteConnection數(shù)組,從類名就能猜出(當(dāng)然事實(shí)也確實(shí)是這樣滴)這個(gè)類描述的是一個(gè)和Zygote進(jìn)程的連接,也就是說當(dāng)Zygote接收到請求之后,會(huì)將它封裝成一個(gè)ZygoteConnection對象。
  1. 開個(gè)死循環(huán),調(diào)用方法Os.poll,處理輪詢狀態(tài)。poll也是Linux提供的系統(tǒng)調(diào)用,用于獲知指定的Socket是否有事件到達(dá)。可以看到這里創(chuàng)建了一個(gè)StructPollfd數(shù)組,StructPollfd類是專門與Poll調(diào)用配合的一個(gè)類,用來描述poll調(diào)用的目的和結(jié)果,它既包含了一個(gè)描述poll監(jiān)聽目的的成員變量,也包含了一個(gè)描述已發(fā)生事件的成員變量。Poll調(diào)用根據(jù)傳入的StructPollfd,指定監(jiān)聽的socket,指定監(jiān)聽的事件類型,如果沒有事件到達(dá),會(huì)阻塞在poll方法中,如果有事件到達(dá),則將發(fā)生的事件寫入StructPollfd對象中,然后返回。
  1. 可以看到,一開始裝入的pollfdmServerSocket,然后進(jìn)入poll調(diào)用,一旦有事件到達(dá),poll方法將跳出,進(jìn)入下面的for循環(huán),這時(shí)如果i=0,就是AMS請求與Zygote連接(注意這里并非請求創(chuàng)建進(jìn)程),AMS一般在第一次請求創(chuàng)建進(jìn)程時(shí)會(huì)先請求連接,之后如果沒有關(guān)閉這個(gè)鏈接,則再請求創(chuàng)建之時(shí)不用請求連接。Zygote接收到連接請求,則將請求包裝后,放入peers中,然后又回到Poll了。注意這里的連接,即ZygoteConnection對象,描述的是和AMS的連接,并不會(huì)包括AMS請求創(chuàng)建進(jìn)程所傳遞的任何參數(shù)。
  1. 等到AMS再次請求創(chuàng)建時(shí),取出peers中對應(yīng)的連接,處理、調(diào)用processOneCommand方法。這個(gè)地方Poll的作用就是在于監(jiān)聽到socket有數(shù)據(jù)傳入了,這些數(shù)據(jù)才是AMS請求創(chuàng)建進(jìn)程所傳遞的數(shù)據(jù),而讀出這些數(shù)據(jù)的地方就在processOneCommand方法中。
  1. 往下又是一個(gè)非常典型的fork之后的寫法,如果是子進(jìn)程,就把processOneCommand的結(jié)果,即一個(gè)Runnable返回出去,在前面提到的ZygoteInit的main方法中會(huì)調(diào)用它run。父進(jìn)程會(huì)判斷是否和AMS已經(jīng)斷開了,通過方法connection.isClosedByPeer()判斷的。如果已經(jīng)斷開,則把連接刪除掉,如果沒有斷開,就繼續(xù)在poll等待AMS請求創(chuàng)建進(jìn)程。

Step3.4:ZygoteConnection.processOneCommand

Runnable processOneCommand(ZygoteServer zygoteServer) {
    ...
    //從socket中讀出要?jiǎng)?chuàng)建的進(jìn)程的參數(shù)
    args = readArgumentList();
    ...
    parsedArgs = new Arguments(args);
    ...
    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal,parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote, parsedArgs.instructionSet, parsedArgs.appDataDir);
    ...
    if (pid == 0) {
        // 子進(jìn)程
            zygoteServer.setForkChild();
        // 子進(jìn)程中要關(guān)掉ServerSocket
        zygoteServer.closeServerSocket();
        ...
        return handleChildProc(parsedArgs, descriptors, childPipeFd, parsedArgs.startChildZygote);
        } else {
            // 父進(jìn)程,即Zygote
            handleParentProc(pid, descriptors, serverPipeFd);
            return null;
        }
        ...
}

這個(gè)方法要處理創(chuàng)建進(jìn)程的請求,在這里會(huì)fork出子進(jìn)程了。

  1. 調(diào)用readArgumentList方法,從mServerSocket中讀出AMS放進(jìn)去的請求參數(shù),并封裝一下
  1. 調(diào)用Zygote.forkAndSpecialize方法fork出子進(jìn)程
  1. 父進(jìn)程和子進(jìn)程分開處理。這個(gè)地方涉及到的主要是應(yīng)用程序進(jìn)程的啟動(dòng)過程,這里不詳述。

到這里Zygote就啟動(dòng)完成啦,在死循環(huán)里面等著。


System啟動(dòng)

Step1: ZygoteInit.handleSystemServerProcess

private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
    ...
    if (parsedArgs.invokeWith != null) {
        ...
    } 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. 這個(gè)方法在ZygoteInit里調(diào)用的,前面有說到。而且它的調(diào)用順序是在Zygote的死循環(huán)開始之前的。
  1. 它的參數(shù)是前面設(shè)置好的一個(gè)參數(shù),而且是指向子進(jìn)程的,也就是system進(jìn)程。其中invokeWith是沒有設(shè)置的,應(yīng)該是為了檢測進(jìn)程內(nèi)存泄露等等Debug用途時(shí)才會(huì)有值,這一點(diǎn)如果有大大知道,望指點(diǎn)一二。
  1. 接下來調(diào)用ZygoteInit.zygoteInit

Step2: ZygoteInit.zygoteInit

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
    ...
    ZygoteInit.nativeZygoteInit();
    return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    ...
}
  1. nativeZygoteInit在System進(jìn)程中啟動(dòng)了一個(gè)Binder線程池。這里不詳述,關(guān)于Binder的知識(shí)后面會(huì)寫文章。
  1. 調(diào)用了RuntimeInit.applicationInit

Step3: RuntimeInit.applicationInit

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        ...
        return findStaticMain(args.startClass, args.startArgs, classLoader);
}

繼續(xù)調(diào)用findStaticMain


Step4: RuntimeInit.findStaticMain

protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
    Class<?> cl;
    ...
    cl = Class.forName(className, true, classLoader);
    ...
    Method m;
    ...
    m = cl.getMethod("main", new Class[] { String[].class });
    ...
    return new MethodAndArgsCaller(m, argv);
}

這里調(diào)用了className指向的類的main方法,也就是SystemServer類的main方法。包裝了一下返回了一個(gè)MethodAndArgsCaller對象,這個(gè)類實(shí)現(xiàn)了Runnable接口,于是這個(gè)對象會(huì)一直返回一直返回到ZygoteInit方法中。

值得注意的是,這里返回到ZygoteInit.main方法中的進(jìn)程,不是前面的Zygote進(jìn)程,而是System進(jìn)程,是由Zygote進(jìn)程fork出來的。我們重新看看main方法中的那一段代碼。

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

返回出來的對象就是r,然后調(diào)用了r的run方法,然后把ZygoteInit的main方法返回掉,于是接下來就是SystemServer.main


SystemServer.main

new SystemServer().run();

就調(diào)用了這么個(gè)方法


SystemServer.run

private void run() {
    try {
        ...
        String timezoneProperty =  SystemProperties.get("persist.sys.timezone");
        if (timezoneProperty == null || timezoneProperty.isEmpty()) {
            Slog.w(TAG, "Timezone not set; setting to GMT.");
            SystemProperties.set("persist.sys.timezone", "GMT");
        }
        ...
        if (!SystemProperties.get("persist.sys.language").isEmpty()) {
            final String languageTag = Locale.getDefault().toLanguageTag();
            SystemProperties.set("persist.sys.locale", languageTag);
            SystemProperties.set("persist.sys.language", "");
            SystemProperties.set("persist.sys.country", "");
            SystemProperties.set("persist.sys.localevar", "");
        }
        ...
        Looper.prepareMainLooper();
        ...
        // Initialize the system context.
        createSystemContext();
        // Create the system service manager.
        mSystemServiceManager = new SystemServiceManager(mSystemContext
        ...
        SystemServerInitThreadPool.get();
        );
        } finally {
            traceEnd();  // InitBeforeStartServices
        }
    ...
    // Start services.
    startBootstrapServices();
    startCoreServices();
    startOtherServices();
    ...
    // Loop forever.
    Looper.loop();
}

這里是真正運(yùn)行System進(jìn)程要初始化的工作的地方!!!

  1. 先設(shè)置了一些時(shí)區(qū)、語言等等
  1. 創(chuàng)建了一個(gè)消息循環(huán)Looper
  1. 創(chuàng)建系統(tǒng)上下文、創(chuàng)建SystemServiceManager,創(chuàng)建一個(gè)線程池用來維護(hù)系統(tǒng)服務(wù)。
  1. 調(diào)用各個(gè)方法啟動(dòng)各種系統(tǒng)服務(wù),關(guān)于系統(tǒng)服務(wù)。
    • startBootstrapServices:這里啟動(dòng)一些依賴性比較強(qiáng)的服務(wù)。如安裝器、設(shè)備標(biāo)識(shí)服務(wù)、AMS、PackageManagerServices、UserManagerService、電池管理服務(wù)、Recovery服務(wù)、亮度服務(wù)、傳感器等等等等。

    • startCoreServices:這里啟動(dòng)了UsageStatsService(用戶使用情況服務(wù))、WebViewUpdate服務(wù)

    • startOtherServices:一些雜七雜八的服務(wù),比如鬧鐘、藍(lán)牙、網(wǎng)絡(luò)(包括wifi)、媒體、存儲(chǔ)等等甚至是statusBar也是單開一個(gè)服務(wù)的,還有一個(gè)重要的是WindowymanagerServices,他在這里的原因是它要等到傳感器都初始化好之后,它才能啟動(dòng),這里順便一提,還給AMS設(shè)置了一個(gè)回調(diào)systemReady,告訴AMS可以運(yùn)行非系統(tǒng)的代碼了。以及NotificationManager也是在這里創(chuàng)建的。

  1. 啟動(dòng)Looper

到這里System進(jìn)程就啟動(dòng)完成啦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,667評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內(nèi)容