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

宋者為王發表於2020-09-16

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

       這裡將Android程式分為兩個部分:

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

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

            1)AMS向Zygote程式傳送建立程式的請求;

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

        本文將圍繞上述幾點,基於Android P(API28)的原始碼,來梳理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執行緒中切換到主執行緒中。

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

    (1)通過fork得到一個虛擬機器例項副本;

    (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進階解密》

相關文章