閱讀本文大約需要花費1小時。
文章的內容主要還是從源碼進行分析,雖然又臭又長,但是如果想要學習Android系統源碼,這是必要走的路,沒有捷徑。
相對於碎片學習,我更傾向於靜下心來花費1個小時認真的學習一段內容。
專注於Android系統級源碼分析,Android的平臺設計,歡迎關注我,謝謝!
上一節我們講完了Launcher的啟動流程,這一節來看看應用進程的創建過程以及Zygote的fork流程。
系列文章:
1.概述
上一節我們學習了Launcher的啟動流程。這一節來介紹下應用進程的創建過程以及Zygote Fork的過程。
點擊桌面圖標啟動應用概述:
在上一節Launcher的啟動中我們知道了,手機的桌面其實就是Launcher進程,裡面的應用圖標都是Launcher通過ListView進行展示。
那麼我們點擊一個桌面圖標,比如微信,這個應用是如何啟動的呢,這一節我們從系統級的源碼來一步步的進行分析。
在分析之前,我們簡單區分一下進程和線程的概念。
在Android中通過Logcat抓取log時,存在PID和TID兩個概念。
PID:Process ID,進程ID
TID: Thread ID,線程ID
每個Android都是一個進程,每個進程有一個或多個線程
進程:
是併發執行的程序在執行過程中分配和管理資源的基本單位,是一個動態概念,競爭計算機系統資源的基本單位。
當我們點擊某個應用的圖標時,必須創建一個進程,該進程是由Zygote fork出來的,進程具有獨立的資源空間,用於承載App上運行的各種Activity/Service等組件。
線程:
是進程的一個執行單元,是進程內科調度實體。比進程更小的獨立運行的基本單位。線程也被稱為輕量級進程。
每個應用有多個線程,例如UI展示屬於UI主線程,一些通信過程屬於獨立線程,通常JAVA中使用new Thread().start()來創建一個新的線程。
該線程並沒有自己獨立的地址空間,而是與其所在進程之間資源共享。
進程線程的區別
- 地址空間:同一進程的線程共享本進程的地址空間,而進程之間則是獨立的地址空間。
- 資源擁有:同一進程內的線程共享本進程的資源,但是進程之間的資源是獨立的。
- 一個進程崩潰後,在保護模式下不會對其他進程產生影響,但是一個線程崩潰整個進程都死掉。所以多進程要比多線程健壯。
- 進程切換時,消耗的資源大,效率高。所以涉及到頻繁的切換時,使用線程要好於進程。同樣如果要求同時進行並且又要共享某些變量的併發操作,只能用線程不能用進程。
- 執行過程:每個獨立的進程有一個程序運行的入口、順序執行序列和程序入口。但是線程不能獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。
- 線程是處理器調度的基本單位,但是進程不是。
- 兩者均可併發執行。
2.核心源碼
3.架構
App發起進程:點擊一個桌面應用(例如微信),Launcher 加載應用, LauncherActivity收到觸發事件,組裝Intent,通過binder發送消息給SystemServer進程,調用Activity的startActivity()來啟動進程,啟動Activity時,受ActivityManagerService-AMS的服務控制,AMS屬於SystemServer進程,因此SystemServer進行會通過Process 來向Zygote發送一個Socket。
Zygote有一個無限循環,一直在等待Socket請求,收到SystemServer發來新的Socket請求後,Zygote調用系統的fork函數來孵化一個新的進程,比如這裡的微信。
再把啟動的入口交給ActivityThread,進入微信的進程中,進行詳細的UI展示。
3.1 進程創建圖
從點擊Launcher中的圖標,到啟動Activity,再到Zygote Fork操作,最終進入新的進行進行UI繪製。
3.2 Zygote Fork圖
Zygote調用系統的fork()函數,孵化出一個新的進程,fork()採用copy-on-write機制,有些類如果不做改變,甚至都不用複製,子進程可以和父進程共享這部分數據,從而省去不少內存的佔用。
圖片來源Gityuan
4.源碼分析
應用的啟動共分以下四個步驟完成:
- 點擊桌面的圖標,Launcher調用系統的startActivity進行啟動Activity,此時的動作在Launcher進程中
- ATM\\AMS 進行Activity的處理,組裝message,通過socket發送給Socket
- Zygote收到SystemServer發來的消息,進行消息拆分,再調用系統的fork()函數,進行進行孵化操作。
- 進入ActivityThread的main(),完成最終應用進程的的onCreate操作
接下來我們根據這四個步驟來進行詳細的源碼分析.
4.1 第一階段,點擊桌面圖標,觸發點擊事件
觸發Launcher listview的點擊事件 onListItemClick()
說明:桌面圖標按照5*5或者6*6的方式進行排列,這其實是Launcher進程展示的ListView,每個應用圖標填入其中,點擊圖標進入Launcher的點擊事件處理
源碼:
4.1.1 [Activity.java]
startActivity()
說明:這裡比較簡單,調用
startActivityForResult()
源碼:
4.1.2 [Activity.java]
startActivityForResult()
說明:不難發現,不論有沒有父Activity,最終都交給了 Instrumentation 來開啟
源碼:
4.1.3 [Instrumentation.java]
execStartActivity()
說明:Binder 調用 ActivityTaskManagerService-ATM 來啟動 Activity
源碼:
從下面代碼可以看到,IActivityTaskManager其實獲得的是activity_task對應服務的Binder對象,
即是ActivityTaskManagerService-ATM
4.2 第二階段:ATM\\AMS 進行Activity的處理
調用棧如下:
4.2.1 [ActivityTaskManagerService.java]
startActivity()
說明: 這裡很簡單,直接調用startActivityAsUser()
源碼:
4.2.2 [ActivityTaskManagerService.java]
startActivityAsUser()
說明:獲取 ActivityStarter 對象,最終調用ActivityStarter的execute()
源碼:
4.2.3 [ActivityStarter.java] execute()
說明:根據[4.2.2]中調用了setMayWait,因此這裡的mRequest.mayWait為true
源碼:
4.2.4 [ActivityStarter.java]
startActivityMayWait()
說明:調用startActivity()來啟動Activity
源碼:
4.2.5 [ActivityStarter.java]
startActivity()
說明:延時佈局,然後通過startActivityUnchecked()來處理啟動標記 flag ,要啟動的
4.2.6 [RootActivityContainer.java]
resumeFocusedStacksTopActivities()
說明:獲取棧頂的Activity,恢復它
源碼:
4.2.7 [ActivityStackSupervisor.java]
startSpecificActivityLocked()
說明: 發佈消息以啟動進程,以避免在ATM鎖保持的情況下調用AMS時可能出現死鎖,最終調用到ATM的startProcess()
源碼:
4.2.8 [ActivityManagerService.java]
startProcess()
說明: 一路調用Process start(),最終到ZygoteProcess的
attemptUsapSendArgsAndGetResult(),用來fork一個新的Launcher的進程
源碼:
調用棧如下:
4.2.9 [ZygoteProcess.java]
attemptZygoteSendArgsAndGetResult()
說明:通過Socket連接Zygote進程,把之前組裝的msg發給Zygote,其中processClass ="android.app.ActivityThread",通過Zygote進程來Fork出一個新的進程,
並執行 "android.app.ActivityThread"的main方法
源碼:
4.3 第三階段 Zygote Fork 應用進程
說明:Zygote的啟動過程我們前面有詳細講到過。
SystemServer的AMS服務向啟動Home Activity發起一個fork請求,Zygote進程通過Linux的fork函數,孵化出一個新的進程。
由於Zygote進程在啟動時會創建Java虛擬機,因此通過fork而創建的Launcher程序進程可以在內部獲取一個Java虛擬機的實例拷貝。
fork採用copy-on-write機制,有些類如果不做改變,甚至都不用複製,子進程可以和父進程共享這部分數據,從而省去不少內存的佔用。
調用棧如下:
4.3.1 [ZygoteInit.java] main()
說明:Zygote先fork出SystemServer進程,接著進入循環等待,用來接收Socket發來的消息,用來fork出其他應用進程,比如Launcher
源碼:
4.3.2 [ZygoteConnection.java]
processOneCommand()
說明:通過 forkAndSpecialize()來fork出Launcher的子進程,並執行handleChildProc,進入子進程的處理
源碼:
4.3.3 [Zygote.java] forkAndSpecialize
說明:主要是調用dalvik中ZygoteHooks的preFrok進行預處理,再調用postForkCommon進行完成的進程fork
源碼:
4.3.3.1 [ZygoteHooks.java] preFork()
說明:Zygote進程有4個Daemon子線程分別是
HeapTaskDaemon、
ReferenceQueueDaemon、
FinalizerDaemon、
FinalizerWatchdogDaemon
preFork()預處理主要是先停止4個子線程,等待所有的子線程結束,最後完成gc堆的初始化工作
Zygote子線程如下圖所示:
源碼:
4.3.3.2 [Daemons.java] stop()
說明:此處守護線程Stop方式是先調用目標線程interrrupt()方法,然後再調用目標線程join()方法,等待線程執行完成
停止4個子線程,分別是:Java堆整理線程;引用隊列線程;析構線程;析構監控線程
源碼:
4.3.3.3 [ZygoteHooks.java]
waitUntilAllThreadsStopped()
說明:等待所有子線程結束
源碼:
4.3.4 [ZygoteHooks.java]
nativePreFork()
通過JNI最終調用的是以下方法:
[dalvik_system_ZygoteHooks.cc] ZygoteHooks_nativePreFork()
說明:進行堆的一些預處理
源碼:
4.3.4.1 [runtime.cpp] PreZygoteFork()
說明:堆的初始化工作,屬於虛擬機的範疇,想理解的可以深挖一下
源碼:
4.3.5 [Zygote.java]
nativeForkAndSpecialize()
通過JNI最終調用的是以下方法:
[com_android_internal_os_Zygote.cpp] com_android_internal_os_Zygote_nativeForkAndSpecialize
說明: fork 子進程
源碼:
4.3.5.1 [com_android_internal_os_Zygote.cpp]
ForkCommon()
說明:調用系統的fork()進行 應用進程的孵化操作,採用copy-on-write的機制,使得應用進程與Zygote共享部分數據,減少內存的佔用
源碼:
4.3.5.2 [com_android_internal_os_Zygote.cpp]
SpecializeCommon()
說明:進行進程的一些資源處理,selinux權限處理,並調用Zygote的callPostForkChildHooks()
源碼:
4.3.5.3 [Zygote.java]
callPostForkChildHooks()
說明:JAVA堆線程的一些處理
源碼:
創建JAVA的線程池,設置信號處理,啟動JDWP線程
4.3.6 [ZygoteHooks.java] postForkCommon()
說明:在fork新進程後,啟動Zygote的4個Daemon線程,java堆整理,引用隊列,以及析構線程。
源碼:
啟動Zygote的4個新的子線程
4.3.7 [ZygoteConnection.java]
handleChildProc()
說明:進行子進程的操作,最終獲得需要執行的ActivityThread的main()
源碼:
zygoteInit 進行一些環境的初始化、啟動Binder進程等操作
把之前傳來的"android.app.ActivityThread" 傳遞給findStaticMain
通過反射,拿到ActivityThread的main()方法
把反射得來的ActivityThread main()入口返回給ZygoteInit的main,通過caller.run()進行調用
至此,Zygote fork進程的操作全部完成,下一步進入JAVA世界,進行真正的Activity的啟動流程。
4.4 第四階段 進入應用進程,啟動Activity的onCreate()
調用棧如下:
4.4.1 [ActivityThread.java] main()
說明: 主線程處理, 創建ActivityThread對象,調用attach進行處理,最終進入Looper循環
源碼:
調用ActivityThread的attach進行處理
4.4.2 [ActivityManagerService.java]
attachApplication()
說明:清除一些無用的記錄,最終調用ActivityStackSupervisor.java的 realStartActivityLocked(),進行Activity的啟動
源碼:
4.4.3 [ActivityStackSupervisor.java]
realStartActivityLocked()
說明:真正準備去啟動Activity,通過clientTransaction.addCallback把LaunchActivityItem的obtain作為回調參數加進去,再調用
ClientLifecycleManager.scheduleTransaction()得到LaunchActivityItem的execute()方法進行最終的執行
參考上面的第四階段的調用棧流程:
源碼:
4.4.4 [TransactionExecutor.java] execute()
說明:執行之前realStartActivityLocked()中的
clientTransaction.addCallback
調用棧:
源碼:
4.4.5 [ActivityThread.java]
handleLaunchActivity()
說明:主要乾了兩件事,第一件:初始化WindowManagerGlobal;第二件:調用performLaunchActivity方法
源碼:
4.4.6 [ActivityThread.java]
performLaunchActivity()
說明:獲取ComponentName、Context,反射創建Activity,設置Activity的一些內容,比如主題等;
最終調用callActivityOnCreate()來執行Activity的onCreate()方法
源碼:
callActivityOnCreate先執行activity onCreate的預處理,再去調用Activity的onCreate,最終完成Create創建後的內容處理
performCreate()主要調用Activity的onCreate()
至此,看到了我們最熟悉的Activity的onCreate(),應用啟動的啟動完成,應用程序被真正的調用起來。
5.總結
通過上面一系列的流程,我們理解了應用進程的創建流程,以及Zygote fork這些應用進程的流程。
主要分為4步完成:
- 點擊桌面的圖標,Launcher調用系統的startActivity進行啟動Activity,此時的動作在Launcher進程中
- 通過Binder向SystemServer進行發送消息,讓ATM\\AMS 進行Activity的處理,組裝message,通過socket發送給Socket,此時動作在SystemServer進程中
- Zygote收到SystemServer發來的消息,進行消息拆分,再調用系統的fork()函數,進行進行孵化操作,此時動作在Zygote進程中
- 進入ActivityThread的main(),完成最終應用進程的的onCreate操作,該步動作處於新創建的應用進程中
閱讀更多 IngresGe 的文章