在Ams中Activity的容器是Task, task的容器是stack, 所以我们先来看下stack是如何管理Task的
final class ActivityStack {
/**
* The back history of all previous (and possibly still
* running) activities. It contains #TaskRecord objects.
*/
private ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
}
再来看下TaskRecord
final class TaskRecord {
/** Indication of what to run next when task exits. Use ActivityRecord types.
* ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
* task stack. */
private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
}
static final int APPLICATION_ACTIVITY_TYPE = 0;
static final int HOME_ACTIVITY_TYPE = 1;
static final int RECENTS_ACTIVITY_TYPE = 2;
ActivityStack使用mTaskHistory来管理多个Task,Task的mTaskToReturnTo代表该Task上最后一个Activity销毁后返回的Task类型,分别是:
- APPLICATION_ACTIVITY_TYPE 返回到另外一个普通应用的Task。
- HOME_ACTIVITY_TYPE 表示返回到桌面。
- RECENTS_ACTIVITY_TYPE 表示返回到最近任务。
通常由于我们一个Activity启动了一个新的Task,那么新Task返回后就应该返回到启动它的Task对应的Activity上。 但是考虑如下两种情况:
- 假如用户按Home键,然后从某个应用图标进入某个Task,则Task退出后应返回到桌面。
- 假如用户按最近任务键,切入某个Task, 则该Task退出后也应该返回到桌面。
所以通过最近任务和桌面进入Task会破坏掉原来的Task返回链路。Task.mTaskToReturnTo都会变为HOME_ACTIVITY_TYPE或者RECENTS_ACTIVITY_TYPE。
Ams怎么管理Stack呢? 从6.0开始Android支持多stack,也就是分屏。Android使用stack管理Activity的回退路径,使用stack管理屏幕上的多个窗口(多个回退路径)。
class ActivityDisplay {
/** All of the stacks on this display. Order matters, topmost stack is in front of all other
* stacks, bottommost behind. Accessed directly by ActivityManager package classes */
final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
}
每个Display下面可以有多个ActivityStack。外界如何控制stack的大小位置? 通过ActivityContainer
class ActivityContainer extends android.app.IActivityContainer.Stub {
@Override
public int getStackId() {
synchronized (mService) {
return mStackId;
}
}
@Override
public boolean injectEvent(InputEvent event) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mService) {
if (mActivityDisplay != null) {
return mInputManagerInternal.injectInputEvent(event,
mActivityDisplay.mDisplayId,
InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
}
return false;
} finally {
Binder.restoreCallingIdentity(origId);
}
}
......
@Override
public final int startActivity(Intent intent) {
mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
final int userId = mService.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), mCurrentUser, false,
ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
// TODO: Switch to user app stacks here.
String mimeType = intent.getType();
final Uri data = intent.getData();
if (mimeType == null && data != null && "content".equals(data.getScheme())) {
mimeType = mService.getProviderMimeType(data, userId);
}
checkEmbeddedAllowedInner(userId, intent, mimeType);
intent.addFlags(FORCE_NEW_TASK_FLAGS);
return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null,
0, 0, null, null, null, null, false, userId, this, null);
}
@Override
public final int startActivityIntentSender(IIntentSender intentSender)
throws TransactionTooLargeException {
mService.enforceNotIsolatedCaller("ActivityContainer.startActivityIntentSender");
if (!(intentSender instanceof PendingIntentRecord)) {
throw new IllegalArgumentException("Bad PendingIntent object");
}
final int userId = mService.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), mCurrentUser, false,
ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
final PendingIntentRecord pendingIntent = (PendingIntentRecord) intentSender;
checkEmbeddedAllowedInner(userId, pendingIntent.key.requestIntent,
pendingIntent.key.requestResolvedType);
return pendingIntent.sendInner(0, null, null, null, null, null, null, 0,
FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
}
@Override
public void setSurface(Surface surface, int width, int height, int density) {
mService.enforceNotIsolatedCaller("ActivityContainer.attachToSurface");
}
......
}
ActivityContainer是一个Binder服务,客户端拿到对应的Binder代理就可以通过ActivityContainer在stack上创建Activity了。另外ActivityManagerService的resize函数可以设置ActivityStack的大小和位置,这也是分屏实现的基础。
@Override
public void resizeTask(int taskId, Rect bounds) {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
"resizeTask()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
if (task == null) {
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
return;
}
mStackSupervisor.resizeTaskLocked(task, bounds);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
在默认不分屏的情况下Android有两个Satck,分别对应最近任务和桌面所在的stack(HomeStack),以及普通应用所在的Stack。当全屏应用启动后,应用ActivityStack会覆盖在HomeStack上。当遇到Task.mTaskToReturnTo的Task清空后,由于普通应用的Activity都不可见则HomeStack就显示了出来。