AMS之開機啟動Launcher、開機廣告後啟動Launcher、Launcher啟動activity
activity的啟動關閉最終都是由AMS控制的。從刷了rom到第一開機引導、launcher啟動、點選啟動特定app,這之間ams控制開機引導activity、launcher、app啟動有什麼不同嗎?還是same流程?下面讓我們一探究竟。
文章分三部分:第一部總體概述、第二部分流程圖、第三部分講解下具體一些細節點。
一、總體概述:
無所做什麼,一定先是瞭解概況,然後在看細節,不然就是隻見樹木不見森林。
這裡就會有區分,開機廣告/開機引導類似(電視現在都是先播放廣告,然後啟動launcher)、launcher、其他app;
本文也從這個角度進行一下分析。
簡單的說,啟動一個activity,先看是否已經有activity是resume狀態,沒有則直接啟動;有則先pause掉當前resume的,然後啟動想啟動的;這裡也不關注activity如何呼叫到AMS的,只關注AMS內部如何排程最終啟動相關的activity的。
除了開機廣告,launcher和app啟動都是兩個階段:一pause當前resume的activity;二resume需要啟動的activity。(先finish後pause)
牢記,就這兩個階段,不過launcher和app啟動在這兩個階段有些許的區別而已。
開機廣告就不多說了,後面也會給出AMS新增的方案,從AMS直接啟動廣告Activity播放廣告,然後主動finish;系統會啟動Launcher;點選相關app,啟動自己想開啟的應用(順序三個階段)。
二、流程圖
1.正常啟動Launcher
這裡先看下正常情況下的Luancher啟動,即開機即啟動Launcher。然後在看下先播放開機廣告,然後在自動Launcher,看下異同點。
AMS被SystemServer啟動之後,SystemServer會通過AMS呼叫startHomeActtivity啟動Launcher,流程見上流程圖。
其中有幾個關鍵函式,需要關注一下:startHomeActivityLocked、startActivityLocked、addActivityToTop、resumeTopActivityLocked、realStartActivityLocked、attachApplicationLocked;幾個點記住:ProcessLocked中有Process.start,最終會觸發AMS的attachApplication。
從流程途中看到,起點可以算startHomeActivityLocked
第一階段是startHomeActivity,觸發activity的程序建立;第二階段就是AMS的attachApplication在程序建立後被呼叫,最終執行realStartActivityLocked會回撥Activity的onCreate函式。
這裡第一階段和上面說的不太一樣,不過沒關係,下面看下先播開機廣告在啟動launcher的流程。
2.開機廣告之後啟動Launcher
AMS啟動廣告的就不看了,看下廣告finish之後,Launcher啟動的流程:
先看下呼叫棧:
第一階段:開機廣告finish掉,觸發paused:
06-28 18:07:14.098 4200 4391 W System.err: at com.android.server.am.ActivityStack.startPausingLocked(ActivityStack.java:825)
06-28 18:07:14.098 4200 4391 W System.err: at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:2745)
06-28 18:07:14.098 4200 4391 W System.err: at com.android.server.am.ActivityStack.requestFinishActivityLocked(ActivityStack.java:2572)
06-28 18:07:14.098 4200 4391 W System.err: at com.android.server.am.ActivityManagerService.finishActivity(ActivityManagerService.java:4543)
06-28 18:07:14.098 4200 4391 W System.err: at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:325)
06-28 18:07:14.098 4200 4391 W System.err: at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2267)
06-28 18:07:14.098 4200 4391 W System.err: at android.os.Binder.execTransact(Binder.java:446)
第二階段:paused並啟動launcher
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStackSupervisor.realStartActivityLocked(ActivityStackSupervisor.java:1182)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1285)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:1898)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1459)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStackSupervisor.resumeTopActivitiesLocked(ActivityStackSupervisor.java:2477)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStack.startActivityLocked(ActivityStack.java:2097)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStackSupervisor.startActivityUncheckedLocked(ActivityStackSupervisor.java:2217)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1519)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStackSupervisor.startHomeActivity(ActivityStackSupervisor.java:833)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityManagerService.startHomeActivityLocked(ActivityManagerService.java:3248)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStackSupervisor.resumeHomeStackTask(ActivityStackSupervisor.java:459)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:1504)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1459)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStackSupervisor.resumeTopActivitiesLocked(ActivityStackSupervisor.java:2477)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:998)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:896)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:6591)
06-29 15:18:57.860 4196 4213 W System.err: at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:512)
06-29 15:18:57.860 4196 4213 W System.err: at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2267)
06-29 15:18:57.860 4196 4213 W System.err: at android.os.Binder.execTransact(Binder.java:446)
流程圖:
直接啟動launcher,通過程序建立,觸發attach就起來了;而開機廣告這種情況則複雜很多,先是finish掉開機廣告,然後由pause流程觸發startHomeActivity並遞迴呼叫了一次resume的流程之後才走到realStartActivityLocked,回撥launcher的onCreate函式。
3.Launcher啟動之後啟動app
流程圖:
正常啟動:一階段:先呼叫startActivityLocked,並呼叫pause,二階段pause呼叫resume直接啟動activity了。
正常啟動activity,會走startActivity(這裡會將ActivityRecord資訊加入task頂,並也呼叫startPausingLocked);
在後續流程中,也不同,主要是2中launcher啟動遞迴呼叫了resume得幾個函式;而正常啟動則不會遞迴,
原因就是正常啟動在首次就將ActivityRecord資訊入task頂了,而2中launcher則沒有;
三、一些注意點
1.addActivityToTop這個函式比較重要,會將要啟動的activity的AcitivityRecord加入TASK頂端;這個非常重要,決定著realStartActivityLocked會不會被呼叫,還是啟動launcher;如果執行了,即加入了Task的棧頂則這裡next!=null而是相關的ActivityRecord,否則為null(final ActivityRecord next = topRunningActivityLocked(null););
final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
if (!mService.mBooting && !mService.mBooted) {
// Not ready yet!
return false;
}
// Find the first activity that is not finishing.
final ActivityRecord next = topRunningActivityLocked(null);
final TaskRecord prevTask = prev != null ? prev.task : null;
if (next == null) {
// There are no more activities! Let's just start up the
// Launcher...
// Only resume home if on home display
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "noMoreActivities");
}
2.resumeTopActivityLocked這個函式比較坑(5.1~9.0都這樣),函式裡有個判斷會導致2.2部分的launcher啟動不起來,2.2中的呼叫邏輯是我將AOSP程式碼註釋掉一行以後,啟動的。
看下這個函式:注意標誌位:inResumeTopActivity
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
mStackSupervisor.inResumeTopActivity = true;//註釋掉即可,既能如2.2中所示呼叫流程,否則巢狀呼叫就返回,launcher無法啟動
if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
mService.updateSleepIfNeededLocked();
}
result = resumeTopActivityInnerLocked(prev, options);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
return result;
}
可以看到這個函式使用標誌位inResumeTopActivity ,但是2.2中開機廣告這種情況下,就會出現問題;
在2.2中,第一階段只是進行finish處理和pause呼叫;第二階段才會通過pause進行resume,但是先走到這個函式而後觸發的startActivityLocked(呼叫addActivityToTop),隨後又走到這裡的時候就返回了,並沒有繼續執行,所以luancher就沒有啟動,會出現開機廣告播放完成之後,一直黑屏的現象。
相關關鍵函式:
startHomeActivityLocked:呼叫啟動Launcher;
startActivityLocked(ActivityStack中 ):呼叫觸發addActivityToTop將ActivityRecord加入棧頂;
resumeTopActivityLocked:這個函式是3.1中說的函式,不修改會導致廣告後launcher不啟動;
realStartActivityLocked:觸發app.thread.scheduleLaunchActivity,去回撥mainactivity的onCreate函式;
attachApplicationLocked:由建立相關程序之後觸發,此函式會觸發realStartActivityLocked的呼叫。
總結:
整體上,這篇文章涉及較多,AMS管理task即生命週期都有涉及,如果之前沒有接觸過,基本看不懂,很頭痛。
這裡放上幾篇基礎文章,可以閱讀後再來讀本篇文章,應該會又更深刻的理解。
附上AMS關係圖:
大元件之ActivityRecord