參照《Android 進階解密》做的摘要。
Android 系統啟動過程
init 進程啟動
Linux 內核加載完成后,它會尋找 init.rc 文件并啟動 init 進程,init 進程的入口函數為 init.cpp 中的 main 函數,可以此為代碼入口跟蹤 init 進程的處理任務。
init 進程啟動后主要做了三件事:
- 創建和掛載啟動所需的文件目錄;
- 初始化和啟動屬性服務,啟動 ServiceManger 對各種服務進行管理;
- 解析 init.rc 配置文件并啟動 Zygote 進程
Zygote 進程啟動
Zygote 進程被稱為孵化器,SystemServer 進程和應用程序進程都是通過 fork Zygote 進程來創建的。
Zygote 進程啟動流程:
-
app_main.cpp:main()
↓ -
AndroidRunTime.cpp:start() → startVm() → startReg()
↓ -
ZygoteInit.java:main() → ZygoteServer.registerServerSocket() → preload() → startSystemServer()
↓ - ZygoteServer.java:runSelectLoop()
Zygote 進程啟動主要做了一下幾件事:
- 創建 APPRuntime 并調用其 strat 方法,啟動 Zygote 進程,即進入 Zygote 進程的入口函數 main,詳情可看 app_main.cpp;
- 創建 Java 虛擬機并為 Java 虛擬機注冊 JNI 方法,因此后面 fork Zygote 創建的進程都會持有 Java 虛擬機實例以及 JNI 調用能力;
- 通過 JNI 調用 ZygoteInit 的 main 函數進入 Zygote 的 Java 框架層,注意此前包括 init 進程操作等等都是在 C/C++ 層處理,經過上面步驟 2 后才能進入 Java 框架層;
- 通過 registerZygoteSocket 方法創建服務端 Socket,并通過 runSelectLoop 方法等待 AMS 的請求來創建新的應用程序進程;
- 啟動 SystemServer 進程。
注: 為什么這里需要創建 Socket 進程通訊而不是通過 Binder 進行進程間通訊?因為進程的 fork() 對多線程不友好,僅會將發起調用的線程拷貝到子進程,其他線程都會立即停止,那如果一個線程在 fork() 前占用了某個互斥量,fork() 后被立即停止,這個互斥量就得不到釋放,再去請求該互斥量就會發生死鎖了。盡管 Zygote 沒有采取 Binder 機制,它也不是單線程的,內部還跑了一些虛擬機相關的守護線程,但它在 fork() 前主動停止了其他線程,fork() 后再重新啟動。相比來說自己啟用的線程會比 Binder 線程池的線程更好控制。我猜還有一個問題是如果使用 Binder ,那 fork() 的時候停止了 Binder 線程池就可能導致錯過某個進程的創建請求。
SystemServer 進程啟動
SystemServer 進程啟動流程:
-
ZygoteInit.java:main() → startSystemServer() → Zygote.forkSystemServer() → handleSystemServerProcess() → zygoteInit() → nativeZygoteInit();
↓ -
RuntimeInit.java:applicationInit() → invokeStaticMain()
↓ -
MethodAndArgsCaller.java:run()
↓ - SystemServer.java:main() → startBootstrapServices() → startCoreServices() → startOtherServices() → Looper.loop()
SystemServer 進程主要用于創建系統服務,如 AMS、WMS 和 PMS 等,并維持這些服務與參與應用的管理和通訊。
SystemServer 進程啟動主要做了一下幾件事:
- 啟動 binder 線程池,這樣就可以與其它進程進行通訊;
- 創建 SystemServiceManager ,其用于對系統服務進行創建、啟動和生命周期管理;
- 啟動各種系統服務,官方分為三大類:引導服務、核心服務和其它服務,具體類別可自行查詢。
Launcher 桌面應用啟動
SystemServer 進程在啟動的過程中會啟動 PackageManagerService,PackageManagerService 啟動后會將系統中的應用程序安裝完成,然后已啟動的 AMS 會將 Launcher 啟動起來。Launcher 啟動后會讀取已安裝的應用顯示到桌面,具體邏輯課查看 Launcher.java 。
Android 系統啟動整體流程
-
啟動電源以及 BootLoader:當電源按下時引導芯片會從固定位置加載引導程序 BootLoader,然后 BootLoader 會把系統 OS 拉起來并運行;
2.** Linux 內核啟動:**當內核啟動時,設置緩存、被保護存儲器、計劃列表、加載驅動。然后會在系統文件中尋找 init.rc 文件啟動 init 進程; - 進程啟動:啟動 init 進程,進而啟動 Zygote 進程接著啟動 SystemServer 進程,最后啟動 Launcher 桌面應用,到此粗略的系統啟動流程完成。
應用程序進程啟動過程
AMS 發送啟動應用程序進程請求流程:
-
AMS.java:startProcessLocked()
↓ -
Process.java:start() → startViaZygote() → openZygoteSocketIfNeeded() → zygoteSendArgsAndGetResult()
↓ - ZygoteState.java:connect()
Zygote 接受請求并創建應用程序進程流程:
-
ZygoteInit.java:main()
↓ -
SystemServer.java:runSelectLoop()
↓ -
ZygoteConnection.java:runOnce() → Zygote.forkAndSpecialize() → handleChildProc()
↓ -
ZygoteInit.java:zygoteInit() → nativeZygoteInit()
↓ -
RuntimeInit.java:applicationInit() → invokeStaticMain()
↓ -
MethodAndArgsCaller.java:run()
↓ - ActivityThread.java:main()
解釋:
AMS 的 startProcessLocked() 會將 ActivityThread.java 的全類名作為進程入口參數向下傳導,所以 Zygote 進程創建子進程后才能定位到子進程的入口并執行 ActivityThread.main() ;
應用程序進程啟動過程中會通過 ZygoteInit.nativeZygoteInit() 創建 Binder 線程池。
四大組件的工作過程
根 Activity 的啟動過程
Launcher 請求 AMS 過程:
-
Launcher.java:startActivitySafely()
↓ -
Activity.java:startActivity() → startActivityForResult()
↓ -
Instrumentation.java:execStartActivity()
↓ -
IActivityManager.java:startActivity()
↓ - AMS.java:startActivity()
AMS 到 ApplicationThread 的調用過程:
-
AMS.java:startActivity() → startActivityAsUser()
↓ -
ActivityStarter.java:startActivityMayWay() → startActivityLocked() → startActivity() → startActivity() → startActivityUnchecked()
↓ -
ActivityStackSupervisor.java:resumeFocusedStackTopActivityLocked()
↓ -
ActivityStack.java:resumeTopActivityUncheckedLocked() → resumeTopActivityInnerLocked()
↓ -
ActivityStackSupervisor.java:startSpecificActivityLocked() → realStartActivityLocked()
↓ - ApplicationThread.java:scheduleLaunchActivity()
ActivityThread 啟動 Activity 的過程:
-
ApplicationThread.java:scheduleLaunchActivity()
↓ -
ActivityThread.java:sendMessage()
↓ -
H.java:handleMessage()
↓ -
ActivityThread.java:handleLaunchActivity() → performLaunchActivity()
↓ -
Instrumentation.java:callActivityOnCreate()
↓ - Activity.java:performCreate() → onCreate()
其中 ActivityThread 調用 performLaunchActivity() 時會通過 createBaseContextForActivity() 創建 ContextImpl 并通過 ClassLoader 創建 Activity 實例,然后通過 activity.attach() 綁定 ContextImpl 并關聯 Window,performLaunchActivity() 結束后還會調用 handleResumeActivity() 將 Activity 的狀態置為 Resume。
Service 的啟動過程
ContextImpl 到 AMS 的調用過程:
-
ContextWrapper.java:startService()
↓ -
ContextImpl.java:startService() → startServiceCommon()
↓ -
IActivityManager.java:startService()
↓ - AMS.java:startService()
AMS 到 AcitivtyThread 的調用過程:
-
AMS.java:startService()
↓ -
ActiveServices.java:startServiceLocked() → startServiceInnerLocked() → bringUpServiceLocked() → realStartServiceLocked()
↓ -
ApplicationThread.java:scheduleCreateService()
↓ -
ActivityThread.java:sendMessage()
↓ -
H.java:handleMessage()
↓ -
ActivityThread.java:handleCreateService()
↓ - Service.java:onCreate()
其中 ActivityThread 調用 handleCreateService() 時會通過 ContextImpl.createAppContext 創建 ContextImpl 并通過 ClassLoader 創建 Service 實例,然后通過 service.attach() 綁定 ContextImpl 并初始化 service , 然后調用 service.onCreate() 走 service 的生命周期函數。
Service 的綁定過程
ContextImpl 到 AMS 的調用過程:
-
ContextWrapper.java:bindService()
↓ -
ContextImpl.java:bindService() → bindServiceCommon()
↓ -
IActivityManager.java:bindService()
↓ - AMS.java:bindService()
AMS 到 AcitivtyThread 的調用過程:
-
AMS.java:bindService()
↓ -
ActiveServices.java:bindServiceLocked() → requestServiceBindingLocked()
↓ -
ApplicationThread.java:scheduleBindService()
↓ -
ActivityThread.java:sendMessage()
↓ -
H.java:handleMessage()
↓ -
ActivityThread.java:handleBindService()
↓ - AMS.java:publishService()
Service 的綁定過程剩余流程:
-
AMS.java:publishService()
↓ -
ActiveServices.java:publishServiceLocked()
↓ -
InnerConnection.java:connected()
↓ -
ServiceDiapatcher.java:connected()
↓ -
RunConnection.java:run()
↓ -
ServiceDiapatcher.java:doConnected()
↓ - ServiceConnection.java:onServiceConnected()
廣播的注冊、發送和接收過程
廣播注冊
ContextImpl 到 AMS 的調用過程:
-
ContextWrapper.java:registerReceiver()
↓ -
ContextImpl.java:registerReceiver() → registerReceiverInternal()
↓ -
IActivityManager.java:registerReceiver()
↓ - AMS.java:registerReceiver()
其中會將 BroadcastReceiver 封裝為 Binder 類型的 IIntentReceiver 傳遞到 AMS ,AMS 會將 IntentFilter 和 IIntentReceiver 封裝為 BroadcastFilter 保存,當收到廣播后會匹配對應的 IntentFilter 然后通過 ApplicationThread 回傳 IIntentReceiver 進行廣播接收者調用。
廣播發送
ContextImpl 到 AMS 的調用過程:
-
ContextWrapper.java:sendBroadcast()
↓ -
ContextImpl.java:sendBroadcast() → sendBroadcast()
↓ -
IActivityManager.java:broadcastIntent()
↓ - AMS.java:broadcastIntent() → broadcastIntentLocked()
AMS 到 BroadcastReceiver 的調用過程:
-
BroadcastQueue.java:scheduleBroadcastsLocked() → BroadcastHandler.handlerMessage() → deliverToRegisteredReceiverLocked() → performReceiverLocked()
↓ -
ApplicationThread.java:scheduleRegisteredReceiver()
↓ -
InnerReceiver.java:performReceiver()
↓ -
ReceiverDispatcher.java:performReceiver()
↓ -
Args.java:run()
↓ - BroadcastReceiver.java:onReceiver()
ContentProvider 的啟動過程
query 方法到 AMS 的調用過程:
-
ContentResolver.java:query() → acquireUnstableProvider
↓ -
ApplicationContentResolver.java:acquireUnstableProvider()
↓ -
ActivityThread.java:acquireProvider()
↓ -
IActivityManager.java:getContentProvider()
↓ -
AMS.java:getContentProvider() → getContentProviderImpl()
↓ -
ActivityThread.java:main() → attach()
↓ -
IActivityManager.java:attachApplication()
↓ - AMS.java:attachApplication()
AMS 啟動 ContentProvider 的過程:
-
AMS.java:attachApplication() → attachApplicationLocked()
↓ -
ApplicationThread.java:bindApplication()
↓ -
ActivityThread.java:sendMessage() → H.handleMessage() → handleBindApplication() → installContentProviders() → installProvider()
↓ - ContentProvider.java:attachInfo() → onCreate()
理解上下文 Context
Context 意為上下文,經常使用它來啟動四大組件、訪問資源、調用系統服務或者彈出 Toast 、創建 Dialog 之類的。它有兩個子類 ContextWrapper 和 ContextImpl,ContextImpl 負責具體邏輯細節實現,ContextWrapper 則只是對 ContextImpl 進行基本的裝飾,后面的類則繼承自 ContextWrapper 進行進一步功能增強,比如針對主題強化的 ContextThemeWrapper 。Activity、Service、Application 都繼承自 ContextWrapper,所以應用進程的 Context 數量就等于它們三者相加之和。
Application Context 的創建過程:
-
ActivityThread.java:main()
↓ -
LoadedApk.java:makeApplication() → ContextImpl.createAppContext()
↓ -
Instrumentation.java:newApplication()
↓ -
Application.java:attach()
↓ - ContextWrapper.java:attachBaseContext()
Activity 和 Service 的 Context 創建在上面四大組件啟動中可以看到,最終都是 ContextImpl 創建通過 attachBaseContext 設置的。
理解 ActivityManagerService
ActivityManagerService 簡稱 AMS ,創建于 SystemServer 進程,主要負責四大組件的管理工作。Android 8.0 之前。應用程序與 AMS 通訊使用的是原始的 Binder 通訊,相對麻煩,8.0 開始則改為了使用 AIDL 接口,簡化了代碼交互邏輯。
AMS 重要的數據結構
ActivityRecord
內部記錄了 Activity 的所有信息,包括 AMS 的引用、AndroidManifest 節點信息、Activity 狀態、Activity 資源信息和 Activity 進程相關信息以及 TaskRecord。
TaskRecord
就是我們通常所說的 Activity 任務棧,里面保存了棧中的各個 Activity 的 ActivityRecord 信息。
ActivityStack
ActivityStack 是一個管理類,用來管理系統所有 Activity,并按不同的狀態進行分類。它內部存儲各種不同狀態的列表,列表的元素主要有 ActivityRecord 和 TaskRecord,比如 mTaskHistory 列表存儲的是所有沒有被銷毀的 Activity 任務棧 TaskRecord。
理解 WindowManager
Window 是一個每一個界面的載體,具體的實現為 PhoneWindow,它對 View 進行管理;WindowManager 繼承接口 ViewManager ,實現類為 WindowManagerImpl,主要負責與 WindowManagerService 通信,WindowManagerService 則負責 Window 的具體管理工作。如果要對 Window 進行添加、更新和刪除操作,需要借助 WindowManager 將具體的工作交由 WMS 來處理,WindowManager 和 WMS 通過 Binder 進行跨進程通信。
Activity 的 PhoneWindow 創建是在調用 Activity.attach() 方法內部創建的,接著PhoneWindow 又通過 setWindowManager 創建一個 WindowManagerImpl 實例,而 WindowManagerImpl 的內部又會將具體實現委托給 WindowManagerGlobal, WindowManagerGlobal 是一個單例,一個進程中只有一個 WindowManagerGlobal 實例。
Window 的屬性
Window 的類型
Window 的主要分為三大類型,分別是 Application Window(應用程序窗口),Sub Window(子窗口)、System Window(系統窗口)
- 應用程序窗口:Activity 就是一個典型的應用程序窗口,應用程序窗口的 Type 范圍是 1-99 ,根據 Type 值的不同又會分為很多種應用程序窗口,具體可查閱資料或源碼;
- 子窗口:子窗口無法獨立存在,需要依附在其它窗口才可以,PopupWindow 就屬于子窗口,子窗口的 Type 范圍是 1000-1999;
- 系統窗口: Toast、出入法窗口、系統音量條窗口、系統錯誤窗口都屬于系統窗口,系統窗口的 Type 范圍是 2000-2999 ;
Window 的顯示次序
如果把手機屏幕虛擬的用 X、Y、Z 軸表示,其中 Z 軸垂直于屏幕,則 Window 的顯示次序可以看作是在 Z 軸上的次序,通常 Type 值越大,則 Window 的顯示就越靠近用戶,所以應用程序窗口 < 子窗口 < 系統窗口,< 代表顯示層級。
Window 的操作
Activity 的 Window 添加過程:
-
ActivityThread.java:handleResumeActivity()
↓ -
WindowManagerImpl.java:addView()
↓ -
WindowManagerGlobal.java:addView()
↓ -
ViewRootImpl.java:setView()
↓ -
Session.java:addToDisPlay()
↓ - WMS.java:addWindow()
其中 WindowManagerGlobal 保存了每個窗口對應的 View 和 ViewRootImpl,具體的添加過程則是通過 ViewRootImpl 來進行的。ViewRootImpl 身負了很多職責,主要有一下幾點:
- View 樹的根并管理 View 樹;
- 觸發 View 的測量、布局和繪制;
- 輸入事件的中轉站;
- 管理 Surface;
- 負責與 WMS 進行進程間通信。
Window 的更新過程:
-
WindowManagerImpl.java:updateViewLayout()
↓ -
WindowManagerGlobal.java:updateViewLayout()
↓ -
ViewRootImpl.java:setLayoutParams() -> scheduleTraversals() -> doTraversal() -> performTraversals() -> relaoutWindow()
↓ -
Session.java:relayout()
↓ - WMS.java:relayoutWindow()
其中 ViewRootImpl 在 performTraversals() 調用 relaoutWindow() 后就會繼續往下執行 View 的繪制三部曲: performMeasure() -> performLayout() -> performDraw() ;
理解 WindowManagerService
WMS 的職責
WMS 是 Android 中重要的服務,它有很多職責,每個職責都會涉及重要且復雜的系統:
- 窗口管理:它是窗口的管理者,負責窗口的啟動、添加和刪除,還有對窗口的大小和顯示層級進行管理;
- 窗口動畫:窗口動畫有 WMS 的動畫子系統來負責,動畫子系統的管理者為 WindowAnimator ;
- 輸入系統的中轉站:通過對窗口的觸摸從而產生觸摸事件,InputManagerService(IMS)會對觸摸事件進行處理,它會尋找一個最合適的窗口來處理觸摸反饋信息,WMS 是窗口的管理者,它作為輸入系統的中轉站再合適不過了;
- Surface 管理:窗口并不具備繪制的功能,因此每個窗口都需要有一塊 Surface 來供自己繪制,為每個窗口分配 Surface 是由 WMS 來完成的。
WMS 的創建過程
WMS 的創建過程依次分為三個線程進行處理:
- system_server:startCoreService() -> WMS.main() -> WMS.displayReady()
- android.display:new WMS() -> WMS.initPolicy()
- android.ui:PWM.init()
android.display 的優先級比 system_server 高,所以 system_server 會等待 android.display 處理完畢,同理 android.display 也會等待 android.ui 線程處理完畢,具體實現可查看源碼。
WMS 的重要成員
mSessions: ArraySet
mSessions 的元素是 Session,它主要用于進程間通信,每個應用程序進程想和 WMS 進行通信都需要經過 Session ,并且每個應用程序進程都會對應一個 Session ,WMS 保存這些 Session 用來記錄所有向 WMS 提出窗口管理服務的客戶端。
mFinishedStarting: ArrayList
mFinishedStarting 的元素是 AppWindowToken,它是 WindowToken 的子類,WindowToken 主要有兩個作用:
- 窗口令牌,當應用程序想要向 WMS 申請新創建一個窗口,則需要向 WMS 出示有效的 WindowToken。所以每個 Activity 都對應一個 APPWindowToken;
- WindowToken 會將同一個組件(比如同一個 Activity )的窗口(WindowState)集合在一起,方便管理,即 Dialog 的窗口和 Activity 的窗口是放在一起管理的。
mFinishedStarting 存儲已經完成啟動的應用程序窗口的 AppWindowToken 列表。
Window 的 WMS 添加過程
Window 的 WMS 添加過程主要集中在 addWindow() 方法,該方法主要做了四件事:
- 對所要添加的窗口進行檢查,如果窗口不滿足一些條件,就不會再執行下面的代碼邏輯;
- WindowToken 相關的處理,比如有的窗口類型需要提供 WindowToken,沒有提供的話就不會執行下面的代碼邏輯,有的窗口類型則需要由 WMS 隱式創建 WindowToken;
- WindowState 的創建和相關處理,將 WindowToken 和 WindowState 相關聯;
- 創建和配置 DisplayContent,完成窗口添加到系統前的準備工作。
Window 的 刪除過程
Window 的刪除過程:
-
WindowManagerImpl.java:removeView()
↓ -
WindowManagerGlobal.java:removeView() -> removeViewLocked()
↓ -
ViewRootImpl.java:die() -> doDie() (doDie 內部會遍歷子 View 調用 dispatchDetachedFromWindow())
↓ -
WindowManagerGlobal.java:doRemoveView()
↓ - WMS.java:relayoutWindow()
dispatchDetachedFromWindow 流程:
-
ViewRootImpl.java:dispatchDetachedFromWindow()
↓ -
Session.java:remove()
↓ - WMS.java:removeWindow() -> removeIfPossible() -> removeImmediately()
Window 的刪除邏輯比較復雜,以下作簡單總結:
- 檢查刪除線程的正確性,即只能是創建 View 的線程(通常稱為 UI 線程,不一定是主線程)才能操作 View;
- 從 ViewRootImpl 列表、布局參數列表和 View 列表中刪除與 View 對應的元素;
- 判斷是否可以直接執行刪除操作,如果不能就推遲刪除操作;
- 執行刪除操作,清理和釋放與 View 相關的一切資源。
JNI 原理
JNI 是 Java 世界和 Native 世界的橋梁。
Native 方法注冊
Native 方法注冊分為靜態注冊和動態注冊,其中靜態注冊多用于 NDK 開發,而動態注冊多用于 Framework 開發。
靜態注冊使用的是約定大于配置的思想,通過包名+類名+方法名的格式將 Java 方法和 JNI 函數建立關聯
動態注冊則需要手動將 Java 方法和 JNI 函數進行綁定注冊,通常會在 JNI_OnLoad 函數中進行。
方法簽名
JNI 的方法簽名的格式為: (參數簽名格式...)返回值簽名格式
解析 JNIEnv
JNIEnv 是 Native 世界中 Java 環境的代表,通過 JNIEnv *指針可以在 Native 世界中訪問 Java 世界的代碼進行操作,它只在創建它的線程中有效,不能跨線程傳遞,因此不同線程的 JNIEnv 是彼此獨立的,JNIEnv 的主要作用有以下兩點:
- 調用 Java 的方法。
- 操作 Java (操作 Java 中的變量和對象等)。
JNIEnv 是一個結構體,其內部又包含了 JNINativeInterface。JNIEnv 中常用函數很多,這里列舉三個,FindClass 用來找到 Java 中指定名稱的類,GetMethodID 用來得到 Java 中的方法,GetFieldID 用來得到 Java 中的成員變量。
引用類型
JNI 的引用類型分別是本地引用(Local References)、全局引用(Global References)和弱全局引用(Weak Global References)。
本地引用:
- 當 Native 函數返回時,這個本地引用就會被自動釋放。
- 只在創建它的線程中有效,不能夠跨線程使用。
- 局部引用是 JVM 負責的引用類型,受 JVM 管理。
全局引用:
- 在 native 函數返回時不會被自動釋放,因此全局引用需要手動來進行釋放,并且不會被 GC 回收。
- 全局引用是可以跨線程使用的。
- 全局引用不受到 JVM 管理。
弱全局引用:
- 弱全局引用是一種特殊的全局引用,它和全局引用的特點相似,不同的是弱全局引用是可以被 GC 回收的,弱全局引用被 GC 回收之后會只想 NULL。
ClassLoader
Android 中的 ClassLoader 類型和 Java 中的 ClassLoader 類型類似,也分為兩種類型,分別是系統類加載器和自定義類加載。其中系統類加載器主要包括 3 種,分別是 BootClassLoader 、 PathClassLoader 和 DexClassLoader。
1.BootClassLoader
Android 系統啟動時會使用 BootClassLoader 來預加載常用類,與 JDK 中的 BootClassLoader 不同,它不是由 C/C++ 代碼實現的,而是由 Java 實現的,BootClassLoader 是 ClassLoader 的內部類,進繼承自 ClassLoader。
2.DexClassLoader
DexClassLoader 可以加載 dex 文件以及包含 dex 的壓縮文件(apk 和 jar 文件),不管加載哪種文件,最終都要加載 dex 文件。
3.DexClassLoader
Android 系統使用 PathClassLoader 來加載系統類和應用程序的類。
PathClassLoader 和 DexClassLoader 都是繼承自 BaseDexClassLoader,所以它們的構造方法都有如下 4 個參數:
- dexPath:dex 相關文件路徑集合,多個路徑用文件分隔符分割,默認文件分隔符為":"。
- optimizedDirectory:解壓的 dex 文件存儲路徑,這個路徑必須是一個內部存儲路徑,即應用程序的內部存儲空間。
- librarySearchPath:包含 C/C++ 庫的路徑集合,多個路徑用文件分隔符分割,可以為 null。
- parent:父加載器。
PathClassLoader 中的 optimizedDirectory 固定為 /data/dalvik-cache,所以 PathClassLoader 無法定義解壓的 dex 文件存儲路徑,因此 PathClassLoader 通常用來加載已經安裝的 apk 的 dex 文件(安裝的 apk 的 dex 文件會存儲在 /data/dalvik-cache 中)。DexClassLoader 則通常用于插件化中加載新的 dex 文件。
ClassLoader 查找流程:
-
ClassLoader:loadClass()
↓ -
BaseDexClassLoader.java:findClass()
↓ -
DexPathList.java:findClass()
↓ -
Element.java:findClass()
↓ - DexFile.java:loadClassBinaryName()
BootClassLoader 和 PathClassLoader 都是在 Zygote 進程的 ZygoteInit 中創建的。