閱讀這篇文章,需要對Binder有一定了解。我們通過從桌面啟動(dòng)一個(gè)應(yīng)用講解啟動(dòng)一個(gè)安卓應(yīng)用的流程贪惹。
遠(yuǎn)程調(diào)用
這里要先明確一個(gè)概念,就是所謂的遠(yuǎn)程調(diào)用即跨進(jìn)程調(diào)用寂嘉,安卓大部分情況下通過Binder來實(shí)現(xiàn)奏瞬,其實(shí)現(xiàn)的大致原理,每個(gè)支持Binder的進(jìn)程都有一個(gè)Binder線程池垫释,當(dāng)我們通過Binder遠(yuǎn)程調(diào)用另一個(gè)進(jìn)程的方法時(shí)丝格,例如A進(jìn)程遠(yuǎn)程調(diào)用B進(jìn)程的print方法,其過程是A進(jìn)程把要調(diào)用的方法的方法描述(方法名棵譬,參數(shù)显蝌,身份確認(rèn)信息等)裝進(jìn)一個(gè)Parcel對象發(fā)送到Binder驅(qū)動(dòng),B進(jìn)程中空閑的Binder線程會(huì)去取消息,當(dāng)它取到消息后開始在B進(jìn)程里運(yùn)行曼尊,根據(jù)傳遞過來的方法描述去調(diào)用對應(yīng)的方法酬诀,這樣兩個(gè)進(jìn)程間就完成了一次跨進(jìn)程的調(diào)用,屏蔽掉細(xì)節(jié)就變成了A進(jìn)程調(diào)用了B進(jìn)程的print方法骆撇,這里要注意的是瞒御,A進(jìn)程往Binder驅(qū)動(dòng)寫值后,可以選擇阻塞或不阻塞神郊,也就是Binder的雙向還是單向模式肴裙,若調(diào)用模式為單向模式,A進(jìn)程往Binder驅(qū)動(dòng)寫入值后會(huì)立即返回涌乳,開始執(zhí)行下一條指令蜻懦,不在乎B進(jìn)程是否正確處理了這個(gè)消息,而如果是雙向夕晓,則在A進(jìn)程寫值后會(huì)一直等待宛乃,等待B進(jìn)程處理完成print方法,再往Binder驅(qū)動(dòng)回一條消息蒸辆,A進(jìn)程接收到這個(gè)消息后調(diào)用返回征炼,開始執(zhí)行下一條指令,這個(gè)過程就很像在同一個(gè)進(jìn)程中調(diào)用方法了躬贡,想象若我們在A進(jìn)程中也有同名方法print谆奥,這個(gè)方法的作用是往Binder驅(qū)動(dòng)寫值并等待調(diào)用返回,而B進(jìn)程收到消息并執(zhí)行了B進(jìn)程的print并在Binder驅(qū)動(dòng)中寫回值逗宜,現(xiàn)在A進(jìn)程收到寫回的消息雄右,print返回,執(zhí)行下一條指令纺讲,其過程就像是在A進(jìn)程里執(zhí)行了B進(jìn)程的print方法一樣擂仍,足以讓使用者忽略掉這其實(shí)經(jīng)過了跨進(jìn)程的通信,而只是調(diào)用了一次普通方法熬甚。
幾個(gè)重要的類:
- ActivityManagerService (簡稱AMS)逢渔,運(yùn)行在system_server 進(jìn)程,其實(shí)質(zhì)為一個(gè)Binder服務(wù)端乡括,與之對應(yīng)的是 ActivityManagerProxy(簡稱AMP)肃廓,運(yùn)行在各個(gè)應(yīng)用即客戶端,封裝了Binder操作诲泌,應(yīng)用使用這個(gè)類遠(yuǎn)程調(diào)用AMS
- ActivityThread盲赊,應(yīng)用進(jìn)程java層的根節(jié)點(diǎn),其main方法為應(yīng)用進(jìn)程java層的起點(diǎn)敷扫,完成應(yīng)用啟動(dòng)初始化工作哀蘑,并通過Binder和Handler負(fù)責(zé)應(yīng)用與system_server進(jìn)程間通信的消息轉(zhuǎn)發(fā)工作
- ApplicationThread,工作在應(yīng)用進(jìn)程,ActivityThread的成員變量绘迁,負(fù)責(zé)應(yīng)用與system_server間的通信合溺,與AMS功能對應(yīng),其作為Binder服務(wù)端缀台,system_server通過ApplicationThreadProxy遠(yuǎn)程調(diào)用ApplicationThread棠赛,從而調(diào)用ActivityThread的各個(gè)方法,經(jīng)過ActivityThread的轉(zhuǎn)發(fā)膛腐,從而控制整個(gè)應(yīng)用
- Instrumentation睛约,ActivityThread對Activity生命周期的調(diào)用具體通過這個(gè)類實(shí)現(xiàn)
以下我們通過Launcher啟動(dòng)一個(gè)應(yīng)用來演示一個(gè)應(yīng)用的啟動(dòng)過程:
startActivity
通過Launcher啟動(dòng)一個(gè)帶視圖的應(yīng)用,即啟動(dòng)一個(gè)Activity,此時(shí)這個(gè)Activity所需要依附的進(jìn)程還未啟動(dòng):
首先我們在Launcher的main線程(即所謂UI線程)里調(diào)用startActivity,這個(gè)方法最終通過Instrumentation調(diào)用ActivityManagerProxy的同名方法碟狞,通過AMP遠(yuǎn)程調(diào)用AMS(ActivityManagerService的同名方法)耕姊,
打印main 線程的調(diào)用棧,調(diào)用從下到上棍丐,Activity的startActivity方法最終調(diào)到了AMP的startActivity误辑,作為Binder客戶端這個(gè)startActivity的實(shí)現(xiàn)就是打包各種參數(shù)并傳到Binder驅(qū)動(dòng)
main:
showStartingWindow
調(diào)到這里,因?yàn)锳MS和AMP是實(shí)現(xiàn)了同一個(gè)接口的歌逢,所以在AMS作為服務(wù)端也有同名方法巾钉,下面是在system_server進(jìn)程中,一個(gè)被啟動(dòng)來處理這個(gè)消息的Binder線程的調(diào)用棧:
可以看到Binder在倒數(shù)第四行秘案,調(diào)用了startActivity砰苍,下面三個(gè)函數(shù)啟動(dòng)的作用就是取出并解析傳過來的數(shù)據(jù),然后交給對應(yīng)的方法處理阱高,這里根據(jù)傳過來的方法id調(diào)用到了ActivityManagerService的startActivity方法赚导,再經(jīng)過層層調(diào)用,通知WMS顯示startingWindow赤惊,所謂startingWindow吼旧,就是系統(tǒng)為了應(yīng)用之間的過渡平滑,應(yīng)用在啟動(dòng)之前未舟,預(yù)先啟動(dòng)起來的預(yù)覽視圖圈暗,這是應(yīng)用的MainActivity的theme里面配置的,這個(gè)視圖的顯示速度很快裕膀,因?yàn)槠洳粚儆趹?yīng)用進(jìn)程员串,不需要等待應(yīng)用初始化,往往在點(diǎn)擊應(yīng)用圖標(biāo)的瞬間就能顯示昼扛。
schedulePauseActivity
再看這次調(diào)用中另一個(gè)方法的調(diào)用棧:
調(diào)到了ApplicationThreadProxy(ATP)的schedulePauseActivity方法寸齐,看名字,就知道這又是一個(gè)Binder客戶端,這個(gè)Binder客戶端對應(yīng)的Binder服務(wù)端在Launcher的進(jìn)程里访忿,名字叫ApplicationThread瞧栗,system_server進(jìn)程通過這個(gè)ATP可以跨進(jìn)程調(diào)用Launcher的方法(每個(gè)應(yīng)用進(jìn)程都有一個(gè)ApplicationThread,可見system_server進(jìn)程存有所有由它管理的進(jìn)程的ATP海铆,因?yàn)樗枰ㄟ^這些ATP去管理所有應(yīng)用進(jìn)程迹恐,如控制應(yīng)用組件的生命周期),到這里卧斟,整個(gè)調(diào)用鏈從Launcher進(jìn)程的main線程殴边,到system_server進(jìn)程,現(xiàn)在又要回到Launcher珍语,但是要注意锤岸,通過Binder再調(diào)回去之后,ApplicationThread的schedulepauseActivity方法就是在一個(gè)另起的Binder線程里了板乙,main線程會(huì)繼續(xù)執(zhí)行它后續(xù)的指令不受影響是偷,我們現(xiàn)在查看Launcher里面這個(gè)另起的Binder線程的調(diào)用棧:
這里可以看到,在ApplicationThread的schedulepauseActivity方法里的處理募逞,Binder線程往Handler里發(fā)送了一條消息蛋铆,這個(gè)消息將由main線程來處理
activityPaused
此時(shí)我們查看主線程收到這個(gè)這個(gè)message之后的處理:
可以看到收到在handleMessage里,主線程調(diào)用了ActivityThread的handlePauseActivity放接,我們來看一下handlePauseActivity的實(shí)現(xiàn)刺啦,下面是幾行關(guān)鍵代碼:
performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
...
...
// Tell the activity manager we have paused.
if (!dontReport) {
try {
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
performPauseActivity最終會(huì)調(diào)用到Activity的onPause方法(在這之前還會(huì)先調(diào)用Fragment的onPause),然后調(diào)用到ActivityManagerNative.getDefault().activityPaused(token)
也就是我們上圖調(diào)用棧所示的AMP的activityPaused方法纠脾。
到這里玛瘸,整個(gè)流程還沒有走到一個(gè)新的Activity的創(chuàng)建甚至連新的應(yīng)用進(jìn)程都還沒有創(chuàng)建,Launcher與system_server兩個(gè)進(jìn)程之間已經(jīng)經(jīng)過了來回各一次跨進(jìn)程的調(diào)用苟蹈。而到現(xiàn)在對應(yīng)用開發(fā)者能實(shí)際感知的到的很重要的一點(diǎn)糊渊,就是當(dāng)前Activity和Fragment走到到了生命周期onPause。應(yīng)用開發(fā)者該在這里做狀態(tài)保存工作了慧脱。
Process.start
回到AMP的activityPaused方法再来,現(xiàn)在Launcher的主線程又要遠(yuǎn)程調(diào)用AMS,system_server端會(huì)把這個(gè)調(diào)用交個(gè)一個(gè)空閑Binder線程去處理磷瘤,我們查看其調(diào)用棧:
注意 ActivityStackSupervisor中的startSpecificActivityLocked方法芒篷,這個(gè)方法在這里會(huì)進(jìn)入分水嶺,這里會(huì)檢查這個(gè)Activity需要依附的進(jìn)程有沒有被創(chuàng)建采缚,如果已經(jīng)創(chuàng)建针炉,則會(huì)進(jìn)入realStartActivityLocked方法,遠(yuǎn)程調(diào)會(huì)Launcher進(jìn)程扳抽,實(shí)例化要啟動(dòng)的Activity篡帕,并依次調(diào)用其onCreate殖侵,onStart,onResume生命周期方法(當(dāng)然其中各個(gè)方法的調(diào)用都是經(jīng)過各個(gè)類層層調(diào)用镰烧,但如果從應(yīng)用開發(fā)的角度來說就是這個(gè)調(diào)用順序拢军,期間不需要再由AMS干預(yù)),但對應(yīng)進(jìn)程如果不存在怔鳖,則還需要調(diào)用AMS的startProcess創(chuàng)建這個(gè)進(jìn)程茉唉,如上調(diào)用棧棧頂走到Process類的start方法,注意調(diào)用這個(gè)方法時(shí)傳遞的一個(gè)參數(shù)结执,entryPoint度陆,這里是android.app.ActivityThread
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
checkTime(startTime, "startProcess: returned from zygote!");
傳遞這個(gè)參數(shù),新進(jìn)程在啟動(dòng)之后就會(huì)調(diào)用這個(gè)類的main方法作為java層的起點(diǎn)(java層第一個(gè)方法應(yīng)該是ZygoInit的main,但在調(diào)用棧中根據(jù)傳過來的參數(shù)分成別反射調(diào)用了SystemServer和ActiviThread的main献幔,我們習(xí)慣上把這兩個(gè)函數(shù)當(dāng)成起點(diǎn))懂傀,至于Process.start的實(shí)現(xiàn),這里先不深究蜡感,大致過程蹬蚁,zygote進(jìn)程與system_server之間通過socket通信,要?jiǎng)?chuàng)建進(jìn)程時(shí)郑兴,system_server 進(jìn)程里通過往socket寫入消息缚忧,zygote接收到消息后fork出一個(gè)進(jìn)程,最終會(huì)調(diào)用ActivityThread的main函數(shù)杈笔,下面看一下創(chuàng)建進(jìn)程需要的參數(shù):
* Starts a new process via the zygote mechanism.
*
* @param processClass Class name whose static main() to run
* @param niceName 'nice' process name to appear in ps
* @param uid a POSIX uid that the new process should setuid() to
* @param gid a POSIX gid that the new process shuold setgid() to
* @param gids null-ok; a list of supplementary group IDs that the
* new process should setgroup() to.
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SELinux information for the new process.
* @param abi the ABI the process should use.
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
其實(shí)現(xiàn):
/**
* See com.android.internal.os.ZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
writer.flush();
---
---
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
往流里寫入值各種參數(shù),再從流里讀回返回信息糕非,具體的實(shí)現(xiàn)就是zygote進(jìn)程的事了蒙具。
至此,一個(gè)應(yīng)用進(jìn)程就已經(jīng)啟動(dòng)朽肥,我們進(jìn)入android.app.ActivityThread的main方法禁筏,我們可以當(dāng)這里是應(yīng)用的起點(diǎn)。
ActivityThread.main
從 ActivityThread 的main方法開始衡招,應(yīng)用進(jìn)入 java 層篱昔,應(yīng)用在main里面的關(guān)鍵代碼:
public static void main(String[] args) {
... ...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
... ...
Looper.loop();
}
主要的三件事:
調(diào)用Looper.prepareMainLooper 創(chuàng)建mainLooper并賦值給Loop (這個(gè)looper的MessageQueue不能quit)靜態(tài)變量 sMainLooper ,這樣應(yīng)用可以在任何地方拿到主線程的Looper
-
創(chuàng)建ActivityThread實(shí)例始腾,并調(diào)用attach州刽,這兩步很關(guān)鍵,首先浪箭,ActivityThread對象創(chuàng)建時(shí)穗椅,會(huì)創(chuàng)建ResourcesManager的單例對象,還會(huì)創(chuàng)建 ApplicationThread 對象作為匿名Binder服務(wù)端用以跟system_server進(jìn)程通信奶栖,在thread.attach(false) 中通過AMP把 這個(gè)對象注冊到AMS:
final IActivityManager mgr = ActivityManagerNative.getDefault(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }
AMS 對各應(yīng)用組件的生命周期管理就是通過這個(gè)對象實(shí)現(xiàn)的匹表,AMS會(huì)通過這個(gè)ApplicationThread 對象遠(yuǎn)程調(diào)用應(yīng)用進(jìn)程的方法從而實(shí)現(xiàn)管理门坷。
?
另外在attach 方法里ActivityThread對象會(huì)把自己賦值給靜態(tài)變量sCurrentActivityThread,在應(yīng)用開發(fā)中可以通過反射ActivityThread 直接拿到這個(gè)靜態(tài)變量對象或反射后調(diào)用靜態(tài)方法 currentActivityThread()拿到應(yīng)用的ActivityThread 對象袍镀,從而可以拿到其成員變量mAppThread默蚌,mInstrumentation,插件化方案可能需要hook這兩個(gè)對象苇羡。
?
主線程啟動(dòng)loop绸吸,進(jìn)入循環(huán),等待其他線程往消息隊(duì)列里發(fā)消息
attachApplication
遠(yuǎn)程調(diào)用AMS的attachApplication方法后宣虾,會(huì)輾轉(zhuǎn)到系統(tǒng)進(jìn)場中AMS的attachApplicationLocked惯裕,通過ProcessRecord.makeActive將這個(gè)IApplicationThread 傳入與進(jìn)程相關(guān)的ProcessRecord,這個(gè)對象與每個(gè)用戶進(jìn)程相對應(yīng)绣硝, 這樣system_server進(jìn)程就持有了應(yīng)用的一個(gè)Binder蜻势,之后就可以通過這個(gè)Binder給應(yīng)用發(fā)消息,從而管理應(yīng)用了鹉胖。
bindApplication
之后system_server進(jìn)程通過thread.bindApplication遠(yuǎn)程調(diào)用應(yīng)用進(jìn)程的ApplicationThread的同名方法握玛,同之前的其他調(diào)用,應(yīng)用進(jìn)程里bindApplication這個(gè)方法是運(yùn)行在某個(gè)binder線程的甫菠,這里這個(gè)Binder線程調(diào)用這個(gè)方法通過handler即成員變量mH把消息丟給了主線程挠铲,主線程收到消息轉(zhuǎn)到ActivityThread的handleBindApplication方法,查看調(diào)用棧
system_server:
從attachApplication 調(diào)用到 bindApplication寂诱,整個(gè)調(diào)用過程由應(yīng)用發(fā)起拂苹,將ApplicationThread傳遞給AMS(attachApplication這個(gè)方法最主要的功能就是把ApplicatioThread傳遞給了system_server進(jìn)程,從此應(yīng)用進(jìn)程和system_server進(jìn)程可以互相通信)痰洒,然后AMS拿到這個(gè)ApplicationThread的客戶端ATP瓢棒,調(diào)用其bindApplication,這樣調(diào)用又走回了應(yīng)用丘喻,應(yīng)用會(huì)在bindApplication里面做一些初始化工作脯宿,如實(shí)例化Instrumentation,實(shí)例化Application泉粉,并賦值給mInitialApplication = app;這個(gè)變量的賦值是唯一的连霉,只會(huì)有這一次,也就是一個(gè)進(jìn)程應(yīng)用進(jìn)程只會(huì)有一個(gè)mInitialApplication嗡靡,但是跺撼,這并不意味著一個(gè)進(jìn)程只有一個(gè)Application實(shí)例,一個(gè)進(jìn)程里是有可能創(chuàng)建多個(gè)Application實(shí)例的讨彼,比如下面要講的handleLaunchActivity方法财边,每啟動(dòng)一個(gè)Activity,都會(huì)去判斷這個(gè)Activity對應(yīng)的Application有沒有被實(shí)例化点骑,若沒有酣难,則會(huì)創(chuàng)建谍夭,并添加到mAllApplications列表,這種情況會(huì)在兩個(gè)應(yīng)用共用進(jìn)程時(shí)出現(xiàn)憨募。mInitialApplication賦值后紧索,會(huì)作為參數(shù)啟動(dòng)provider。
bindApplication:
// Allow disk access during application and provider setup. This could
// block processing ordered broadcasts, but later processing would
// probably end up doing the same disk access.
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
//這里只會(huì)實(shí)例化Application菜谣,而不會(huì)調(diào)用其onCreate
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
//初始化ContentProvider
installContentProviders(app, data.providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing.
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
throw new RuntimeException(
"Exception thrown in onCreate() of "
+ data.instrumentationName + ": " + e.toString(), e);
}
try {
//調(diào)用Application.onCreate
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
if (DEBUG_PROVIDER) {
StringBuilder buf = new StringBuilder(128);
buf.append("Pub ");
buf.append(cpi.authority);
buf.append(": ");
buf.append(cpi.name);
Log.i(TAG, buf.toString());
}
//這個(gè)context就是mInitialApplication珠漂,這里會(huì)實(shí)例化provider
//installProvider方法里會(huì)為每個(gè)provider賦值一個(gè)context,這個(gè)Context有可能是 //mInitialApplication本身尾膊,也可能是根據(jù)不同包名重新創(chuàng)建的
//這個(gè)方法里還會(huì)調(diào)用ContentProvider的onCreate生命周期方法
//要注意媳危,直到這里,我們還在ActivityThread的bindApplication方法里冈敛,這是AMS對應(yīng)用進(jìn)程的第 //一個(gè)遠(yuǎn)程調(diào)用待笑,我們雖然已經(jīng)創(chuàng)建了Application實(shí)例,但我們還沒有調(diào)用其onCreate抓谴,還沒有任何 //Activity和Service組件被實(shí)例化暮蹂,而在這里,所有ContentProvider已經(jīng)完成創(chuàng)建癌压,調(diào)用 //onCreate并注冊到AMS了
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
//注冊到AMS
try {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
bindApplication完成后仰泻,到這里應(yīng)用進(jìn)程已經(jīng)先后完成了Application的實(shí)例化,ContentProvider的實(shí)例化和onCreate生命周期滩届,Application的onCreate生命周期集侯。
scheduleLaunchActivity
注意AMS里面 attachApplicationLocked方法,除了遠(yuǎn)程調(diào)用ActivityThread的bindApplication外帜消,還調(diào)用了其scheduleLaunchActivity方法棠枉,這個(gè)方法最終會(huì)實(shí)例化一個(gè)Activity,調(diào)用其生命周期方法券犁。先來看system_server端的調(diào)用棧:
下面是上面兩次遠(yuǎn)程調(diào)用,轉(zhuǎn)到應(yīng)用進(jìn)程后對應(yīng)的兩次處理汹碱,都是Binder線程收到消息后重新丟到主線程里后主線程的調(diào)用棧粘衬。
handleLaunchActivity是應(yīng)用進(jìn)程收到的第二個(gè)system_server的遠(yuǎn)程調(diào)用(通過handler中轉(zhuǎn)過的),我們來看一下主線程在handleLaunchActivity里做了什么:
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
... ...
// Initialize before creating the activity
WindowManagerGlobal.initialize();
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
... ...
}
performLaunchActivity得到了一個(gè)Activity咳促,之后調(diào)用了handleResumeActivity稚新,這里方法里就會(huì)調(diào)用Activity的onResume生命周期方法。再看在這之前performLaunchActivity的邏輯:
Activity activity = null;
try {
//反射實(shí)例化Activity
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
//拿到Application跪腹,這個(gè)Application是之前已經(jīng)創(chuàng)建的褂删,若對應(yīng)的Application之前沒有創(chuàng)建
//則會(huì)先實(shí)例化,這種情況出現(xiàn)在一個(gè)應(yīng)用進(jìn)程承載多個(gè)應(yīng)用時(shí)冲茸,啟動(dòng)第一個(gè)之外的其他應(yīng)用時(shí)應(yīng)用進(jìn)程
//已經(jīng)創(chuàng)建并與AMS綁定屯阀,所以不會(huì)走bindApplication方法缅帘,所以新應(yīng)用對應(yīng)的Application是還沒有
//創(chuàng)建的,需要先創(chuàng)建难衰。
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
... ...
if (activity != null) {
//這里實(shí)際是一個(gè)ContextImpl實(shí)例
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
//典型裝飾者模式钦无,Activity的很多功能會(huì)委托給ContextImpl實(shí)例實(shí)現(xiàn)
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
//調(diào)用Activity.onCreate
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
... ...
//Activity.onStart
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
///Activity.onRestoreInstanceState
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
利用Instrumentation反射創(chuàng)建Activity,然后r.packageInfo.makeApplication(false, mInstrumentation)盖袭,這個(gè)方法會(huì)判斷當(dāng)前應(yīng)用(注意是應(yīng)用而不是進(jìn)程)有沒有Application實(shí)例失暂,若沒有,則創(chuàng)建鳄虱,創(chuàng)建其ContextImpl弟塞,調(diào)用其生命周期方法onCreate,注意Application app = r.packageInfo.makeApplication(false, mInstrumentation);
這個(gè)方法拙已,其實(shí)現(xiàn)末尾處有一段判斷
if (mApplication != null) {
return mApplication;//這里作為應(yīng)用進(jìn)程第一個(gè)被創(chuàng)建的Application决记,在bindApplication里就完成了實(shí)例化和生命周期onCreate,這里直接返回
}
//這里省略了反射實(shí)例化Application的代碼
... ...
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
... ...
}
}
若傳遞的instrumentation不為空悠栓,則調(diào)用其onCreate霉涨,之前在bindAppliction里面調(diào)用傳遞參數(shù)是空,所以只是實(shí)例化了Application惭适,這里在參數(shù)不為空笙瑟,如果這個(gè)Application不是應(yīng)用進(jìn)程的第一個(gè)Application,那么會(huì)在這里實(shí)例化并調(diào)用onCreate 癞志。
Activity.attach
可以看出往枷,如果同一個(gè)進(jìn)程運(yùn)行多個(gè)應(yīng)用的話,除了一個(gè)應(yīng)用外凄杯,一個(gè)應(yīng)用的第一個(gè)Activity會(huì)比Application先實(shí)例化错洁,只是生命周期的調(diào)用時(shí)機(jī)在Application后面。Activity的創(chuàng)建過程是先反射創(chuàng)建其實(shí)例戒突,然后作為參數(shù)創(chuàng)建其委托對象ContextImpl屯碴,然后attach這個(gè)對象,將ContextImpl作為自己的成員變量膊存,很多功能會(huì)委托給這個(gè)對象實(shí)現(xiàn)导而,除此之外Activity.attach方法還會(huì)為創(chuàng)建PhoneWindow作為成員變量。
callActivityOnCreate
attach之后隔崎,來到mInstrumentation.callActivityOnCreate今艺,這里會(huì)調(diào)用Activity的onCreate,activity.performStart爵卒,調(diào)用activity.onStart虚缎,mInstrumentation.callActivityOnRestoreInstanceState,調(diào)用Activity.onRestoreInstanceState钓株,performLaunchActivity 方法返回之后实牡,handleLaunchActivity繼續(xù)走到ActivityThread.handleResumeActivity陌僵,調(diào)用Activity.onResume 。這些方法里面還夾雜Fragment的管理铲掐,這里先忽略拾弃。
scheduleStopActivity
至此,完成這個(gè)應(yīng)用啟動(dòng)需要走的所有生命周期摆霉,而Launcher我們只分析到OnPause豪椿,一個(gè)完整的過程它是需要走到onStop才對的,我們看下在Launcher的ActivityThread調(diào)用ams的activityPaused里面携栋,AMS除了通知Zygote孵化新進(jìn)程外還做了什么搭盾,我們先回顧下創(chuàng)建應(yīng)用進(jìn)程的調(diào)用棧,:
Launcher在走完onPause生命周期后婉支,就會(huì)通知AMS去啟動(dòng)新的Activity鸯隅,而啟動(dòng)時(shí)發(fā)現(xiàn)對應(yīng)的進(jìn)程還沒創(chuàng)建,所以這里先創(chuàng)建進(jìn)程向挖,這之后AMS就等著新啟動(dòng)的進(jìn)程走到j(luò)ava層的attach方法來注冊自己蝌以。
我們看上面這個(gè)調(diào)用里,在completePausedLocked方法里何之,還有另一個(gè)調(diào)用跟畅,看下面的調(diào)用棧:
往Handler里面發(fā)了一條消息,這個(gè)handler攜帶的消息會(huì)在system_server的一個(gè)Looper子線程里被處理溶推,我們看其處理的調(diào)用棧:
這里就會(huì)去調(diào)用經(jīng)過Binder和Handler中轉(zhuǎn)徊件,就會(huì)走到Launcher的的onStop生命周期了。
回顧
到這里大家可以回顧一下兩個(gè)應(yīng)用的的Activity生命周期是怎么走的蒜危,首先Launcher向AMS發(fā)消息要啟動(dòng)一個(gè)Activity虱痕,AMS發(fā)消息回來,讓Launcher走到onPause辐赞,然后Launcher告訴AMS onPause已經(jīng)調(diào)用部翘,這個(gè)“告訴”的過程中往system_server的一個(gè)Looper線程中發(fā)了條消息,這個(gè)消息收到后就會(huì)再回過來調(diào)用到Launcher的onStop响委,同時(shí)新思,還通過Process.start通知Zygote孵化出要啟動(dòng)的應(yīng)用進(jìn)程,應(yīng)用進(jìn)程啟動(dòng)后通過AMP.attachApplication注冊自己的ApplicationThread到AMS晃酒,AMS回過來通過ApplicationThread調(diào)用了應(yīng)用的bindApplication和scheduleLaunchActivity表牢,前者完成Application對象實(shí)例化窄绒,Instrumentation初始化贝次,ContentProvider的實(shí)例化和onCreate調(diào)用,Application的onCreate的調(diào)用彰导,后者完成Activity的實(shí)例化蛔翅,以及onCreate,onStart,onResume 連續(xù)三個(gè)生命周期的調(diào)用敲茄。這里可以看出兩點(diǎn):
- Application的實(shí)例化是在ContentProvider之前的,但是Application的onCreate調(diào)用時(shí)機(jī)其實(shí)是在ContentProvider的onCreate之后的山析。
- Launcher的onStop的調(diào)用其實(shí)和被啟動(dòng)的應(yīng)用的Activity的生命周期是沒有絕對的順序的堰燎,但它的onPause肯定是要先被調(diào)用的(而在這之前還會(huì)通知WMS顯示應(yīng)用的startingWindow),其調(diào)用時(shí)機(jī)甚至比新應(yīng)用進(jìn)程的創(chuàng)建還早笋轨,AMS會(huì)等它被調(diào)用后才通知Zygote孵化新進(jìn)程(其實(shí)也不絕對秆剪,想象如果onPause耗時(shí)太久,必然會(huì)影響新進(jìn)程的啟動(dòng)了爵政,這里AMS會(huì)有超時(shí)機(jī)制仅讽,超過500毫秒還沒有通知AMS activityPaused,AMS就會(huì)不再等待钾挟,直接創(chuàng)建新進(jìn)程)