一、概述
從我們在屏幕上點擊一個App快捷圖標開始到app打開到啟動頁不過短短的500~1500毫秒之間。但是在這個過程的底層卻做了非常多的事情,光大步驟就分了7步。其中AMS在這里面占據了非常重要的角色,基本上每一步都離不開他。
有些同學可能有疑問,了解這些東西有啥用啊?作用還是很大的,比如:我們了解了app的啟動流程后就可以針對啟動流程的原理做啟動速度優化,了解了內部的Activity的啟動原理后就可以做插件化實現熱更新的同時還可以加深你對整個系統的理解,從而可以讓編程的基本功更加扎實,不僅知其然還能知其所以然。不要懷疑,無論是開發中的方案設計、系統或者App優化都是先從原理了解的,主要指導了內部原理,就可以針對具體的問題,做針對性的優化。
下面具體講一下從點擊Launcher圖標到app啟動的原理,我們先看原理然后再看具體的源代碼流程。
二、流程分析
我們經常看到的手機App圖標頁業界稱之為Launcher,Launcher是一個Activity,只不過里面放置的是App啟動圖標。業界習慣上把這個Activity所在的進程稱之為Launcher進程,下面在將的時候也按照業界標准來(為了更接地氣)。Launcher中為每個App圖標定義了啟動這個App所需要的Intent信息,如:
action:android.intent.action.MAIN
category:android.intent.category.LAUNCHER
這些信息是App在安裝或者系統啟動的時候由PackageManagerService(PMS)從apk包中的AndroidMainifest.xml中解析出來的。
從點擊Launcher圖標到app啟動經歷了七大步。
1.Launcher通知AMS要啟動某個App,並把圖標中攜帶的啟動信息也發給AMS。
2.AMS收到消息后保存App圖標中攜帶的啟動信息,並同坐App進程,我知道了,你可以休眠了。
3.Launcher進程收到AMS發過來的消息后,Launcher Activity進入休眠(pause),然后通知AMS我已休眠
4.AMS收到Launcher進程的休眠信息后,會檢查目標App進程是否啟動,如果啟動就直接打開,如果沒有啟動就利用Proccess.start方法創建ActiivtyThread對象並執行其Main方法
5.App進程創建完成后會通知AMS App進程已創建完成,並把ActivityThread對象發送給AMS
6.AMS收到App進程發送過來的數據后會從第二步中翻出保存的App啟動信息(具體要啟動哪個Activity),然后通知app進程創建指定的Activity
7.App進程收到啟動信息后,會根據啟動信息創建Activity對象並調用其onCreate方法,然后創建Context對象並與Activity做關聯。
到此,從點擊Launcher到App啟動的過程就完成了。
三、針對上面的七步,結合相關的類拆分開了進行分析。
第一步:Launcher進程通知AMS要啟動某個Activity,並把啟動信息發送給AMS。
Launcher所在Activity首先會調用自身的startActivitySafely方法,startActivitySafely方法又會調用Activity的startActivity方法,startActvity內部又會調用startActivityForResult方法。在startActivityForResult內部又會調用Instrumentation.execStartActiivty,execStartActivity又會調用ActivityManagerNative.getDefault().startActivity方法,把啟動信息發送給AMS。
其中有兩點需要注意:1.ActivityManagerNative.getDefault()方法的返回值是IActivityManger接口,其實現類是ActivityMangerProxy對象,即AMS在app中的代理對象。ActiivtyMangerNative和ActivityManagerProxy都實現了IActivityManager接口。IActivityManger接口中定義了app中四大組件的所有生命周期函數。
所以這里真正把Activity的啟動信息發送給AMS是ActivityManagerProxy(AMS的代理對象)。
第二步:AMS收到消息后保存啟動信息並通知Launcher進程進入pause狀態
AMS通過App的代理對象ApplicationThreadProxy對象的schedulePauseActivity通知Launcher進程把LauncherActivity暫停。
ps: 在這個步驟中AMS會檢查目標Activity是否在AndroidManifest.xml中注冊了,如果沒有注冊就會提示拋異常,Activity not found。
第三步:Launcher進程收到AMS發過來的消息后,把LauncherActivity pause,並通知AMS已經暫停
Launcher進程的ApplicationThread對象收到消息后會調用ActivityThread的sendMessage方法向ActivityThread內部的H發送消息,H在接收到消息后會取出數據並調用自身的handleMessage方法,在handleMessage方法內部又會調用ActivityThread的handlePauseActivity方法把Activity方法暫停。
ps:在handlePauseActivity內部會調用ActivityThread的mActiviities集合並取出要pause的Activity進行pause,並通知AMS Activity已暫停。
第四部:AMS收到Launcher的已暫停消息后,會檢查要啟動的Activity所在的進程是否已經啟動了,如果已經啟動了就打開,如果沒有啟動就啟動。
AMS會調用Process.start(android.app.ActivityThread)來啟動一個新的進程
第五步:App進程啟動好以后會通知AMS進程已經啟動好了
AMS調用你Process.start方法會創建一個ActivityThread對象,並調用其main函數,然后再main函數內部會初始化主線程Looper即MainLooper,並創建Application對象。然后通過Instrumentation.newApplication通過反射創建Application對象,並創建ContextImpl通過Application的attach方法與Application進行綁定,最終會調用Instrumentation.callApplicationOnCreate執行Application的onCreate函數進行一些初始化的工作。完成后會通知AMS進程已經啟動好了,並把ActivityThread對象發送給AMS
第六步:AMS收到app進程啟動成功的消息后,通知App進程要啟動哪個具體的Activity(在第二步中接收到的啟動信息)
AMS把收到的ActivityThread對象包裝成為ApplicatonThreadProxy對象,並調用其scheduleLauncherActivity方法,把具體要啟動的Activity告訴App進程
第七部:App進程收到AMS具體要啟動的信息后啟動Activity並創建Context對象與Activity做關聯。
app進程的ApplicationThread收到消息后會調用ActiivtyThread的sendMessage方法,給H發送消息,H收到消息后會調用自身的handleMessage方法,在handleMessage方法的內部又會調用ActivityThread的handleLaunchActivity方法,handleLauncherActivity方法的內部又會調用performLaunchActivity方法創建activity和context並將其做關聯。
ps:在performLaunchActiivty的內部會首先通過Instrumentation.newActiviity方法通過反射創建Actiivty實例,然后創建Context對象並通過Activity的attach方法把Actiivty和Context綁定到一塊。然后調用Instrumentation.callActiivtyOnCreate函數把執行Actiivty的onCreate函數。
到此,整個流程就分析完成了。
總結:以上的流程其實經歷了三個進程Launcher進程、SystemServer進程(AMS所在的進程)和App進程。前三步都是Launcher進程和AMS進行通信,后四步都是AMS和App進程進行通信。大家仔細理解一下上面的這些流程其實都是Activity反反復復的和AMS機型握手的過程(通過Binder進行的IPC過程)。
下面給出一個類的執行流程圖:
上面的過程是三個進程間的通訊。如果打開同一個App中的Activity流程是類似的。舉個栗子:ActivityA要求啟動ActivityB會經歷5步
1.ActiivtyA通知AMS要啟動ActivityB,並把要啟動的ActivityB的信息發送給AMS
2.AMS收到啟動信息后保存記錄,並通知ActivityA,你可以去休眠了
3.ActivityA收到消息后進入休眠狀態並通知AMS,我已休眠
4.AMS收到ActivityA的休眠信息,取出保存的ActivityB的信息,並檢查到ActiivtyA和ActivityB在同一個進程中,通知App啟動ActivityB
5.App進程收到消息后啟動ActivityB。流程結束。相關的類關系,和上面的非常類似,就不過多贅述了。
講到這里順便講一下Context家族樹,不多說,貼出一張圖,大家就立馬能夠看明白。
ps:說明一下,Context是一個抽象類。ContextWrapper繼承了Context類並實現了其方法。但是不管是Context還是ContextWrapper內部都沒有做具體的工作,具體的工作都是交給ContextImpl來完成的.
例如ContextWrapper.startActivity
@Override public void startActivity(Intent intent) { mBase.startActivity(intent); }
mBase指的就是ContextImpl對象。另外要注意ContextImpl對開發是不可見的。