分析這個(gè)過(guò)程不是單純?yōu)樽咭槐楹瘮?shù)調(diào)用的流程,而是更好的理解平常用到的一些方法旭咽、
對(duì)象的初始化時(shí)間贞奋,對(duì)象創(chuàng)建的個(gè)數(shù),方法的先后順序穷绵,以及每個(gè)類轿塔,
方法背后的作用和目的。主要是一下幾個(gè)問(wèn)題:
- Application是什么時(shí)候創(chuàng)建的,每個(gè)應(yīng)用程序有幾個(gè)Application
- 應(yīng)用的資源路徑什么時(shí)候初始化的
- 應(yīng)用中ContextImpl的個(gè)數(shù)
- Application.attach(),Activity.attach()的調(diào)用時(shí)機(jī)及作用
- Instrumentation的重要性及具體作用
- 點(diǎn)擊Launcher啟動(dòng)Activity和應(yīng)用內(nèi)部啟動(dòng)Activity的區(qū)別
1. 應(yīng)用的安裝過(guò)程
應(yīng)用安裝的時(shí)候,通過(guò)PMS解析apk的AndroidManifest.xml文件,
提取出這個(gè)apk的信息寫(xiě)入到packages.xml文件中勾缭,
這些信息包括:權(quán)限揍障、應(yīng)用包名、icon俩由、APK的安裝位置毒嫡、版本、userID等等采驻。
packages.xml文件位于系統(tǒng)目錄下/data/system/packages.xml。
2. 系統(tǒng)啟動(dòng)開(kāi)啟的服務(wù)
系統(tǒng)的會(huì)在啟動(dòng)時(shí)也可以認(rèn)為開(kāi)機(jī)時(shí)啟動(dòng)常用的服務(wù),
如ActivityManagerService(AMS),
PackageManagerService(PMS),
WindowManagerService(WMS),
以及ServiceManager(SM),
用于管理各種服務(wù),詳細(xì)的管理方式見(jiàn)理解Binder框架匈勋。
同時(shí)桌面Launcher會(huì)為安裝過(guò)的應(yīng)用生成不同的應(yīng)用入口,對(duì)應(yīng)桌面上的應(yīng)用圖標(biāo)礼旅,
下面分析點(diǎn)擊應(yīng)用圖標(biāo)的到應(yīng)用啟動(dòng)的過(guò)程。
這里主要是應(yīng)用端的過(guò)程,服務(wù)端也就是AMS少量涉及,
同時(shí)以大體框架為主,不深入代碼細(xì)節(jié)洽洁。主要分為L(zhǎng)auncher進(jìn)程痘系,AMS進(jìn)程,應(yīng)用程序進(jìn)程饿自。
- Instrumentation: 用于管理應(yīng)用程序和系統(tǒng)(主要與應(yīng)用程序內(nèi)的Activity)的交互過(guò)程汰翠,Instrumentation將在任何應(yīng)用程序運(yùn)行前初始化,每個(gè)進(jìn)程只會(huì)存在一個(gè)Instrumentation對(duì)象昭雌,且每個(gè)Activity都有此對(duì)象的引用复唤,可以通過(guò)它監(jiān)測(cè)系統(tǒng)與應(yīng)用程序之間的所有交互,主要是內(nèi)部交互烛卧。
- **ActivityThread: **App的真正入口,通過(guò)調(diào)用main()App開(kāi)始真正運(yùn)行佛纫,同時(shí)開(kāi)啟消息循環(huán)隊(duì)列,雖然不是一個(gè)真正的線程,但一般所在的線程被稱為UI線程或主線程总放。ActivityThread就是專門(mén)與AMS的進(jìn)行外部交互呈宇。
- ApplicationThread: 應(yīng)用需要和遠(yuǎn)程服務(wù)AMS等通信,而B(niǎo)inder只能單項(xiàng)通信,而AMS等服務(wù)想控制應(yīng)用需要應(yīng)用程序提供一個(gè)Binder接口,ApplicationThread就是這個(gè)Binder接口,用于通過(guò)遠(yuǎn)程服務(wù)調(diào)用本地的方法。
- ActivityManagerProxy: AMS遠(yuǎn)程服務(wù)在本地的代理局雄。
- ApplicationThreadProxy: ApplicationThread在遠(yuǎn)程服務(wù)AMS的代理甥啄。
其實(shí)Launcher本身也是一個(gè)Activity,我們不考慮Launcher的創(chuàng)建過(guò)程炬搭,只分析用戶的應(yīng)用程序的從點(diǎn)擊到Activity啟動(dòng)的過(guò)程蜈漓。上面的這些每個(gè)進(jìn)程只存在一個(gè),如果應(yīng)用存在多個(gè)進(jìn)程宫盔,就會(huì)有多個(gè)實(shí)例迎变。
Launcher所在進(jìn)程,Launcher通過(guò)Binder與ActivityManagerService與通信飘言。
Launcher.startActivitySafely
|
Launcher.startActivity
|
Activity.startActivity
|
Activity.startActivityForResult
|
Instrumentation.execStartActivity
|
ActivityManagerNative.getDefault().startActivity
|
ActivityManagerProxy.startActivity
上面的這些都是在一條調(diào)用鏈上衣形,ActivityManagerProxy是AMS的本地代理,實(shí)際的工作是在遠(yuǎn)程AMS完成的,下面是AMS進(jìn)程谆吴。
借助binder驅(qū)動(dòng)
ActivityManagerService.startActivity-> (AMS)
...
//一系類AMS的調(diào)用鏈和一些與Launcher通過(guò)Binder的互相調(diào)用過(guò)程倒源,此時(shí)仍然未創(chuàng)建應(yīng)用程序的進(jìn)程。
...
* AMS創(chuàng)建一個(gè)新的進(jìn)程句狼,用來(lái)啟動(dòng)一個(gè)ActivityThread實(shí)例笋熬,
* 即將要啟動(dòng)的Activity就是在這個(gè)ActivityThread實(shí)例中運(yùn)行
Process.start("android.app.ActivityThread",...)->
// 通過(guò)zygote機(jī)制創(chuàng)建一個(gè)新的進(jìn)程
Process.startViaZygote->調(diào)用新進(jìn)程的main()
ActivityThread.main->
創(chuàng)建新進(jìn)程的時(shí)候,AMS會(huì)保存一個(gè)ProcessRecord信息腻菇,Activity應(yīng)用程序中的AndroidManifest.xml配置文件中胳螟,我們沒(méi)有指定Application標(biāo)簽的process屬性,系統(tǒng)就會(huì)默認(rèn)使用package的名稱筹吐。每一個(gè)應(yīng)用程序都有自己的uid糖耸,因此,這里uid + process的組合就可以為每一個(gè)應(yīng)用程序創(chuàng)建一個(gè)ProcessRecord丘薛。每次在新建新進(jìn)程前的時(shí)候會(huì)先判斷這個(gè)ProcessRecord是否已存在嘉竟,如果已經(jīng)存在就不會(huì)新建進(jìn)程了,這就屬于應(yīng)用內(nèi)打開(kāi)Activity的過(guò)程了。
AMS通過(guò)開(kāi)啟新的進(jìn)程并調(diào)用ActivityThread.main后洋侨,接下來(lái)就是應(yīng)用程序進(jìn)程了舍扰。
public static void main(String[] args) {
Looper.prepareMainLooper();
//又新建一個(gè)ActivityThread并調(diào)用attach(false)
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
}
thread.attach(false)主要是為了將ApplicationThread通過(guò)Binder驅(qū)動(dòng)"傳遞"到遠(yuǎn)程AMS,也就是綁定,主要
是為了讓AMS能通過(guò)ApplicationThread的代理ApplicationThreadProxy來(lái)調(diào)用ApplicationThread的方法希坚,而本地應(yīng)用程序通過(guò)ActivityManagerProxy來(lái)調(diào)用遠(yuǎn)程ActivityManagerService的方法边苹,相當(dāng)于應(yīng)用程序與
AMS的通信窗口。
注意此時(shí)只創(chuàng)建了應(yīng)用程序的ActivityThread和ApplicationThread,和開(kāi)啟了Handler消息循環(huán)機(jī)制裁僧,其他的都還未創(chuàng)建, ActivityThread.attach(false)又會(huì)最終到AMS的attachApplication勾给,這個(gè)工程其實(shí)是將本地的ApplicationThread傳遞到AMS。然后AMS就可以通過(guò)ApplicationThread的代理ApplicationThreadProxy來(lái)調(diào)用應(yīng)用程序ApplicationThread.bindApplication锅知,通知應(yīng)用程序的ApplicationThread已和AMS綁定播急,可以不借助其他進(jìn)程幫助直接通信了。此時(shí)Launcher的任務(wù)也算是完成了售睹。過(guò)程如下:
應(yīng)用進(jìn)程:
ActivityThread.attach
|
IActivityManager.attachApplication(mAppThread)
|
ActivityManagerProxy.attachApplication(mAppThread)
AMS進(jìn)程:
ActivityManagerService.attachApplication
|
ApplicationThreadProxy.bindApplication
應(yīng)用進(jìn)程:
ApplicationThread.bindApplication
| Handler通信
AplicationThread.handlerBindApplication
ApplicationThreadProxy.bindApplication(...)會(huì)傳來(lái)這個(gè)應(yīng)用的一些信息桩警,如ApplicationInfo,Configuration等,在ApplicationThread.bindApplication里會(huì)待信息封裝成'AppBindData',通過(guò)
sendMessage(H.BIND_APPLICATION, data)
將信息放到應(yīng)用里的消息隊(duì)列里昌妹,通過(guò)Handler消息機(jī)制捶枢,在ActivityThread.handleMeaasge里處理H.BIND_APPLICATION的信息,調(diào)用AplicationThread.handleBindApplication飞崖。
handleBindApplication(AppBindData data) {
Process.setArgV0(data.processName);//設(shè)置進(jìn)程名
...
//初始化mInstrumentation
if(data.mInstrumentation!=null) {
mInstrumentation = (Instrumentation) cl.loadClass(data.instrumentationName.getClassName()).newInstance();
}else {
mInstrumentation = new Instrumentation();
}
//創(chuàng)建Application烂叔,data.info是個(gè)LoadedApk對(duì)象。
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
//調(diào)用Application的onCreate()方法固歪。
mInstrumentation.callApplicationOnCreate(app);
}
LoadedApk類:
public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
String appClass = mApplicationInfo.className;
java.lang.ClassLoader cl = getClassLoader();
//此時(shí)新建一個(gè)Application的ContextImpl對(duì)象蒜鸡,
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//通過(guò)在handleBindApplication創(chuàng)建的mInstrumentation對(duì)象新建一個(gè)Application對(duì)象胯努,同時(shí)進(jìn)行attach。
app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
appContext.setOuterContext(app);
}
Instrumentation類:
public Application newApplication(ClassLoader cl, String className, Context context) {
return newApplication(cl.loadClass(className), context);
}
Instrumentation類:
static public Application newApplication(Class<?> clazz, Context context) {
//實(shí)例化Application
Application app = (Application)clazz.newInstance();
// Application和context綁定
app.attach(context);
return app;
}
//attach就是將新建的ContextImpl賦值到mBase,這個(gè)ContextImpl對(duì)象就是所有Application內(nèi)Context的具體
//實(shí)現(xiàn)逢防,同時(shí)賦值一些其他的信息如mLoadedApk叶沛。
final void attach(Context context) {
mBase = base;
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
這時(shí)Application就創(chuàng)建好了,這點(diǎn)很重要忘朝,很多博客里說(shuō)Application是在performLaunchActivity里創(chuàng)建的灰署,因?yàn)閜erformLaunchActivity也有mInstrumentation.newApplication這個(gè)調(diào)用,newApplication函數(shù)中可看出會(huì)先判斷是否以及創(chuàng)建了Application,如果之前已經(jīng)創(chuàng)建局嘁,就返回已創(chuàng)建的Application對(duì)象溉箕。
ApplicationThreadProxy.bindApplication完成后,同時(shí)在AMS進(jìn)程悦昵,調(diào)用realStartActivityLocked肴茄,接著就通過(guò)ApplicationThreadProxy調(diào)用到應(yīng)用程序進(jìn)程
//AMS進(jìn)程:
ActivityManagerService.realStartActivityLocked
|
ApplicationThreadProxy.scheduleLaunchActivity
//應(yīng)用程序進(jìn)程
ApplicationThread.scheduleLaunchActivity
| Handler通信
sendMessage(H.LAUNCH_ACTIVITY, r);
| handleMassage
ActivityThread.handleLaunchActivity
|
ActivityThread.performLaunchActivity {
//類似Application的創(chuàng)建過(guò)程,通過(guò)classLoader加載到activity.
activity = mInstrumentation.newActivity(classLoader,
component.getClassName(), r.intent);
//因?yàn)锳ctivity有界面旱捧,所以其Context是ContextThemeWrapper類型独郎,但實(shí)現(xiàn)類仍是ContextImpl.
Context appContext = createBaseContextForActivity(r, activity);
activity.attach(context,mInstrumentation,application,...);
//attach后調(diào)用activity的activity方法踩麦。
mInstrumentation.callActivityOnCreate(activity,...)
}
在ActivityThread.handleLaunchActivity里枚赡,接著調(diào)用
|
ActivityThread.performResumeActivity
|
activity.performResume
|
mInstrumentation.callActivityOnResume(this);
|
this.onResume;
activity.onResume就是和Window,View之類的綁定相關(guān)了谓谦,此時(shí)界面就顯示出來(lái)了贫橙。
3. 總結(jié)
Application是在ActivityThread.handleBindApplication中創(chuàng)建的,一個(gè)線程只會(huì)創(chuàng)建一個(gè)Application反粥,但一個(gè)應(yīng)用程序如果有多個(gè)進(jìn)程將會(huì)創(chuàng)建多個(gè)Application對(duì)象卢肃。
應(yīng)用資源是在Application初始化的時(shí)候,也就是創(chuàng)建Application ContextImpl的時(shí)候,ContextImpl就包含這個(gè)路徑才顿,主要就是對(duì)就是ResourcesManager這個(gè)單例的引用莫湘。
可以看出每次創(chuàng)建Application和Acitvity以及Service時(shí)就會(huì)有一個(gè)ContextImpl實(shí)例,ContentProvider和BroadcastReceiver的Context是其他地方傳入的郑气。所以Context數(shù)量=Application數(shù)量+Activity數(shù)量+Service數(shù)量幅垮,單進(jìn)程情況下Application數(shù)量就是1。
attach是依附尾组、貼上的意思忙芒,可以理解為將兩種事物聯(lián)系在一起,上面分析的過(guò)程主要涉及3個(gè)attach讳侨,ActivityThread.attach可以理解為將應(yīng)用程序進(jìn)程的ApplicationThread依附到AMS呵萨,和AMS聯(lián)系起來(lái),用于整個(gè)AMS和應(yīng)用程序的通信跨跨,Application.attach和Activity.attach主要是將新創(chuàng)建的ContextImpl對(duì)象與Application潮峦,Activity,Service等組件聯(lián)系起來(lái),對(duì)組件中其中的Context mBase變量賦值跑杭,以及一些初始化工作铆帽,比如MainHandler的賦值,mWindow的初始化(如果存在)等德谅。
ContextImpl包含資源信息爹橱、對(duì)Context的一些函數(shù)的實(shí)現(xiàn)等。 可以很好的理解窄做,attach需要在Application愧驱,Activity等組件調(diào)用onCreat之前調(diào)用,因?yàn)樾枰韧瓿山M件的初始化工作椭盏。
-
管理著組件Application,Activity组砚,Service等的創(chuàng)建,生命周期調(diào)用掏颊,很重要的一個(gè)類糟红。例如:
//創(chuàng)建Application
mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
//調(diào)用Application的onCreate()方法。
mInstrumentation.callApplicationOnCreate(app);//創(chuàng)建Activity,實(shí)際生命周期的管理乌叶。 mInstrumentation.newActivity(classLoader, component.getClassName(), r.intent); mInstrumentation.callActivityOnCreate(activity); mInstrumentation.callActivityOnOnResume(activity); ...
點(diǎn)擊Launcher時(shí)會(huì)創(chuàng)建一個(gè)新進(jìn)程來(lái)開(kāi)啟Activity盆偿,而應(yīng)用內(nèi)打開(kāi)Activity,如果Activity不指定新進(jìn)程,將在原來(lái)進(jìn)程打開(kāi)准浴,是否開(kāi)啟新進(jìn)程實(shí)在AMS進(jìn)行控制的事扭,上面分析得到,每次開(kāi)啟新進(jìn)程時(shí)會(huì)保存進(jìn)程信息乐横,默認(rèn)為應(yīng)用包名+應(yīng)用UID,打開(kāi)Activity時(shí)會(huì)檢查請(qǐng)求方的信息來(lái)判斷是否需要新開(kāi)進(jìn)程求橄。Launcher打開(kāi)Activity默認(rèn)ACTIVITY_NEW_TASK,新開(kāi)一個(gè)Activity棧來(lái)保存Activity的信息葡公。