天天看點

【系統之音】Android程序的建立及啟動簡述

Android的程序都是通過Zygote fork而來的,那這些程序的啟動流程都是怎樣的呢?本文将基于Android P的源碼來分析Android系統架構程序SystemServer和應用程式程序的建立過程,力求完整和簡潔,隻關注關鍵流程。

       Android系統中的程序(這裡不包括init等底層的程序)都是通過Zygote fork而來的,那這些程序的啟動流程都是怎樣的呢?

       這裡将Android程序分為兩個部分:

    (1)系統架構程序SystemServer程序。它是Zygote建立的第一個程序,是在系統啟動過程中,Zygote程序啟動時直接fork而來的。

    (2)應用程式程序。比如Launcher、SystemUI,其它應用程式等的程序。這些應用程式程序的啟動大緻包含兩個步驟:

            1)AMS向Zygote程序發送建立程序的請求;

            2)Zygote接受請求,建立并啟動應用程式程序。

        本文将圍繞上述幾點,基于Android P(API28)的源碼,來梳理Android程序的建立與啟動過程。内容的主要對象是應用開發者,是以力求簡潔和完整,内容大體如下:

【系統之音】Android程式的建立及啟動簡述

1、Zygote程序啟動簡述

       在了解這一部分前,建議先閱讀【系統之音】Android系統啟動篇。

       系統在啟動時,會啟動一個名為“init”的系統程序,然後該程序會建立并啟動Zygote程序。建立和啟動Zygote程序的過程,先後從Nativie層跨入Java層,在Native層會建立虛拟機執行個體(即ART執行個體),然後通過JNI的方式調用ZygoteInit類的main方法。Native層的代碼咱們不深究,這裡看看main方法:

1 //(代碼1.1)=========ZygoteInit.java=====
 2 public static void main(String argv[]) {
 3       ZygoteServer zygoteServer = new ZygoteServer();
 4       ......
 5       String socketName = "zygote";
 6       ......
 7       //建立一個名為“zygote”的Server端Socket,在後續會一直監聽AMS發起的建立新程序的請求。
 8       zygoteServer.registerServerSocketFromEnv(socketName);
 9       ......
10       //①通過fork方式建立SystemServer程序并啟動
11       if (startSystemServer) {
12                 Runnable r = forkSystemServer(abiList, socketName, zygoteServer);//fork建立SystemServer程序
13                 ......
14                 if (r != null) {
15                     r.run();//啟動SystemServer程序
16                     return;
17                 }
18             }
19        //②該方法中使用了一個while(true)的無限循環來實作一直監聽AMS的請求
20        caller = zygoteServer.runSelectLoop(abiList);
21        ......
22        //③這裡是會執行子程序(應用程式程序)的ActivityThread的main方法,後文會講到
23        if (caller != null) {
24             caller.run();
25         }
26 }      

我抽取了關鍵的代碼,主要是關注Zygote啟動期間所做的主要工作,這裡先給出結論(有必要牢記于心):

    (1)建立虛拟機執行個體;

    (2)建立一個名為“zygote”的Server端Socket,用于後續監聽AMS的請求;

    (3)通過fork的方式建立SystemServer程序并啟動它,該過程會啟動各種系統服務,AMS就是在這個階段啟動的;

    (4)在runSelectLoop方法中通過一個while(true)無限循環來實作對AMS的監聽;

    (5)啟動非SystemServer程序。

2、Zygote建立與啟動SystemServer

       實際上SystemServer是Zygote建立出的第一個程序,我們從代碼1.1中的注釋②處的forkSystemServer方法來深入了解:

1 //代碼2.1==========ZygoteInit.java=======
 2 private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {
 3       ......
 4       int pid;
 5       ......
 6       //fork的過程發生在Native層
 7       pid = Zygote.forkSystemServer(...);
 8       ......
 9       //④pid為0表示子程序(即SystemServer程序)建立成功,邏輯進入到子程序中。下面的邏輯會啟動SystemServer程序
10       if (pid == 0) {
11             ......
12             return handleSystemServerProcess(parsedArgs);
13        }
14 }
15 
16 public static int forkSystemServer(...){
17       ......
18       int pid = nativeForkSystemServer(...);
19       ......
20 }
21 
22 native private static int nativeForkSystemServer(...)      

