ActivityManagerService对于Task的管理

在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上。 但是考虑如下两种情况:

  1. 假如用户按Home键,然后从某个应用图标进入某个Task,则Task退出后应返回到桌面。
  2. 假如用户按最近任务键,切入某个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就显示了出来。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值