Android 8.0 原始碼分析 (三) 應用程式程式建立到應用程式啟動的過程

DevYK發表於2019-10-27

前言

我們熟知一般 Android 工程師都是在應用層上開發,不會涉及系統原始碼,但是如果你想往底層發展,或者深入外掛化、Framework 系統層等開發工作,如果不瞭解 Android 原始碼可是不行的,那麼接下來我基於自己的理解跟學習來記錄跟 Android 開發息息相關的原始碼分析,大概從 Android 中的 SystemServer 啟動、四大元件啟動、AMS、PMS 等幾個維度來介紹,下面是我的計劃,當然在未來也有可能改變。

還沒有關注的小夥伴,可以先關注一波,系列文章會持續更新。

Android 8.0 原始碼分析 (一) SystemServer 程式啟動

Android 8.0 原始碼分析 (二) Launcher 啟動

Android 8.0 原始碼分析 (三) 應用程式程式建立到應用程式啟動的過程

Android 8.0 原始碼分析 (四) Activity 啟動

Android 8.0 原始碼分析 (五) Service 啟動

Android 8.0 原始碼分析 (六) BroadcastReceiver 啟動

Android 8.0 原始碼分析 (七) ContentProvider 啟動

Android 8.0 原始碼分析 (八) ActivityManagerService

Android 8.0 原始碼分析 (九) WindowManager

Android 8.0 原始碼分析 (十) WindowManagerService 的視窗管理

介紹

前面 2 篇我們學習了 Android 的系統服務程式啟動和桌面 Launcher 的啟動,那麼基於前面學的內容,這一篇將帶來應用程式程式的啟動過程分析,如果對 Zygote、SystemServer、Launcher 啟動原理還不瞭解的建議先看下我前面文章。

應用程式程式簡介

想要啟動一個應用程式,首先要保證這個應用程式所需要的應用程式程式已經啟動。 AMS 在啟動應用程式時會檢查這個應用程式需要的應用程式程式是否存在,不存在就會請求 Zygote 程式啟動需要的應用程式程式。在 Android 8.0 原始碼分析 (一) SystemServer 程式啟動 中我們知道在 Zygote 的 Java 框架層中會建立一個 Server 端的 Socket , 這個 Socket 就是用來等待 AMS 請求 Zygote 建立新的應用程式程式。Zygote 程式通過 fock 自身建立的應用程式程式,這樣應用程式就會獲得 Zygote 程式在啟動時建立的虛擬機器例項。當然,在應用程式程式建立過程中除了獲取虛擬機器例項外,還建立了 Bindler 執行緒池和訊息迴圈,這樣執行在應用程式中的應用程式就可以方便的使用 Binder 進行程式間通訊以及處理訊息了。

應用程式程式啟動過程介紹

應用程式程式建立過程的步驟比較多,這裡分為兩個部分來講解,分別是 AMS 傳送啟動應用程式程式請求,以及 Zygote 接收請求並建立應用程式程式。

AMS 傳送啟動應用程式程式請求

先來看一下 AMS 傳送啟動應用程式程式請求過程的時序圖,然後對每一個步驟進行詳細分析。

KykGXn.png

AMS 如果想要啟動應用程式程式,就需要向 Zygote 程式傳送建立應用程式程式的請求, AMS 會通過呼叫 startProcessLocked 函式向 Zygote 程式傳送請求,如下所示:

//com.android.server.am; ActivityManagerService.java

    /**
     * 啟動程式的函式
     * @param app
     * @param hostingType
     * @param hostingNameStr
     * @param abiOverride
     * @param entryPoint
     * @param entryPointArgs
     */
    private final void startProcessLocked(
            ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride,
            String entryPoint, String[] entryPointArgs){
      
        ...
          
        try {
            try {
                final int userId = UserHandle.getUserId(app.uid);
                AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }

            /**
             * 1. 獲取要建立的應用程式程式的 使用者 id 
             */
            int uid = app.uid;
            int[] gids = null;
            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
            if (!app.isolated) {
              ...

                /**
                 * 2. 對 gids 進行建立和賦值
                 */
                if (ArrayUtils.isEmpty(permGids)) {
                    gids = new int[3];
                } else {
                    gids = new int[permGids.length + 3];
                    System.arraycopy(permGids, 0, gids, 3, permGids.length);
                }
                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
                gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
            }
           ...
            boolean isActivityProcess = (entryPoint == null);
            /**
             * 3. 如果 entryPoint == null 那麼將 ActivityThread 全類名賦值給 entryPoint
             */
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkTime(startTime, "startProcess: asking zygote to start proc");
            ProcessStartResult startResult;
            if (hostingType.equals("webview_service")) {
                startResult = startWebView(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, entryPointArgs);
            } else {

                /**
                 * 4. 在 AMS 中呼叫 start 函式進行通知 Zygote fork 程式
                  */
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, entryPointArgs);
            }
          ...
    }
複製程式碼

總結下上面程式碼意思,可分為 4 個步驟:

    1. 獲取建立應用程式程式的使用者 ID
    1. 對使用者組 ID(gids)進行建立和賦值
    1. 如果 entryPoint 為 null ,就把 ActivityThread 全類名賦值給它
    1. 呼叫 Process 的 start 函式

Process.start 的第一個函式就是 android.app.ActivityThread ,後面小節會用到它,它就是關鍵所在,好了下面我們看下 Process 的 start 函式:

//android.os; Process.java

    public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String invokeWith,
                                  String[] zygoteArgs) {
      	//1. 通過 ZygoteProcess 呼叫 start 函式
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }

複製程式碼

在 Process.start 靜態函式中我們看到,又呼叫了 ZygoteProcess 的 start 函式,其實 ZygoteProcess 是用於與 Zygote 程式保持通訊的狀態,該 start 函式如下:

//android.os; ZygoteProcess.java

    public final Process.ProcessStartResult start(final String processClass,
                                                  final String niceName,
                                                  int uid, int gid, int[] gids,
                                                  int debugFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  String[] zygoteArgs) {
        try {
            /**
             * 繼續呼叫當前類的 startViaZygote 函式
             */
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }

    private Process.ProcessStartResult startViaZygote(final String processClass,
                                                      final String niceName,
                                                      final int uid, final int gid,
                                                      final int[] gids,
                                                      int debugFlags, int mountExternal,
                                                      int targetSdkVersion,
                                                      String seInfo,
                                                      String abi,
                                                      String instructionSet,
                                                      String appDataDir,
                                                      String invokeWith,
                                                      String[] extraArgs)
                                                      throws ZygoteStartFailedEx {

        //建立一個集合 將應用程式程式啟動引數儲存
        ArrayList<String> argsForZygote = new ArrayList<String>();

        // --runtime-args, --setuid=, --setgid=,
        // and --setgroups= must go first
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
       ...//省略部分程式碼

        synchronized(mLock) {
         //繼續呼叫內部函式
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }
複製程式碼

通過上面程式碼我們知道主要就是將應用程式程式啟動引數告訴 zygoteSendArgsAndGetResult 然後通過 Socket 傳遞給 zygote 程式,我們先來看 openZygoteSocketIfNeeded(abi) 實現

//android.os; ZygoteProcess.java
    @GuardedBy("mLock")
    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                /**
                 * 1. 連線 zygote 名稱為 "zygote" 服務端的 Socket ,建立程式間通訊
                 */
                primaryZygoteState = ZygoteState.connect(mSocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
        }

        /**
         * 2. 連線 Zygote 主模式返回的 ZygoteState 是否與啟動應用程式程式所需要的 ABI 匹配
         */
        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }

        // 如果不匹配,則嘗試連線 zygote 輔模式
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            try {
                /**
                 * 3. 如果不匹配那麼就嘗試連線 name 為 "zygote_secondary" 的 Socket
                 */
                secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            }
        }

        /**
         * 4. 連線 Zygote 輔模式返回的 ZygoteState 是否與啟動應用程式程式所需要的 ABI 匹配
         */
        if (secondaryZygoteState.matches(abi)) {
            return secondaryZygoteState;
        }

        //如果都不匹配那麼就拋一個異常
        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }
複製程式碼