可見,forkSystemServer程序是發生在Native層的,接着繼續從注釋④處看看SystemServer程序的啟動:

1 //代碼2.2 =========ZygoteInit.java========
 2 private static Runnable handleSystemServerProcess(...){
 3       ......
 4       return ZygoteInit.zygoteInit(...);
 5 }
 6 
 7 public static final Runnable zygoteInit(...) {
 8        ......
 9        //該處用于建立Binder線程池,此後SystemServer程序就可以使用Binder來實作IPC了。該過程也是在Native層實作,Binder在ServiceManager中進行注冊。
10         ZygoteInit.nativeZygoteInit();
11         return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
12     }
13 
14 private static final native void nativeZygoteInit();
15 
16 //==========RuntimeInit.java=======
17 protected static Runnable applicationInit(...){
18       ......
19       //通過上下文可以得知這裡的args.startClass值為“com.android.server.SystemServer”
20       return findStaticMain(args.startClass, args.startArgs, classLoader);
21 }
22 
23 /**
24  * Invokes a static "main(argv[]) method on class "className".
25  * ......
26  */
27 protected static Runnable findStaticMain(String className, String[] argv,
28         ClassLoader classLoader) {
29     Class<?> cl;
30     try {
31         cl = Class.forName(className, true, classLoader);
32     } catch (ClassNotFoundException ex) {
33         throw new RuntimeException(
34                 "Missing class when invoking static main " + className,
35                 ex);
36     }
37     Method m;
38     try {
39         m = cl.getMethod("main", new Class[] { String[].class });
40     } catch (NoSuchMethodException ex) {
41         throw new RuntimeException(
42                 "Missing static main on " + className, ex);
43     } catch (SecurityException ex) {
44         throw new RuntimeException(
45                 "Problem getting static main on " + className, ex);
46     }
47     int modifiers = m.getModifiers();
48     if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
49         throw new RuntimeException(
50                 "Main method is not public and static on " + className);
51     }
52     ...... //毫無疑問,這裡的m就是SystemServer類的main方法了
53     return new MethodAndArgsCaller(m, argv);
54 }
55 
56 static class MethodAndArgsCaller implements Runnable {
57     /** method to call */
58     private final Method mMethod;
59     /** argument array */
60     private final String[] mArgs;
61     public MethodAndArgsCaller(Method method, String[] args) {
62         mMethod = method;
63         mArgs = args;
64     }
65     public void run() {
66         try {
67             mMethod.invoke(null, new Object[] { mArgs });
68         }
69         ......
70     }
71 }      

       一步步跟進時,我們會發現該過程中主線都是傳回的Runnable類型的對象,回到代碼1.1的注釋②處的第12行,這裡的 r 就是MethodAndArgsCaller對象,第13行r.run()執行,就是調用的上述代碼第67行,跟蹤上下文可知這裡就是執行的SystemServer.main方法。緊接着第14行是return,Zygote就完成了建立和啟動SystemServer程序。此時你是否會有疑問:這裡就return了,那後面監聽AMS請求和啟動非SystemServer程序的邏輯又如何實作呢?這裡我們需要了解“fork”,後面我們會詳細介紹。

        這裡進一步看看SystemServer程序中都做了些什麼:

1 //=========SystemServer.java===========
 2 public static void main(String[] args) {
 3     new SystemServer().run();
 4 }
 5 private void run() {
 6     ......
 7     //建立消息Looper
 8     Looper.prepareMainLooper();
 9     // 加載動态庫libandroid_servers.so,初始化native服務
10     System.loadLibrary("android_servers");
11     ......
12     //初始化系統context
13     createSystemContext();
14     //建立SystemServiceManager
15     mSystemServiceManager = new SystemServiceManager(mSystemContext);
16     ......
17     //啟動引導服務,如AMS等
18     startBootstrapServices();
19     //啟動核心服務
20     startCoreServices();
21     //啟動其它服務,如WMS,SystemUI等
22     startOtherServices();
23     ....
24     // Loop forever.
25     Looper.loop();
26 }      

到這裡Zygote就建立并啟動了SystemServe程序,總結一下這個過程中主要做了些什麼工作:

    (1)通過fork得到一個虛拟機執行個體副本;

    (2)建立Binder線程池,SystemServer可以通過Binder來實作IPC(跨程序通信);

    (3)啟動系統服務,比如AMS,WMS等;

    (4)建立消息循環,Looper.loop()中是一個無限循環,SystemServer将持續運作。

