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