通過上面的程式碼跟註釋我們知道就是與 zygote 程式通過 Socket 進行一個連線,連線成功之後會返回一個 ZygoteState,然後對傳遞進來的 abi 進行匹配,這裡連線和匹配 abi 涉及到 Zygote 的啟動指令碼,感興趣的可以查閱相關資料,通俗的來講就是如果 Zygote 程式採用的是 init.zygote32_64.rc 指令碼啟動,那麼它就是屬於主模式為 “name” 名稱的服務端 Socket, 如果採用的是 init.zygote64_32.rc 指令碼啟動,那麼它就是屬於輔模式為 “zygote_secondary” 名稱的服務端 Socket。最後如果都不匹配說明連線或者匹配異常了。如果連線成功之後我們看 zygoteSendArgsAndGetResult 函式主要做了些什麼工作:

//android.os; ZygoteProcess.java
    private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
       			...
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;

            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }

            writer.flush();

            ...
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }
複製程式碼

通過上面程式碼我們知道,如果與 zygote 程式的服務端 Socket 連線成功,那麼就將儲存起來的應用程式程式啟動引數寫入到 ZygoteState 中。最後就是 Zygote 程式接收後的處理工作了,下面一小節來詳細為大家介紹接收之後的工作。

Zygote 接收請求並建立應用程式程式

如果有看過 Android 8.0 原始碼分析 (一) SystemServer 程式啟動 該文章的一定清楚,其實 SystemServer 跟應用程式啟動在 Zygote 處理 的方式相似,這裡我們們為了複習一下之前的內容,我們就再來溫習一遍吧,先來看一個時序圖。

KymKkq.png

上面我們講了在溫習一下 ZygoteInit main 函式,那麼我們在看一下 服務端的 Socket 建立

//com.android.internal.os.ZygoteInit.java
    public static void main(String argv[]) {

	    ....

        try {
          
          ...
            //是否開啟 SystemServer 標記
            boolean startSystemServer = false;
          	//服務端 Socket 名稱
            String socketName = "zygote";

          	//根據 JNI 層傳遞過來的資訊,來判斷是否啟動系統服務
            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]);
                }
            }
          

            /**
             * 1. 建立服務端的 Socket ,名稱為 "zygote"
             */

            zygoteServer.registerServerSocket(socketName);
           
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                /**
                 *  2. 用來預載入資源
                 */
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }

            ...

            if (startSystemServer) {
                /**
                 * 3. 啟動 SystemServer 程式
                 *
                 */
                startSystemServer(abiList, socketName, zygoteServer);
            }

            Log.i(TAG, "Accepting command socket connections");
            /**
             * 4. 等待 AMS 請求
             */
            zygoteServer.runSelectLoop(abiList);
						//清理或者關閉對應的 Socket
            zygoteServer.closeServerSocket();
        } catch (Zygote.MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        }
    }

複製程式碼

在上面註釋 1 處通過 registerZygoteSocket 函式來建立一個名稱為 “name” 的服務端 Socket, 這個 Socket 是用於等待 AMS 發起建立新的應用程式程式的請求,關於 AMS 後面我會詳細講解。註釋 3 啟動服務程式,註釋 4 等待 AMS 的請求,我們直接看 註釋 4 的程式碼實現