3、fork簡介

       在前文中提到了使用fork的方式來建立程序,也提到了一個疑問:

       “此時你是否會有疑問:這裡就return了,那後面監聽AMS請求和啟動非SystemServer程序的邏輯又如何實作呢?”

       這裡先看看百度百科的介紹:

“複刻(英語:fork,又譯作派生、分支)是UNIX或類UNIX中的分叉函數,fork函數将運作着的程式分成2個(幾乎)完全一樣的程序,
每個程序都啟動一個從代碼的同一位置開始執行的線程。這兩個程序中的線程繼續執行,就像是兩個使用者同時啟動了該應用程式的兩個副本。
    fork系統調用用于建立一個新程序,稱為子程序,它與程序(稱為系統調用fork的程序)同時運作,此程序稱為父程序。建立新的子程序後,
兩個程序将執行fork()系統調用之後的下一條指令。子程序使用相同的pc(程式計數器),相同的CPU寄存器,在父程序中使用的相同打開檔案。”      

       是以,在代碼1.1中forkSystemServer時,Zygote程序會分化為兩個一模一樣的程序來,其中一個是父程序,另外一個是子程序,它是主程序的副本。當SystemServer fork成功後其流程就進入到了子程序中,即代碼1.1中的第15、16行是在子程序中執行的。而與此同時,父程序還會繼續往下執行,不斷監聽AMS的請求以及啟動新的程序。

       要更好地了解fork後Zygote程序和子程序的工作,可以參考閱讀:https://www.cnblogs.com/jiangzhaowei/p/11023098.html。

4、Zygote監聽AMS的請求

        在代碼1.1中注釋②處,會通過調用runSelectLoop方法來監聽AMS的請求,我們看看該方法的實作:

1 //代碼4.1======ZygoteServer.java======
 2 Runnable runSelectLoop(String abiList) {
 3       ......
 4       ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
 5       ......
 6       while (true) {
 7            ......
 8            //⑤當監聽到AMS請求的資料時會執行這裡
 9            ZygoteConnection connection = peers.get(i);
10            final Runnable command = connection.processOneCommand(this);
11            ......
12            return command;
13       }
14 }      

這其中包含了一個while(true)的無限循環,以此來一直監聽AMS的請求,直到注釋⑤處監聽到了AMS的請求,fork出新的子程序(應用程式程序),随後在子程序中return,結束監聽。和fork SystemServer一樣,父程序Zygote仍然繼續監聽着,繼續相應AMS新的請求,fork出新的子程序。

5、AMS向Zygote程序發起建立程序的請求

       要啟動一個程式時,系統首先會判斷該程式所在的程序是否存在,如果不存在就需要先建立并啟動目标程式對應的程序。這一點在四大元件元件啟動流程的源碼中都有展現,當發現目标程序還不存在時,AMS都會向Zygote程序申請建立目标程序。這個過程分為兩步:(1)AMS向Zygote程序發起建立程序的請求;(2)Zygote收到請求,建立并啟動程序。這一節我們先看看第(1)步:

1 //==============ActivityManagerService.java============
 2 private final boolean startProcessLocked(ProcessRecord app, String hostingType,
 3             String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
 4        ......
 5        final String entryPoint = "android.app.ActivityThread";
 6        return startProcessLocked(hostingType, hostingNameStr, entryPoint...);
 7 }
 8 private boolean startProcessLocked(...String entryPoint...) {
 9        ......
10        final ProcessStartResult startResult = startProcess(...entryPoint...);
11  }
12  private ProcessStartResult startProcess(...String entryPoint...){
13        ......
14        final ProcessStartResult startResult;
15        ......
16        startResult = Process.start(entryPoint,
17                          app.processName, uid, uid, gids, runtimeFlags, mountExternal,
18                          app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
19                          app.info.dataDir, invokeWith,
20                          new String[] {PROC_START_SEQ_IDENT + app.startSeq});
21        ......
22  }
23  //================Process.java==============
24  public static final ZygoteProcess zygoteProcess = new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
25  public static final ProcessStartResult start(final String processClass,...) {
26           return zygoteProcess.start(processClass, ...);
27  }
28  //==============ZygoteProcess.java==========
29   public final Process.ProcessStartResult start(final String processClass...) {
30          try {
31              return startViaZygote(processClass...);
32          }......
33     }
34  private Process.ProcessStartResult startViaZygote(final String processClass...){       
35        argsForZygote.add(processClass);
36        ......
37        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
38  }
39  private ZygoteState primaryZygoteState;
40  ......
41  private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
42        ......
43        //追蹤代碼,容易得知mSocket值為"zygote",這裡的作用是連接配接名為“zygote”的Socket
44        primaryZygoteState = ZygoteState.connect(mSocket);
45        ......
46  }      

        從上述代碼可以看出,該過程的邏輯其實挺簡單,通過層層調用後走到第50行。這一行的作用就是和名為“zygote”的Socket服務端建立連接配接,這樣就向Zygote程序發起了請求。這裡的ZygoteState類中的

