版權說明:本文為 開開向前沖 記錄文章,轉載請注明出處;
注:限于作者水平有限,文中有不對的地方還請指教
在文章ActivityManagerService-A中對AMS 中核心的幾個數據類都有說道,在ActivityManagerService-B中對ActivityRecord 的狀態變化做了一個介紹,Activity的狀態只是管理的結果,具體的過程需要需要詳細分析;本文將從幾個簡單的場景結合代碼來分析Activity的管理過程;
場景1:Activity在AMS中的存在形式是ActivityRecord,應用程序的組件是Activity,ActivityRecord與Activity是如何關聯的呢?——>static class Token extends IApplicationToken.Stub
這里涉及到到應用程序的主線程-ActivityThread(ActivityThread其實并不是一個線程類),這個類已經有很多人講解,這里推薦一篇關于ActivityThread和ApplicationThread的解析,ActivityThread有一個內部類 ApplicationThread;
class ApplicationThread extends ApplicationThreadNative
class ApplicationThreadNative extends Binder implements IApplicationThread
AMS 和ActivityStackSupervisor中的 app.thread 就是這里ActivityThread的內部類ApplicationThread對象;
Activity在ActivityThread中的存在形式是ActivityClientRecord;ActivityRecord有一個IApplicationToken.Stub類型的變量appToken,在構造ActivityRecord的時候被初始化;
------>frameworks\base\services\core\java\com\android\server\am\ActivityRecord.java
static class Token extends IApplicationToken.Stub {
final WeakReference<ActivityRecord> weakActivity;
Token(ActivityRecord activity) {
weakActivity = new WeakReference<ActivityRecord>(activity);
}
......
------>frameworks\base\services\core\java\com\android\server\am\ActivityRecord.java
ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration,
ActivityRecord _resultTo, String _resultWho, int _reqCode,
boolean _componentSpecified, ActivityStackSupervisor supervisor,
ActivityContainer container, Bundle options) {
service = _service;
appToken = new Token(this);
......
}
構造一個ActivityRecord時,會將自己(this)傳給Token,變量ActivityRecord.appToken存的就是最終創建出來的Token。
上述ActivityRecord.appToken的功能是什么呢?ActivityRecord是在Activity的啟動過程中被初始化,繼續跟進Activity的啟動過程;
------>frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
------>frameworks\base\core\java\android\app\ActivityThread.java
ActivityStackSupervisor.realStartActivityLocked(ActivityRecord, ...)
——> IApplicationThread.scheduleLaunchActivity(...,token, ...)
——>跨進程調用,調用ActivityThread.ApplicationThread.scheduleLaunchActivity(...,token,...)
——>ApplicationThread.scheduleLaunchActivity(...token, ...)
——>ActivityThread.handleLaunchActivity(LAUNCH_ACTIVITY)
——>ActivityThread.performLaunchActivity(ActivityClientRecord, ...)
——>從ActivityActivityClientRecord取出token使用
——> Activity.attch(...token, ...) //attach中將token 賦值給Activity的mToken變量
通過上述函數調用,ActivityRecord的appToken就和應用進程的mToken建立關聯;在發生Activity切換時,應用進程會將上一個Activity的Token(AMS.startActivity()的輸入參數IBinder resultTo)傳遞給系統進程,系統進程會根據這個Token找到ActivityRecord,對其完成調度后,再通知應用進程:Activity狀態發生了變化。
場景2:啟動新Activity時,需要將新ActivityRecord壓入任務棧頂;
這里先用自然語言描述一下可能的情況:1:新的ActivityRecord 的任務棧已經存在,處于后臺,此時需要將這個后臺任務棧切換為前臺任務棧,然后將這個ActivityRecord置于前臺任務棧棧頂; 2:新ActivityRecord所在的任務棧沒有,需要新建任務棧,然后將ActivityRecord置于棧頂;
代碼邏輯:任務棧存在于后臺的情況:
第一步:需要先找到ActivityRecord所在的任務(TaskRecord);
第二步:將TaskRecord所在的ActivityStack移動到前臺;
第三步:將TaskRecord移動到ActivityStack的棧頂;
1:找到ActivityRecord所在的TaskRecord: findTaskLocked()
------>frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
/**
* Returns the top activity in any existing task matching the given
* Intent. Returns null if no such task is found.
*/
ActivityRecord findTaskLocked(ActivityRecord target) {
Intent intent = target.intent;
ActivityInfo info = target.info;
ComponentName cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
}
...
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
...
final ActivityRecord r = task.getTopActivity();
if (r == null || r.finishing || r.userId != userId ||
r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {//這些條件的直接過濾
continue;
}
...
final Intent taskIntent = task.intent;
final Intent affinityIntent = task.affinityIntent;
...
if (!isDocument && !taskIsDocument && task.rootAffinity != null) {
if (task.rootAffinity.equals(target.taskAffinity)) { //Affinity和Task的rootAffinity相同,
//則就是這個task 了;
return r;
}
} else if (taskIntent != null && taskIntent.getComponent() != null &&
taskIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {//Task的Intent 和target的包名相同
return r;
} else if if (affinityIntent != null && affinityIntent.getComponent() != null &&
affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) { //Affinity Intent的包名相同
return r
}
...
}
return null;
}
改函數主要是對ActivityStack中的所有Task進行遍歷,找到ActivityRecord的所在的Task,如果找到Task,則返回Task最上面的ActivityRecord;找到Task的條件如下:
- ActivityRecord target 的affinity和正在遍歷的Task的rootAffinity相同;
- ActivityRecord target的包名和Task的intent 的包名相同;
- ActivityRecord target的包名和Task的affinityIntent的包名相同;
2:將TaskRecord所在的ActivityStack調整到前臺
- 2.1:findTaskLocked()方法找到Activity所在的Task的頂部ActivityRecord,根據這個ActivityRecord找到所在的TaskRecord和ActivityStack;
------> frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
boolean doResume, Bundle options, TaskRecord inTask) {
......
ActivityRecord intentActivity = !launchSingleInstance ?
findTaskLocked(r) : findActivityLocked(intent, r.info);
if (intentActivity != null) {
......
if (r.task == null) {
r.task = intentActivity.task;
}
targetStack = intentActivity.task.stack;//找到ActivityRecord r所在的ActivityStack
targetStack.mLastPausedActivity = null;
targetStack.moveToFront("intentActivityFound");
......
- 2.2:調整ActivityStack,主要根據ActivityStack的類型來進行ActivityStack棧(mStacks)調整;moveToFront();
------>frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
final void moveToFront(String reason) {
if (isAttached()) {//是否綁定到顯示設備
if (isOnHomeDisplay()) {//是否顯示在默認顯示設備
mStackSupervisor.moveHomeStack(isHomeStack(), reason);//ActivityStack棧調整
}
mStacks.remove(this);//刪除mStacks棧中的該ActivityStack
mStacks.add(this);//將該ActivityStack添加到mStacks中
final TaskRecord task = topTask();
if (task != null) {
mWindowManager.moveTaskToTop(task.taskId);
}
}
}
final boolean isHomeStack() {//判斷當前ActivityStack 是不是HomeStack
return mStackId == HOME_STACK_ID;
}
void moveHomeStack(boolean toFront, String reason) {//棧調整
// 獲取當前的Top Stack
ArrayList<ActivityStack> stacks = mHomeStack.mStacks;//mStacks代表的是綁定到顯示設備的所有Stack;
//所以這里也可以用mFocusedStack.mStacks
final int topNdx = stacks.size() - 1;
if (topNdx <= 0) {
return;
}
ActivityStack topStack = stacks.get(topNdx);
// HomeStack是否需要調整
final boolean homeInFront = topStack == mHomeStack;//判斷stacks 棧頂的ActivityStack是不是HomeStack,
// 即判斷當前HomeStack是不是在前臺;
if (homeInFront != toFront) {
mLastFocusedStack = topStack;
stacks.remove(mHomeStack);
stacks.add(toFront ? topNdx : 0, mHomeStack);//這里根據toFront來調整HomeStack位置
mFocusedStack = stacks.get(topNdx);//調整mFocusedStack
}
...
if (mService.mBooting || !mService.mBooted) { // 開機過程處理
final ActivityRecord r = topRunningActivityLocked();
if (r != null && r.idle) {
checkFinishBootingLocked();
}
}
}
moveHomeStack()方法根據mStacks棧頂的ActivityStack是否是HomeStack來對HomeStack和mFocusedStack 進行調整;homeInFront 表示mStacks棧頂是不是HomeStack(即HomeStack 是否在前臺);toFront 是isHomeStack()的返回值,即當前ActivityStack是否是HomeStack,也就是需要將當前ActivityStack調整到前臺還是后臺;
這里存在如下4種情況:
- homeInFront = true,即topStack == mHomeStack, 表示當前mStacks最頂的棧是HomeStack,即表示HomeStack在前臺;toFront = false 即isHomeStack()返回false,即表示ActivityRecord所在的棧不是HomeStack,所以需要將HomeStack調整到mStacks的底部,即將HomeStack調整到mStacks的0號位置;
- homeInFront = true, toFront = true: 表示HomeStack在前臺,要顯示的ActivityStack就是HomeStack,所以不需要對mStacks進行調整;
- homeInFront = false, toFront = true: 表示HomeStack在后臺,要顯示的ActivityStack就是HomeStack,需要將HomeStack調整到mStacks的最頂端;
- homeInFront = false, toFront = false: 表示HomeStack在后臺,要顯示的ActivityStack 也不 是HomeStack,不需要對mStacks進行調整。
moveToFront中moveHomeStack()調整完HomeStack位置后,調整mStacks棧中當前ActivityStack位置,即先刪除當前ActivityStack,然后再向mStacks中添加當前ActivityStack(這樣做時為了保證將當前ActivityStack置于棧頂);
3:將當前需要顯示的ActivityRecord的TaskRecord 移動到ActivityStack 的棧頂;moveTaskToFrontLocked()
ActivityStack有前臺和后臺之分,前臺ActivityStack代表當前顯示的ActivityRecord在的TaskRecord所在的ActivityStack(不是前臺ActivityStack中所有的TaskRecord 和ActivityRecord都處于可見,只有ActivityStack 棧頂的TaskRecord 棧頂的ActivityRecord處于可見狀態);
第二步已經將ActivityRecord所在的Task的Stack移動到前臺,現在需要將需要顯示的ActivityRecord 所在的TaskRecord 移動到ActivityStack的棧頂,以及將ActivityRecord移動到TaskRecord的棧頂;
------> frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord source, Bundle options,
String reason) {
final int numTasks = mTaskHistory.size();
final int index = mTaskHistory.indexOf(tr);
if (numTasks == 0 || index < 0) { //numTasks 代表當前ActivityStack中的所有TaskRecord數量,
//index 表示當前需要調整的TaskRecord在ActivityStack mTaskHistory中的位置
// nothing to do!
if (source != null &&
(source.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
ActivityOptions.abort(options);
} else {
updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
}
return;
}
// Shift all activities with this task up to the top
// of the stack, keeping them in the same internal order.
insertTaskAtTop(tr);//將Task置于ActivityStack棧頂
moveToFront(reason);//前面說過moveToFront()方法,前面的情況只調用了moveToFront(),
//不會調用moveTaskToFrontLocked();
//一旦要將任務調整到ActivityStack棧頂,意味著ActivityStack也一定要調整到前臺;
if (source != null &&
(source.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
ActivityRecord r = topRunningActivityLocked(null);
if (r != null) {
mNoAnimActivities.add(r);
}
ActivityOptions.abort(options);
} else {
updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
}
mStackSupervisor.resumeTopActivitiesLocked();//當Activity各種棧調整好后,就可以將當前Activity的狀態置為RESUMED
......
}
private void insertTaskAtTop(TaskRecord task) {
// If this is being moved to the top by another activity or being launched from the home
// activity, set mOnTopOfHome accordingly.
if (isOnHomeDisplay()) {
ActivityStack lastStack = mStackSupervisor.getLastStack();
final boolean fromHome = lastStack.isHomeStack();
if (!isHomeStack() && (fromHome || topTask() != task)) {
task.setTaskToReturnTo(fromHome
? lastStack.topTask() == null
? HOME_ACTIVITY_TYPE
: lastStack.topTask().taskType
: APPLICATION_ACTIVITY_TYPE);//設置ReturnTo Task類型
}
} else {
task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
}
mTaskHistory.remove(task);//先從mTaskHistory中移除task
// Now put task at top.
int taskNdx = mTaskHistory.size();
if (!isCurrentProfileLocked(task.userId)) {
// Put non-current user tasks below current user tasks.
while (--taskNdx >= 0) {
if (!isCurrentProfileLocked(mTaskHistory.get(taskNdx).userId)) {
break;
}
}
++taskNdx;
}
mTaskHistory.add(taskNdx, task);//將task添加到mTaskHistory,確保添加到了頂部
updateTaskMovement(task, true);
}
這里將ActivityRecord所在的TaskRecord 移動到ActivityStack的棧頂,還需要將需要顯示的ActivityRecord移動到TaskRecord的棧頂,這個過程通過addActivityToTop()來實現;addActivityToTop()在ActivityStack.java的startActivityLocked()方法中被調用,startActivityLocked()在ActivityStackSupervisor.java的startActivityUncheckedLocked()方法中被調用;
------> frameworks\base\services\core\java\com\android\server\am\TaskRecord.java
void addActivityToTop(ActivityRecord r) {
addActivityAtIndex(mActivities.size(), r);
}
void addActivityAtIndex(int index, ActivityRecord r) {
// Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
if (!mActivities.remove(r) && r.fullscreen) {//刪除mActivities中已經存在的r
// Was not previously in list.
numFullscreen++;
}
// Only set this based on the first activity
if (mActivities.isEmpty()) { //判斷當前啟動的Activity是否為該任務Task的第一個Activity
taskType = r.mActivityType;
isPersistable = r.isPersistable();
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
// Clamp to [1, max].
maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
ActivityManager.getMaxAppRecentsLimitStatic());
} else {
// Otherwise make all added activities match this one.
r.mActivityType = taskType;
}
Log.d(TAG+"mActivities.add",Log.getStackTraceString(new Throwable()));//Keiven-chen
mActivities.add(index, r);//指定將當前Activity添加到mActivities中的位置
updateEffectiveIntent();//如函數名,更新任務棧相關Intent
if (r.isPersistable()) {
mService.notifyTaskPersisterLocked(this, false);
}
}
這里需要明確一點問題,mActivities就是我說的TaskRecord棧, mTaskHistory也就是ActivityStack棧;
場景3: 任務棧會經常調整,任務棧剛開始從底到頂是 A - B - C, 經過調整后任務棧變化為 C - B - A,這個過程會對整個任務棧帶來哪些改變呢?
該問題看似只需要調整mActivities的順序,但是會這么簡單嗎?ActivityManagerService-A文中有說過TaskRecord類,隨著mActivities棧的改變,TaskRecord中的屬性是否也應該改變呢?比如Affinity,Intent;這些值是如何改變的呢?這里涉及updateEffectiveIntent()和setFrontOfTask();
每次調整完mActivities后,需要調用updateEffectiveIntent方法來修改該TaskRecord相關的Intent;
void updateEffectiveIntent() {
final int effectiveRootIndex = findEffectiveRootIndex();//找到根Activity索引
final ActivityRecord r = mActivities.get(effectiveRootIndex);
setIntent(r);//設置Intent相關屬性,順著代碼往下看,
}
/** Sets the original intent, and the calling uid and package. */
void setIntent(ActivityRecord r) {
setIntent(r.intent, r.info);
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
}
/** Sets the original intent, _without_ updating the calling uid or package. */
private void setIntent(Intent _intent, ActivityInfo info) { //該重載方法更新affinity,
//origActivity ,realActivity等屬性;
if (intent == null) {
mNeverRelinquishIdentity =
(info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0;
} else if (mNeverRelinquishIdentity) {
return;
}
affinity = info.taskAffinity;
if (intent == null) {
// If this task already has an intent associated with it, don't set the root
// affinity -- we don't want it changing after initially set, but the initially
// set value may be null.
rootAffinity = affinity;
}
effectiveUid = info.applicationInfo.uid;
stringName = null;
if (info.targetActivity == null) {
if (_intent != null) {
// If this Intent has a selector, we want to clear it for the
// recent task since it is not relevant if the user later wants
// to re-launch the app.
if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
_intent = new Intent(_intent);
_intent.setSelector(null);
_intent.setSourceBounds(null);
}
}
if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
"Setting Intent of " + this + " to " + _intent);
intent = _intent;
realActivity = _intent != null ? _intent.getComponent() : null;
origActivity = null;
} else {
ComponentName targetComponent = new ComponentName(
info.packageName, info.targetActivity);
if (_intent != null) {
Intent targetIntent = new Intent(_intent);
targetIntent.setComponent(targetComponent);
targetIntent.setSelector(null);
targetIntent.setSourceBounds(null);
if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
"Setting Intent of " + this + " to target " + targetIntent);
intent = targetIntent;
realActivity = targetComponent;
origActivity = _intent.getComponent();
} else {
intent = null;
realActivity = targetComponent;
origActivity = new ComponentName(info.packageName, info.name);
}
}
final int intentFlags = intent == null ? 0 : intent.getFlags();
if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
// Once we are set to an Intent with this flag, we count this
// task as having a true root activity.
rootWasReset = true;
}
userId = UserHandle.getUserId(info.applicationInfo.uid);
if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
// If the activity itself has requested auto-remove, then just always do it.
autoRemoveRecents = true;
} else if ((intentFlags & (Intent.FLAG_ACTIVITY_NEW_DOCUMENT
| Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT) {
// If the caller has not asked for the document to be retained, then we may
// want to turn on auto-remove, depending on whether the target has set its
// own document launch mode.
if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
autoRemoveRecents = false;
} else {
autoRemoveRecents = true;
}
} else {
autoRemoveRecents = false;
}
}
任務棧A - B - C的棧底是 A,調整后, C - B - A的棧底是C,然而,TaskRecord并沒有標注當前棧底的屬性, 這個棧底是根據任務棧中每個ActivityRecord的frontOfTask屬性來標識:這個屬性通過setFrontOfTask()方法來修改;
/** Call after activity movement or finish to make sure that frontOfTask is set correctly */
final void setFrontOfTask() {
boolean foundFront = false;
final int numActivities = mActivities.size();
for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {//重棧底開始
final ActivityRecord r = mActivities.get(activityNdx);
if (foundFront || r.finishing) {
r.frontOfTask = false; //非棧底Activity 該屬性都置為false
} else {
r.frontOfTask = true;//棧底Activity 該屬性置為true
// Set frontOfTask false for every following activity.
foundFront = true;
}
}
if (!foundFront && numActivities > 0) {
// All activities of this task are finishing. As we ought to have a frontOfTask
// activity, make the bottom activity front.
mActivities.get(0).frontOfTask = true; //這種情況將mActivities第一個Activity的frontOfTask置為true;
}
}
該函數對任務棧從底到頂進行遍歷,找到第一個未結束(finishing = false)的ActivityRecord, 將其frontOfTask屬性設置成true;其他所有ActivtyRecord的frontOfTask屬性設置為false。這樣就能標記該ActivityRecord為所在任務棧的棧底;