//  com.android.internal.os ZygoteInit.main->runSelectLoop

    void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

        /**
         * 1. 新增獲得該 Socket 的 fd 欄位的值
         */
        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null);

        /**
         * 死迴圈等待 AMS 的請求
         */
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            /**
             * 2. 將 fds 資訊轉存到 pollFds 陣列中。
             */
            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);
            }

            /**
             * 3.對 pollFds 資訊進行遍歷
             */
            for (int i = pollFds.length - 1; i >= 0; --i) {

                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                //如果 i == 0 那麼就認為 服務端 Socket 與客戶端連線上了,就是與 AMS 建立了連線
                if (i == 0) {
                    /**
                     * 4.
                     */
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    //將 ZygoteConnection 新增到 Socket 連線列表中
                    peers.add(newPeer);
                    //將 ZygoteConnection 的檔案描述符 新增到 fds 列表中
                    fds.add(newPeer.getFileDesciptor());
                } else {//如果不等於 0 ,那麼就說明 AMS 向 Zygote 傳送了一個建立應用程式的請求
                    /**
                     * 5. 呼叫 ZygoteConnection 的 runOnce 函式來建立一個新的應用程式,並在成功建立後將這個連線從 Socket 連線列表中 peers、fd 列表中關閉
                     */
                    boolean done = peers.get(i).runOnce(this);
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

複製程式碼

通過上面註釋我們知道,如果 AMS 發來了一個新的請求任務,會走註釋 5 通過 peers.get(i).runOnce(this); 來處理請求資料,我們直接看 runOnce 函式具體實現:

//com.android.internal.os; ZygoteConnection.java
    boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {

        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;

        try {
            /**
             * 1. 獲取應用程式程式的啟動引數
             */
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        }
				...
        int pid = -1;
        FileDescriptor childPipeFd = null;
        FileDescriptor serverPipeFd = null;

        try {
            /**
             * 2. 將獲取到啟動應用程式程式的啟動引數 args 陣列 封裝到 Arguments 型別的 parsedArgs 物件中
             */
            parsedArgs = new Arguments(args);

           ...
            fd = null;

            /**
             * 3. 通過 Zygote 來建立應用程式程式
             */
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        } catch (ErrnoException ex) {
          ...
        }

        try {
            //當前程式碼邏輯執行在被建立出來的子程式中
            if (pid == 0) {
                // in child
                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                //4. 處理應用程式程式
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

                // should never get here, the child is expected to either
                // throw Zygote.MethodAndArgsCaller or exec().
                return true;
            } else {
                // in parent...pid of < 0 means failure
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }
複製程式碼

通過上面程式碼我們知道這裡 runOnce 首先獲取到啟動應用程式程式的引數,然後進行一個 Argument 的包裝,最後通過 Zygote.forkAndSpecialize 建立 AMS 傳遞過來啟動程式資訊,內部其實是 native 函式來進行建立。接下來我們看 註釋 4 處理建立完成的應用程式程式,如下程式碼:

//com.android.internal.os; ZygoteConnection.java    
		private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws Zygote.MethodAndArgsCaller {
        ...
        if (parsedArgs.invokeWith != null) {
            ...
        } else {
            //呼叫 ZygoteInit 的 zygoteInit 函式
            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }
複製程式碼

handleChildProc 內部又呼叫了 ZygoteInit 的 zygoteInit 函式,具體我們看下原始碼:

// com.android.internal.os ZygoteInit

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

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

        RuntimeInit.commonInit();
        /**
         * 1. 啟動 Binder 執行緒池
         */
        ZygoteInit.nativeZygoteInit();
        /**
         * 2. 進入 ActivityThread 的 main 方法
         */
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

複製程式碼

註釋 1 處先啟動 Binder 執行緒池,用於程式間通訊,我們註解看註釋 2 內部實現

  //com.android.internal.os RuntimeInit.java
    protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws Zygote.MethodAndArgsCaller {
       	...
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

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

        try {
            /**
             *1.  通過 className("android.app.ActivityThread" )反射得到 ActivityThread 類
             * className 通過 AMS 等其它地方傳遞過來的,並不是唯一
             */
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }

        Method m;
        try {
            /**
             * 2. 拿到 ActivityThread  main 函式
             */
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            ...
        } catch (SecurityException ex) {
            ...
        }

        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
           ...
        }

        /**
         * 3. 將 m 、argv 傳入 MethodAndArgsCaller,然後拋一個異常,並在 ZygoteInit.main 中進行捕獲異常
         */
        throw new Zygote.MethodAndArgsCaller(m, argv);
    }

複製程式碼

通過上面程式碼首先根據 AMS 傳遞過來的啟動引數 android.app.ActivityThread 然後進行反射拿到 ActivityThread 例項,在通過它的例項拿到 main 函式,最後交於 Zygote.MethodAndArgsCaller(m, argv); 異常來處理,直接看 ZygoteInit.main() 函式

//com.android.internal.os.ZygoteInit.java
    public static void main(String argv[]) {

	    ....

        try {
          
          ...

          	//服務端 Socket 名稱
            String socketName = "zygote";

					...
          

            /**
             * 1. 建立服務端的 Socket ,名稱為 "zygote"
             */

            zygoteServer.registerServerSocket(socketName);
           
        		...
            /**
             * 2. 等待 AMS 請求
             */
            zygoteServer.runSelectLoop(abiList);

        } catch (Zygote.MethodAndArgsCaller caller) {
          	//3. 捕獲到 RuntimeInit applicationInit 中的異常
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        }
    }


複製程式碼

根據註釋 3 我們知道捕獲到了 RuntimeInit applicationInit 中的異常,然後進入它的 run 函式

////com.android.internal.os Zygote.java

    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 {
                /**
                 * 1. 這裡就開始執行 ActivityThread main 方法了
                 */
                mMethod.invoke(null, new Object[] { mArgs });
            } 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);
            }
        }
    }