6、Zygote收到AMS的請求,建立并啟動程序

       在代碼4.1中,我們講過,其中while(true)循環一直監聽AMS的請求,直到收到請求。

1 //===========ZygoteConnection.java=======
 2 Runnable processOneCommand(ZygoteServer zygoteServer) {
 3       ......
 4       //⑥fork方式建立應用程式程序
 5       pid = Zygote.forkAndSpecialize(...);
 6       ......
 7       //pid為0表示目前的代碼邏輯運作在新建立的子程序(即應用程式程序)中
 8       if (pid == 0) {
 9                 // in child
10                  ......
11                  //處理應用程式程序
12                  return handleChildProc(parsedArgs, descriptors, childPipeFd,
13                          parsedArgs.startChildZygote);
14              } else {
15                  ......
16              }
17  }
18 
19  private Runnable handleChildProc(...){
20         ......
21         return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,null /* classLoader */);
22  }
23  //=====ZygoteInit.java========
24  public static final Runnable zygoteInit(...) {
25        ......
26        //建立Binder線程池,此後新的子程序就能夠使用Binder進行IPC了
27        ZygoteInit.nativeZygoteInit();
28        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
29  }
30 
31 //============Zygote.java==========(補充注釋⑥處)
32 public static int forkAndSpecialize(...) {
33     ........
34     int pid = nativeForkAndSpecialize(...);
35     ......
36     return pid;
37 }
38 native private static int nativeForkAndSpecialize(...);      

流程走到第26行就比較清晰了,和代碼2.2中啟動SystemServer程序一緻了,隻不過這裡啟動的是ActivityThread的main方法。

1 //=======ActivityThread.java=====
 2 static volatile Handler sMainThreadHandler;
 3 
 4 public static void main(String[] args) {
 5       ......
 6       Looper.prepareMainLooper();
 7       ......
 8       ActivityThread thread = new ActivityThread();
 9       ......
10       if (sMainThreadHandler == null) {
11             sMainThreadHandler = thread.getHandler();
12        }
13       ......
14        Looper.loop();
15 }
16 
17 final Handler getHandler() {
18         return mH;
19     }
20 
21 final H mH = new H();
22 
23 class H extends Handler {
24       ......
25 }      

       ActivityThread類是主線程的管理類,其main方法中會建立消息循環,其中Looper.loop()方法中通過無限循環的方式,保持主線程一直運作。同時還會建立主線程的H類,這是一個包含主線程looper的Handler,四大元件啟動過程中都需要通過這個H類對象來從Binder線程中切換到主線程中。

       這裡總結一下普通應用程式程序建立時的關鍵工作:

    (2)建立Binder線程池,應用程式程序就可以通過Binder來實作IPC;

    (3)建立消息循環,建立主線程的H類。

7、疑問

    (1)為什麼AMS(SystemServer程序)與Zygote程序通訊采用Socket而不是Binder?

       答:因為fork不允許存在多線程,而Binder通信偏偏就是多線程。(不知道該答案是否準确,目前還沒找到權威答案)。

       可以參考:https://blog.csdn.net/qq_39037047/article/details/88066589

 參考及推薦閱讀:

       https://www.cnblogs.com/andy-songwei/p/11429421.html

       https://www.cnblogs.com/jiangzhaowei/p/11023098.html

       https://www.jianshu.com/p/ab9b83a77af6

       https://blog.csdn.net/qq_39037047/article/details/88066589

       劉望舒《Android進階解密》