Android 內核 - 04 Framework 的啓動

從Linux的角度看,Android只是Linux中的一個應用程序而已。
啓動Android便是啓動一系列的服務和應用模塊。從這個角度去理解Android的啓動過程會使問題變得簡單點。

先啓動一個原始進程,加載必要的資源,建立原型,並開啓socket等待命令(進程間通信的一種手段)

當原始進程收到命令時,把原始進程的資源信息複製一份,fork一個子進程以節省啓動時間。


pic_1


系統中先創建的進程是Zygote,其他的進程便可以由它進行復制而來。
SystemServer比較特殊,雖然它也是有Zygote孵化而來,但它會負責系統管理的職責,所以單獨羅列出來。


Zygote 啓動 Step 1

從 app_process 進入ZygoteInit 中

App_main.cpp  在文件夾  frameworks\base\cmds\app_process 中。
AndroidRuntime.cpp  在文件夾 frameworks\base\core\jni 中。

App_main.cpp main函數中會通過參數判斷要創建對象的類型,是zygote還是普通application,然後將目標類的名稱傳遞給AndroidRuntime。
由Runtime負責後續工作。

pic_2


zygote 創建的參數定義在 init.rc中, 如下:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd


Zygote 啓動 Step 2 ZygoteInit的工作

描述一下 ZygoteInte 的工作大致有以下幾個方面

  • 建立/註冊 socket
  • 加載資源
  • start SystemServer
  • 進入線程循環狀態

pic_2


1) 函數registerZygoteSocket 建立Socket
    
     /**
     * Registers a server socket for zygote command connections
     *
     * @throws RuntimeException when open fails
     */
    private static void registerZygoteSocket() {} 的核心是調用 sServerSocket 
                    = new LocalServerSocket(createFileDescriptor(fileDesc)); 建立socket 連接

LocalServerSocket 的構造函數就是建立一個socket的過程,包括bind 和listen。

    /**
     * Crewates a new server socket listening at specified name.
     * On the Android platform, the name is created in the Linux
     * abstract namespace (instead of on the filesystem).
     * 
     * @param name address for socket
     * @throws IOException
     */
    public LocalServerSocket(String name) throws IOException
    {
        impl = new LocalSocketImpl();

        impl.create(LocalSocket.SOCKET_STREAM);

        localAddress = new LocalSocketAddress(name);
        impl.bind(localAddress);

        impl.listen(LISTEN_BACKLOG);
    }

 連接建立完成後,使用這個連接主要是在第4步


2)預先加載資源 preload()

preload() 函數中主要調用了3個函數         

preloadClasses();       Performs Zygote process initialization. Loads and initializes commonly used classes.
                                   它的核心是Class.forName(name); 用來創建類的實例

preloadResources();  Load in commonly used resources, so they can be shared across processes.


preloadOpenGL();     EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY)


3)startSystemServer() 創建system_service進程

函數中使用fork方式創建一個新的進程system_service,它的參數定義在了函數中
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
            "--capabilities=" + capabilities + "," + capabilities,
            "--runtime-init",
            "--nice-name=system_server",           // 進程名稱
            "com.android.server.SystemServer",  // 進程的工作實體
        };

        pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);

SystemServer文件保存在 framework\base\services\java\com\android\server中。

這裏只保存關於啓動過程的信息,關於SystemServe的相系信息整理在:

4)runSelectLoop() 線程進入循環狀態

     * Runs the zygote process's select loop. Accepts new connections as they happen,
     * and reads commands from connections one spawn-request's worth at a time.

zygote process正式開始工作了,爲新的連接做準備,從新的連接讀取命令並處理。

runSelectLoop的工作源碼:

        while (true) {
            int index;

            /*
             * Call gc() before we block in select().
             * It's work that has to be done anyway, and it's better
             * to avoid making every child do it.  It will also
             * madvise() any free memory as a side-effect.
             *
             * Don't call it every time, because walking the entire
             * heap is a lot of overhead to free a few hundred bytes.
             */
            if (loopCount <= 0) {
                gc();
                loopCount = GC_LOOP_COUNT;
            } else {
                loopCount--;
            }

            try {
                fdArray = fds.toArray(fdArray);
                index = selectReadable(fdArray);
            } catch (IOException ex) {
                throw new RuntimeException("Error in select()", ex);
            }

            if (index < 0) {
                throw new RuntimeException("Error in select()");
            } else if (index == 0) {
                ZygoteConnection newPeer = acceptCommandPeer();
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                boolean done;
                done = peers.get(index).runOnce();

                if (done) {
                    peers.remove(index);
                    fds.remove(index);
                }
            }
        }
    }

源碼中特意強調了gc()要在select 阻塞之前做,並且避免每個子任務單獨的去做GC。

index = selectReadable(fdArray); 作爲和子任務通信的接口,用select方式去讀取來自socket connect的數據。

如果index == 0,表明是一個新的連接,加入peers的列表
如果index > 0,  表明有數據過來了,需要peers列表中的對象進行處理。


ZygoteConnection的runOnce()

     * Reads one start command from the command socket. If successful,
     * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
     * exception is thrown in that child while in the parent process,
     * the method returns normally. On failure, the child is not
     * spawned and messages are printed to the log and stderr. Returns
     * a boolean status value indicating whether an end-of-file on the command
     * socket has been encountered.

從socket 中讀取args
args = readArgumentList();

分析 args 得到 Arguments

創建子進程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName);



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章