前言 當長按手機的power鍵,Android手機就會開機,那麼Android系統的開機啟動過程到底是怎麼樣的呢,本文將要介紹這一過程。簡單來說,Android系統的開機啟動過程大致是這樣的:首先linux系統會啟動一個叫做zygote(可以稱為受精卵、母體)的linux程序,這個程序實際上就是android系統的內核,zygote啟動的時候會建立socket服務端並加載大量的類和資源。接著zygote會孵化第一個dalvik進程SystemServer,在SystemServer中會創建一個socket客戶端,後續AMS(ActivityManagerService)會通過此客戶端和zygote通信,zygote再根據請求孵化出新的dalvik進程即啟動一個新的apk同時把新進程的socket連接關閉。SystemServer初始化完畢後會啟動一個位於棧頂的activity,由於系統剛開機,所以task棧頂沒有activity,於是接著它會發送一個隱式的intent(category:CATEGORY_HOME),也就是launcher了,即Android系統的桌面程序,launcher啟動以後,我們就可以通過桌面啟動各種應用了,可以發現,launcher可以有多個,第三方應用只要加入launcher所需要的intent-filter即可。下面一一分析各個流程。(註:本文分析基於Android4.3源碼) zygote的啟動過程zygote是一個linux程序,其對應的可執行文件位於/system/bin/app_process,它在/init.rc中定義,如下 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
可以發現,zygote創建了一個流式套接字(即採用TCP協議),並監聽660端口,並且當zygote重啟的時候需要對喚醒電源並重啟Media、netd服務。下面看zygote的源碼,其路徑為frameworks\base\cmds\app_process\app_main.cpp中:
[cpp]
1.int main(int argc, char* const argv[])
2.{
3.#ifdef __arm__
4. /*
5. * b/7188322 - Temporarily revert to the compat memory layout
6. * to avoid breaking third party apps.
7. *
8. * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
9. *
11. * changes the kernel mapping from bottom up to top-down.
12. * This breaks some programs which improperly embed
13. * an out of date copy of Android's linker.
14. */
15. char value[PROPERTY_VALUE_MAX];
16. property_get("ro.kernel.qemu", value, "");
17. bool is_qemu = (strcmp(value, "1") == 0);
18. if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) {
19. int current = personality(0xFFFFFFFF);
20. if ((current & ADDR_COMPAT_LAYOUT) == 0) {
21. personality(current | ADDR_COMPAT_LAYOUT);
22. setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);
23. execv("/system/bin/app_process", argv);
24. return -1;
25. }
26. }
27. unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");
28.#endif
29.
30. // These are global variables in ProcessState.cpp
31. mArgC = argc;
32. mArgV = argv;
33.
34. mArgLen = 0;
35. for (int i=0; i<argc; i++) {
36. mArgLen += strlen(argv) + 1;
37. }
38. mArgLen--;
39. //注意,這裡持有了一個AppRuntime對象,其繼承自AndroidRuntime
40. AppRuntime runtime;
41. const char* argv0 = argv[0];
42.
43. // Process command line arguments
44. // ignore argv[0]
45. argc--;
46. argv++;
47.
48. // Everything up to '--' or first non '-' arg goes to the vm
49.
50. int i = runtime.addVmArguments(argc, argv);
51.
52. // Parse runtime arguments. Stop at first unrecognized option.
53. bool zygote = false;
54. bool startSystemServer = false;
55. bool application = false;
56. const char* parentDir = NULL;
57. const char* niceName = NULL;
58. const char* className = NULL;
59. //這裡是解析init.rc中定義的zygote的啟動參數
60. while (i < argc) {
61. const char* arg = argv[i++];
62. if (!parentDir) {
63. parentDir = arg;
64. } else if (strcmp(arg, "--zygote") == 0) {
65. zygote = true;
66. niceName = "zygote";
67. } else if (strcmp(arg, "--start-system-server") == 0) {
68. startSystemServer = true;
69. } else if (strcmp(arg, "--application") == 0) {
70. application = true;
71. } else if (strncmp(arg, "--nice-name=", 12) == 0) {
72. niceName = arg + 12;
73. } else {
74. className = arg;
75. break;
76. }
77. }
78.
79. if (niceName && *niceName) {
80. setArgv0(argv0, niceName);
81. set_process_name(niceName);
82. }
83.
84. runtime.mParentDir = parentDir;
85.
86. if (zygote) {
87. //從init.rc中的定義可以看出,zygote為true,startSystemServer也為true
88. //最終這裡會調用ZygoteInit的main方法
89. runtime.start("com.android.internal.os.ZygoteInit",
90. startSystemServer ? "start-system-server" : "");
91. } else if (className) {
92. // Remainder of args get passed to startup class main()
93. runtime.mClassName = className;
94. runtime.mArgC = argc - i;
95. runtime.mArgV = argv + i;
96. runtime.start("com.android.internal.os.RuntimeInit",
97. application ? "application" : "tool");
98. } else {
99. fprintf(stderr, "Error: no class name or --zygote supplied.\n");
100. app_usage();
101. LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
102. return 10;
103. }
104.}
說明:這句代碼runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "")在AndroidRuntime中實現,其最終會調用ZygoteInit的main方法,請看env->CallStaticVoidMethod(startClass, startMeth, strArray);這裡的startClass就是com.android.internal.os.ZygoteInit,而startMeth就是main,所以,我們直接看ZygoteInit的main方法,代碼路徑為:frameworks\base\core\java\com\android\internal\os\ZygoteInit.java:
[java]
1.public static void main(String argv[]) {
2. try {
3. // Start profiling the zygote initialization.
4. SamplingProfilerIntegration.start();
5. //這裡註冊流式socket,以便於fork新的dalvik進程
6. registerZygoteSocket();
7. EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
8. SystemClock.uptimeMillis());
9. //這裡預先加載一些類和資源
10. preload();
11. EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
12. SystemClock.uptimeMillis());
13.
14. // Finish profiling the zygote initialization.
15. SamplingProfilerIntegration.writeZygoteSnapshot();
16.
17. // Do an initial gc to clean up after startup
18. gc();
19.
20. // Disable tracing so that forked processes do not inherit stale tracing tags from
21. // Zygote.
22. Trace.setTracingEnabled(false);
23.
24. // If requested, start system server directly from Zygote
25. if (argv.length != 2) {
26. throw new RuntimeException(argv[0] + USAGE_STRING);
27. }
28.
29. if (argv[1].equals("start-system-server")) {
30. //啟動SystemServer,zygote通過SystemServer和上層服務進行交互
31. startSystemServer();
32. } else if (!argv[1].equals("")) {
33. throw new RuntimeException(argv[0] + USAGE_STRING);
34. }
35.
36. Log.i(TAG, "Accepting command socket connections");
37. //通過Select方式監聽端口,即異步讀取消息,死循環,沒有消息則一直阻塞在那裡
38. runSelectLoop();
39.
40. closeServerSocket();
41. } catch (MethodAndArgsCaller caller) {
42. caller.run();
43. } catch (RuntimeException ex) {
44. Log.e(TAG, "Zygote died with exception", ex);
45. closeServerSocket();
46. throw ex;
47. }
48.}
下面看一下runSelectLoop方法,看看它是如何fork產生一個新的進程的:
[java]
1./**
2. * Runs the zygote process's select loop. Accepts new connections as
3. * they happen, and reads commands from connections one spawn-request's
4. * worth at a time.
5. *
6. * @throws MethodAndArgsCaller in a child process when a main() should
7. * be executed.
8. */
9.private static void runSelectLoop() throws MethodAndArgsCaller {
10. ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
11. ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
12. FileDescriptor[] fdArray = new FileDescriptor[4];
13.
14. fds.add(sServerSocket.getFileDescriptor());
15. peers.add(null);
16.
17. int loopCount = GC_LOOP_COUNT;
18. //死循環,沒有消息則一直阻塞在這裡
19. while (true) {
20. int index;
21.
22. /*
23. * Call gc() before we block in select().
24. * It's work that has to be done anyway, and it's better
25. * to avoid making every child do it. It will also
26. * madvise() any free memory as a side-effect.
27. *
28. * Don't call it every time, because walking the entire
29. * heap is a lot of overhead to free a few hundred bytes.
30. */
31. if (loopCount <= 0) {
32. gc();
33. loopCount = GC_LOOP_COUNT;
34. } else {
35. loopCount--;
36. }
37.
38.
39. try {
40. fdArray = fds.toArray(fdArray);
41. //通過select()函數來讀取新的socket消息,其返回值有<0、0、>0三種
42. //分別代表:發生異常、繼續讀取新消息、首先處理當前消息
43. index = selectReadable(fdArray);
44. } catch (IOException ex) {
45. throw new RuntimeException("Error in select()", ex);
46. }
47.
48. if (index < 0) {
49. throw new RuntimeException("Error in select()");
50. } else if (index == 0) {
51. //構造一個ZygoteConnection對象,並將其加入到peers列表中
52. ZygoteConnection newPeer = acceptCommandPeer();
53. peers.add(newPeer);
54. fds.add(newPeer.getFileDesciptor());
55. } else {
56. boolean done;
57. //這裡處理當前socket消息,ZygoteConnection的runOnce會被調用,一個新的dalvik進程會被創建
58. done = peers.get(index).runOnce();
59.
60. if (done) {
61. //處理完了以後刪除此socket消息
62. peers.remove(index);
63. fds.remove(index);
64. }
65. }
66. }
67.}
接著,我們還需要看下ZygoteConnection的runOnce方法,看看一個dalvik進程到底是如何產生的,我們知道每個apk都運行在一個獨立的dalvik進程中,所以當啟動一個apk的時候,zygote會孵化出一個新的進程,在這個進程中運行此apk。 在ZygoteConnection中,新進程是通過Zygote的靜態方法forkAndSpecialize來產生的:
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName);
具體的我們就不用多看了,內部肯定是通過linux系統的fork()函數來產生一個新進程的。當一個新的dalvik進程產生了以後,還需要做一些清場的工作,由於新進程是由zygote程序fork出來的,所以子進程具有zygote的一份拷貝,我們知道,zygote啟動的時候創建了一個socket服務端,這個服務端只能有一個,由zygote孵化的子進程是不應該有的,所以子進程孵化出來以後,還必須關閉拷貝的socket服務端,這些操作在handleChildProc方法中完成:
[java]
1.private void handleChildProc(Arguments parsedArgs,
2. FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
3. throws ZygoteInit.MethodAndArgsCaller {
4. //關閉本地和服務端(如果有)的socket
5. closeSocket();
6. ZygoteInit.closeServerSocket();
7.
8. if (descriptors != null) {
9. try {
10. ZygoteInit.reopenStdio(descriptors[0],
11. descriptors[1], descriptors[2]);
12.
13. for (FileDescriptor fd: descriptors) {
14. IoUtils.closeQuietly(fd);
15. }
16. newStderr = System.err;
17. } catch (IOException ex) {
18. Log.e(TAG, "Error reopening stdio", ex);
19. }
20. }
21.
22. if (parsedArgs.niceName != null) {
23. Process.setArgV0(parsedArgs.niceName);
24. }
25.
26. if (parsedArgs.runtimeInit) {
27. if (parsedArgs.invokeWith != null) {
28. WrapperInit.execApplication(parsedArgs.invokeWith,
29. parsedArgs.niceName, parsedArgs.targetSdkVersion,
30. pipeFd, parsedArgs.remainingArgs);
31. } else {
32. RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
33. parsedArgs.remainingArgs);
34. }
35. } else {
36. String className;
37. try {
38. className = parsedArgs.remainingArgs[0];
39. } catch (ArrayIndexOutOfBoundsException ex) {
40. logAndPrintError(newStderr,
41. "Missing required class name argument", null);
42. return;
43. }
44.
45. String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
46. System.arraycopy(parsedArgs.remainingArgs, 1,
47. mainArgs, 0, mainArgs.length);
48.
49. if (parsedArgs.invokeWith != null) {
50. WrapperInit.execStandalone(parsedArgs.invokeWith,
51. parsedArgs.classpath, className, mainArgs);
52. } else {
53. ClassLoader cloader;
54. if (parsedArgs.classpath != null) {
55. cloader = new PathClassLoader(parsedArgs.classpath,
56. ClassLoader.getSystemClassLoader());
57. } else {
58. cloader = ClassLoader.getSystemClassLoader();
59. }
60.
61. try {
62. //這裡子進程的main方法被調用,此時,子進程完全從zygote(母體)上脫離出來了
63. ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
64. } catch (RuntimeException ex) {
65. logAndPrintError(newStderr, "Error starting.", ex);
66. }
67. }
68. }
69.}
同時在ZygoteInit中會預先加載一些類和資源,具體代碼在preload方法中:
static void preload() {
preloadClasses();
preloadResources();
}SystemServer的創建
SystemServer作為zygote孵化的第一個dalvik進程,其孵化過程在上面已經進行了描述,但是其和普通進程的啟動略有不同,普通進程由Zygote.forkAndSpecialize來啟動,而SystemServer由Zygote.forkSystemServer來啟動,其次是SystemServer內部多創建了一個socket客戶端。關於SystemServer內部的本地socket客戶端,本文前面已經說過,外圍的Service都是通過SystemServer和zygote交互的,比如要啟動一個apk,首先AMS會發起一個新進程的創建請求,在startProcessLocked方法中會調用Process的start方法,其內部會調用startViaZygote方法,而在startViaZygote內部會創建一個本地socket和zygote通信,我們要知道,AMS是在SystemServer進程中創建的,所以說在SystemServer中創建一個本地socket和zygote通信是有道理的。SystemServer的一個很重要的作用是創建各種服務,包括大家常見的WindowManagerService 、AlarmManagerService、ActivityManagerService等,然後上層的各種manager通過binder和service進行交互,關於SystemServer創建各種服務的過程以及和binder的交互,請參考我之前寫的一篇博客的其中一節,這裡就不重複了:點擊打開點擊打開
1.final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
2. // Find the first activity that is not finishing.
3. //找到棧頂的activity記錄
4. ActivityRecord next = topRunningActivityLocked(null);
5.
6. // Remember how we'll process this pause/resume situation, and ensure
7. // that the state is reset however we wind up proceeding.
8. final boolean userLeaving = mUserLeaving;
9. mUserLeaving = false;
10. //由於系統剛啟動,棧頂肯定沒有activity,所以next為null
11. if (next == null) {
12. // There are no more activities! Let's just start up the
13. // Launcher...
14. if (mMainStack) {
15. ActivityOptions.abort(options);
16. //程序執行到這裡,桌面就會被調起來
17. return mService.startHomeActivityLocked(mCurrentUser);
18. }
19. }
20. ...此處省略
21.}
最後看看桌面是如何被調起來的:
[java]
1.boolean startHomeActivityLocked(int userId) {
2. if (mHeadless) {
3. // Added because none of the other calls to ensureBootCompleted seem to fire
4. // when running headless.
5. ensureBootCompleted();
6. return false;
7. }
8.
9. if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
10. && mTopAction == null) {
11. // We are running in factory test mode, but unable to find
12. // the factory test app, so just sit around displaying the
13. // error message and don't try to start anything.
14. return false;
15. }
16. Intent intent = new Intent(
17. mTopAction,
18. mTopData != null ? Uri.parse(mTopData) : null);
19. intent.setComponent(mTopComponent);
20. if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
21. //其實就是為intent加上CATEGORY_HOME這個Category,接著就發送隱式intent來調起所有滿足條件的桌面
22. //這也是第三方桌面存在的價值
23. intent.addCategory(Intent.CATEGORY_HOME);
24. }
25. ActivityInfo aInfo =
26. resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
27. if (aInfo != null) {
28. intent.setComponent(new ComponentName(
29. aInfo.applicationInfo.packageName, aInfo.name));
30. // Don't do this if the home app is currently being
31. // instrumented.
32. aInfo = new ActivityInfo(aInfo);
33. aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
34. ProcessRecord app = getProcessRecordLocked(aInfo.processName,
35. aInfo.applicationInfo.uid);
36. if (app == null || app.instrumentationClass == null) {
37. intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
38. //這裡啟動桌面activity,到此為止,桌面被啟動了,我們就可以認為手機開機完成了
39. mMainStack.startActivityLocked(null, intent, null, aInfo,
40. null, null, 0, 0, 0, null, 0, null, false, null);
41. }
42. }
43.
44. return true;
45.}
到此為止,桌面已經啟動了,也就意味著手機的開機啟動過程已經完成,後續我們就可以通過桌面來啟動各個應用了,根據本文的介紹,我們已經知道apk啟動時dalvik進程的創建過程,關於單個activity的啟動過程,請參看我之前寫的另一篇文章Android源碼分析-Activity的啟動過程
。到此為止,本文結束了,相信大家對Android系統的開機啟動過程應該有了一個感性的認識了。
|