【讀書筆記】Android 應用程序進程的啓動過程

這是羅昇陽《Android 系統源代碼》一書中第12章,Android 應用程序進程的啓動過程,的摘要;

 

當 ActivityMangerService 啓動一個應用程序組件時,如果發現這個組件所需要的進程沒有啓動,就會請求 Zygote  啓動新的進程。Zygote 通過複製自身的方式創建一個新的進程,同時也會獲取一個虛擬機實例;

應用程序進程啓動過程中,除了獲得一個虛擬機實例外,還獲得一個 Binder 線程池和一個消息循環。

 

一、應用程序進程創建的過程

當 ActivityManagerService 創建一個新的進程時,會調用 ActivityManagerService.startProcessLocked 方法向 Zygote 發送一個創建進程請求;

 

Zygote.forkAndSpecialize(...) 通過調用native 方法 nativeForkAndSpecialize(...) ,fork 一個新的進程;

ZygoteConnection.handleChildProc(...) 啓動新的進程;

 

 

二、消息循環的創建過程

一個新的應用進程創建完成之後,就會調用 RuntimeInit 類的靜態成員函數 invokeStaticMain 將 ActivityThread 類的靜態成員函數 main 設置爲新創建的應用程序進程入口。 ActivityThread 類的靜態成員函數 main 在調用的過程中,就會在當前應用程序進程中創建一個消息循環。

 

 

 

 

RuntimeInit.invokeStaticMain 方法

static void invokeStaticMain(ClassLoader loader, String className, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl;

        try {
            cl = loader.loadClass(className);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException("Missing class when invoking static main " + className, ex);
        }

        Method m;
        try {
            // 通過反射進入獲取ActivityThread 類的 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);
        }

        /*
         * 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.
         */
        // 拋出 caller 異常,在 ZygoteInit 的 main 方法裏捕獲
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }

 

在 ZygoteInit.main 方法中捕獲 caller 異常

public static void main(String argv[]) {
        ·····
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
           ···
        }
    }

 

調用 MethodAndArgsCaller.run 方法

public static class MethodAndArgsCaller extends Exception 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() {
        try {
            // 調用 ActivityThread 類的 main 方法
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        } catch (InvocationTargetException ex) {
          ···
        }
    }
}

 

ActivityThread.main 方法裏面開啓消息循環

  public static void main(String[] args) {
       ···
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

       ··

        Looper.loop();
        ···
    }

 

使用拋出異常的方式進入 ActivityThread 的 main 方法的原因:

ActivityMangerService 請求 Zygote 進程創建的應用程序的入口函數爲 ActivityThread 類的 main 函數。但是由於新創建的應用程序

進程一開始就需要在內部初始化運行時庫,以及啓動 Binder 線程池,因此,當 ActivityThread 類的靜態成員函數 main 被調用時,新

創建的應用程序進程實際上已經執行了相當多的代碼。爲了使得新創建的應用程序進程覺得它的入口函數就是 ActivityThread 類的 main

,系統就不可以在 ZygoteInit.invokeStaticMain 中直接調用。而是先拋出一個異常回到 ZygoteInit 類的 main 中,然後間接調用它,這樣

巧妙利用 Java 語言的異常處理機制清理它前面的調用棧。

 

 

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