ActivityManagerService-C 管理场景分析
版权说明:本文为 开开向前冲 记录文章,转载请注明出处;
注:限于作者水平有限,文中有不对的地方还请指教
在文章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为所在任务栈的栈底;