複製程式碼

到了這裡 應用程式的程式建立和 應用程式程式的入口 ActivityThread main 都已經執行了,下面我們來看 ActivityThead main 函式實現:

//android.app; ActivityThread.java
    //通過 ZygoteInit 反射呼叫執行的
    public static void main(String[] args) {
        ...
        //1. 主執行緒訊息迴圈 Looper 建立
        Looper.prepareMainLooper();
        //2. 建立 ActivityThread 物件
        ActivityThread thread = new ActivityThread();
        //3. Application,Activity ......入口
        thread.attach(false);
				//4. 拿到 H -> Handler
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        ...
        //5. 開啟 Looper 迴圈,處理主執行緒訊息
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
複製程式碼

通過上面程式碼我們知道 ActivityThread main 函式主要做了 5 件事:

    1. 主執行緒訊息迴圈 Looper 建立
    1. 建立 ActivityThread 物件
    1. 開啟 Application,Activity ......入口
    1. 拿到 H -> Handler
    1. 開啟 Looper 迴圈,處理主執行緒訊息

我們直接跳到註釋 3 處

//

    private void attach(boolean system) {
       	....
          //1. 拿到 IActivityManager aidl 介面
            final IActivityManager mgr = ActivityManager.getService();
            try {
                //2. 關聯 Application
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            ...
            try {
                mInstrumentation = new Instrumentation();
              	//3. 建立系統級別的 Context
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
              	//4. 建立 Application 物件
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
              	//5. Application oncreate 生命週期呼叫
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }

        ...
    }
複製程式碼

我們直接看應用程式 Application 建立吧,跳到註釋 4

//android.app; LoadedApk.java
    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }

       ...
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //1. 建立一個新的 Application
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
           
        } catch (Exception e) {
           ..}
        mApplication = app;

        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
               ...

        return app;
    }
複製程式碼

我們繼續看註釋 1 的實現

//android.app; Instrumentation.java
    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
              //呼叫內部的 newApplication 函式
        return newApplication(cl.loadClass(className), context);
    }

    static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        //反射進行例項化 Application
        Application app = (Application)clazz.newInstance();
        //執行 Application 生命週期函式 attach
        app.attach(context);
        return app;
    }
複製程式碼

到這裡應用程式程式的建立 再到應用程式的 Application 的啟動已經介紹完了

總結

本篇文章涉及到的知識點很多有 Zygote、AMS、ActivityThread、Application 等等,相信如果跟著我的系列文章來閱讀的話,收穫肯定還是有的。

在這裡就簡單的總結下應用程式程式的啟動,首先通過 Launcher 中的點選事件觸控手機螢幕中的應用圖示,AMS 會收到啟動應用程式程式的資訊,然後通過 Socket 傳遞給 Zygote 程式,Zygote 程式收到 AMS 傳遞過來的啟動資訊進行 native 層建立子程式,最後通過反射呼叫 ActivityThead main 函式,最終在 ActivityThead attach 函式中通過反射例項化了 Application 並執行了對應的生命週期函式 。到這裡該應用程式程式就 執行到了 Application 中了。下一篇文章將為大家帶來四大元件中的 Activity 原始碼分析,敬請期待!

參考

  • 《Android 進階解密》

相關文章