從點擊桌面應用圖標到應用顯示的過程咱們再熟悉不過了,下面咱們來分析下這個過程都作了什麼。html
本文主要對如下問題分析:java
ActivityThread 是什麼,它是一個線程嗎,如何被啓動的? ActivityClientRecord 與 ActivityRecord 是什麼? Context 是什麼,ContextImpl,ContextWapper 是什麼? Instrumentation 是什麼? Application 是什麼,何時建立的,每一個應用程序有幾個 Application? 點擊 Launcher 啓動 Activity 和應用內部啓動 Activity 的區別? Activity 啓動過程,onCreate(),onResume() 回調時機及具體做用?緩存
如不瞭解 Android 是如何從開機到 Launcher 啓動的過程。app
咱們知道 Android 系統啓動後已經啓動了 Zygote,ServiceManager,SystemServer 等系統進程;ServiceManager 進程中完成了 Binder 初始化;SystemServer 進程中 ActivityManagerService,WindowManagerService,PackageManagerService 等系統服務在 ServiceManager 中已經註冊;最後啓動了 Launcher 桌面應用。ide
其實 Launcher 自己就是一個應用程序,運行在本身的進程中,咱們看到的桌面就是 Launcher 中的一個 Activity。函數
應用安裝的時候,經過 PackageManagerService 解析 apk 的 AndroidManifest.xml 文件,提取出這個 apk 的信息寫入到 packages.xml 文件中,這些信息包括:權限、應用包名、icon、apk 的安裝位置、版本、userID 等等。packages.xml 文件位於系統目錄下/data/system/packages.xml。oop
同時桌面 Launcher 會爲安裝過的應用生成不一樣的應用入口,對應桌面上的應用圖標,下面分析點擊應用圖標的到應用啓動的過程。佈局
點擊 Launcher 中應用圖標將會執行如下方法ui
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Launcher.startActivitySafely()
Launcher.startActivity()
//以上兩個方法主要是檢查將要打開的 Activity 是否存在
Activity.startActivity()
//這段代碼你們已經很熟悉,常常打開 Activity 用的就是這個方法
Activity.startActivityForResult()
//默認 requestCode = -1,也可經過調用 startActivityForResult() 傳入 requestCode。
//而後經過 MainThread 獲取到 ApplicationThread 傳入下面方法。
Instrumentation.execStartActivity()
//經過 ActivityManagerNative.getDefault() 獲取到 ActivityManagerService 的代理爲進程通信做準備。
ActivityManagerNative.getDefault().startActivity()
ActivityManagerProxy.startActivity()
//調用代理對象的 startActivity() 方法,發送 START_ACTIVITY_TRANSACTION 命令。
|
在 system_server 進程中的服務端 ActivityManagerService 收到 START_ACTIVITY_TRANSACTION 命令後進行處理,調用 startActivity() 方法。this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
ActivityManagerService.startActivity() -> startActivityAsUser(intent, requestCode, userId)
//經過 UserHandle.getCallingUserId() 獲取到 userId 並調用 startActivityAsUser() 方法。
ActivityStackSupervisor.startActivityMayWait() -> resolveActivity()
//經過 intent 建立新的 intent 對象,即便以前 intent 被修改也不受影響。 而後調用 resolveActivity()。
//而後經過層層調用獲取到 ApplicationPackageManager 對象。
PackageManagerService.resolveIntent() -> queryIntentActivities()
//獲取 intent 所指向的 Activity 信息,並保存到 Intent 對象。
PackageManagerService.chooseBestActivity()
//當存在多個知足條件的 Activity 則會彈框讓用戶來選擇。
ActivityStackSupervisor.startActivityLocked()
//獲取到調用者的進程信息。 經過 Intent.FLAG_ACTIVITY_FORWARD_RESULT 判斷是否須要進行 startActivityForResult 處理。
//檢查調用者是否有權限來調用指定的 Activity。
//建立 ActivityRecord 對象,並檢查是否運行 App 切換。
ActivityStackSupervisor.startActivityUncheckedLocked() -> startActivityLocked()
//進行對 launchMode 的處理[可參考 Activity 啓動模式],建立 Task 等操做。
//啓動 Activity 所在進程,已存在則直接 onResume(),不存在則建立 Activity 並處理是否觸發 onNewIntent()。
ActivityStack.resumeTopActivityInnerLocked()
//找到 resume 狀態的 Activity,執行 startPausingLocked() 暫停該 Activity,同時暫停全部處於後臺棧的 Activity,找不到 resume 狀態的 Activity 則回桌面。
//若是須要啓動的 Activity 進程已存在,直接設置 Activity 狀態爲 resumed。 調用下面方法。
ActivityStackSupervisor.startSpecificActivityLocked()
//進程存在調用 realStartActivityLocked() 啓動 Activity,進程不存在則調用下面方法。
|
從 Launcher 點擊圖標,若是應用沒有啓動過,則會 fork 一個新進程。建立新進程的時候,ActivityManagerService 會保存一個 ProcessRecord 信息,Activity 應用程序中的AndroidManifest.xml 配置文件中,咱們沒有指定 Application 標籤的 process 屬性,系統就會默認使用 package 的名稱。每個應用程序都有本身的 uid,所以,這裏 uid + process 的組合就能夠爲每個應用程序建立一個 ProcessRecord。每次在新建新進程前的時候會先判斷這個 ProcessRecord 是否已存在,若是已經存在就不會新建進程了,這就屬於應用內打開 Activity 的過程了。
1
2
|
ActivityManagerService.startProcessLocked()
//進程不存在請求 Zygote 建立新進程。 建立成功後切換到新進程。
|
進程建立成功切換至 App 進程,進入 app 進程後將 ActivityThread 類加載到新進程,並調用 ActivityThread.main() 方法
1
2
3
4
5
6
7
8
|
ActivityThread.main()
//建立主線程的 Looper 對象,建立 ActivityThread 對象,ActivityThread.attach() 創建 Binder 通道,開啓 Looper.loop() 消息循環。
ActivityThread.attach()
//開啓虛擬機各項功能,建立 ActivityManagerProxy 對象,調用基於 IActivityManager 接口的 Binder 通道 ActivityManagerProxy.attachApplication()。
ActivityManagerProxy.attachApplication()
//發送 ATTACH_APPLICATION_TRANSACTION 命令
|
此時只建立了應用程序的 ActivityThread 和 ApplicationThread,和開啓了 Handler 消息循環機制,其餘的都還未建立, ActivityThread.attach(false) 又會最終到 ActivityMangerService 的 attachApplication,這個工程實際上是將本地的 ApplicationThread 傳遞到 ActivityMangerService。而後 ActivityMangerService 就能夠經過 ApplicationThread 的代理 ApplicationThreadProxy 來調用應用程序 ApplicationThread.bindApplication,通知應用程序的 ApplicationThread 已和 ActivityMangerService 綁定,能夠不借助其餘進程幫助直接通訊了。此時 Launcher 的任務也算是完成了。
在 system_server 進程中的服務端 ActivityManagerService 收到 ATTACH_APPLICATION_TRANSACTION 命令後進行處理,調用 attachApplication()。
1
2
3
|
ActivityMangerService.attachApplication() -> attachApplicationLocked()
//首先會獲取到進程信息 ProcessRecord。 綁定死亡通知,移除進程啓動超時消息。 獲取到應用 ApplicationInfo 並綁定應用 IApplicationThread.bindApplication(appInfo)。
//而後檢查 App 所需組件。
|
此處討論 Activity 的啓動過程,只討論 ActivityStackSupervisor.attachApplicationLocked() 方法。
1
2
3
4
5
|
ActivityStackSupervisor.attachApplicationLocked() -> realStartActivityLocked()
//將該進程設置爲前臺進程 PROCESS_STATE_TOP,調用 ApplicationThreadProxy.scheduleLaunchActivity()。
ApplicationThreadProxy.scheduleLaunchActivity()
//發送 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令
|
發送送完 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令,還會發送 BIND_APPLICATION_TRANSACTION 命令來建立 Application。
1
2
|
ApplicationThreadProxy.bindApplication()
//發送 BIND_APPLICATION_TRANSACTION 命令
|
在 app 進程中,收到 BIND_APPLICATION_TRANSACTION 命令後調用 ActivityThread.bindApplication()。
1
2
|
ActivityThread.bindApplication()
//緩存 Service,初始化 AppBindData,發送消息 H.BIND_APPLICATION。
|
ApplicationThreadProxy.bindApplication(…) 會傳來這個應用的一些信息,如ApplicationInfo,Configuration 等,在 ApplicationThread.bindApplication 裏會待信息封裝成A ppBindData,經過
1
|
sendMessage(H.BIND_APPLICATION, data)
|
將信息放到應用裏的消息隊列裏,經過 Handler 消息機制,在 ActivityThread.handleMeaasge 裏處理 H.BIND_APPLICATION 的信息,調用 AplicationThread.handleBindApplication。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
handleBindApplication(AppBindData data) {
Process.setArgV0(data.processName);
//設置進程名
...
//初始化 mInstrumentation
if
(data.mInstrumentation!=
null
) {
mInstrumentation = (Instrumentation) cl.loadClass(data.instrumentationName.getClassName()).newInstance();
}
else
{
mInstrumentation =
new
Instrumentation();
}
//建立Application,data.info 是個 LoadedApk 對象。
Application app = data.info.makeApplication(data.restrictedBackupMode,
null
);
mInitialApplication = app;
//調用 Application 的 onCreate()方法。
mInstrumentation.callApplicationOnCreate(app);
}
public
Application makeApplication(
boolean
forceDefaultAppClass,Instrumentation instrumentation) {
if
(mApplication !=
null
) {
return
mApplication;
}
String appClass = mApplicationInfo.className;
java.lang.ClassLoader cl = getClassLoader();
//此時新建一個 Application 的 ContextImpl 對象,
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread,
this
);
//經過在 handleBindApplication 建立的 mInstrumentation 對象新建一個 Application 對象,同時進行 attach。
app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
appContext.setOuterContext(app);
}
//設置進程名,獲取 LoadedApk 對象,建立 ContextImpl 上下文
//LoadedApk.makeApplication() 建立 Application 對象,調用 Application.onCreate() 方法。
|
Instrumentation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
Application newApplication(ClassLoader cl, String className, Context context) {
return
newApplication(cl.loadClass(className), context);
}
Instrumentation類:
static
public
Application newApplication(Class<!--?--> clazz, Context context) {
//實例化 Application
Application app = (Application)clazz.newInstance();
// Application 和 context綁定
app.attach(context);
return
app;
}
//attach 就是將新建的 ContextImpl 賦值到 mBase,這個 ContextImpl 對象就是全部Application 內 Context 的具體實現,同時賦值一些其餘的信息如 mLoadedApk。
final
void
attach(Context context) {
mBase = base;
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
|
這時 Application 就建立好了,這點很重要,不少資料裏說 Application 是在performLaunchActivity() 裏建立的,由於 performLaunchActivity() 也有mInstrumentation.newApplication 這個調用,newApplication() 函數中可看出會先判斷是否以及建立了 Application,若是以前已經建立,就返回已建立的 Application 對象。
上面 fork 進程時會發送 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令,在 app 進程中,收到 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令後調用 ApplicationThread.scheduleLaunchActivity()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
ApplicationThread.scheduleLaunchActivity()
//發送消息 H.LAUNCH_ACTIVITY。
sendMessage(H.LAUNCH_ACTIVITY, r);
ActivityThread.handleLaunchActivity()
//最終回調目標 Activity 的 onConfigurationChanged(),初始化 WindowManagerService。
//調用 ActivityThread.performLaunchActivity()
ActivityThread.performLaunchActivity() {
//相似 Application 的建立過程,經過 classLoader 加載到 activity.
activity = mInstrumentation.newActivity(classLoader,
component.getClassName(), r.intent);
//由於 Activity 有界面,因此其 Context 是 ContextThemeWrapper 類型,但實現類還是ContextImpl.
Context appContext = createBaseContextForActivity(r, activity);
activity.attach(context,mInstrumentation,application,...);
//與 Window 進行關聯
//attach 後調用 activity 的 onCreate()方法。
mInstrumentation.callActivityOnCreate(activity,...)
}
//在ActivityThread.handleLaunchActivity裏,接着調用
Activity.performCreate() -> onCreate()
//最終回調目標 Activity 的 onCreate()。
Activity.setContentView()
//設置 layout 佈局
ActivityThread.performResumeActivity()
//最終回調目標 Activity 的 onResume()。
|
與 Window 進行關聯。
Activity 的總體啓動流程如圖所示:
ActivityThread 是什麼,它是一個線程嗎,如何被啓動的?
它不是一個線程,它是運行在 App 進程中的主線程中的一個方法中。當 App 進程建立時會執行 ActivityThread.main(),ActivityThread.main() 首先會建立 Looper 執行 Looper.prepareMainLooper();而後建立 ActivityThread 並調用 ActivityThread.attach() 方法告訴 ActivityManagerService 咱們建立了一個應用 並將 ApplicationThread 傳給 ActivityManagerService;最後調用 Looper.loop()。
ActivityClientRecord 與 ActivityRecord 是什麼?
記錄 Activity 相關信息,好比:Window,configuration,ActivityInfo 等。
ActivityClientRecord 是客戶端的,ActivityRecord 是 ActivityManagerService 服務端的。
Context 是什麼,ContextImpl,ContextWapper 是什麼?
Context 定義了 App 進程的相關環境,Context 是一個接口,ContextImpl 是子類,ContextWapper 是具體實現。
應用資源是在 Application 初始化的時候,也就是建立 Application,ContextImpl 的時候,ContextImpl 就包含這個路徑,主要就是對就是 ResourcesManager 這個單例的引用。
能夠看出每次建立 Application 和 Acitvity 以及 Service 時就會有一個 ContextImpl 實例,ContentProvider 和B roadcastReceiver 的 Context 是其餘地方傳入的。
因此 Context 數量 = Application 數量 + Activity 數量 + Service 數量,單進程狀況下 Application 數量就是 1。
Instrumentation 是什麼?
管理着組件Application,Activity,Service等的建立,生命週期調用。
Application 是什麼,何時建立的,每一個應用程序有幾個 Application?
Application 是在 ActivityThread.handleBindApplication() 中建立的,一個進程只會建立一個 Application,可是一個應用若是有多個進程就會建立多個 Application 對象。
點擊 Launcher 啓動 Activity 和應用內部啓動 Activity 的區別?
點擊 Launcher 時會建立一個新進程來開啓 Activity,而應用內打開 Activity,若是 Activity 不指定新進程,將在原來進程打開,是否開啓新進程實在 ActivityManagerService 進行控制的,上面分析獲得,每次開啓新進程時會保存進程信息,默認爲 應用包名 + 應用UID,打開 Activity 時會檢查請求方的信息來判斷是否須要新開進程。Launcher 打開 Activity 默認 ACTIVITY_NEW_TASK,新開一個 Activity 棧來保存 Activity 的信息。
Activity 啓動過程,onCreate(),onResume() 回調時機及具體做用?
Activity.onCreate() 完成了 App 進程,Application,Activity 的建立,調用 setContentView() 給 Activity 設置了 layout 佈局。
Activity.onResume() 完成了 Activity 中 Window 與 WindowManager 的關聯,並對全部子 View 進行渲染並顯示。