AMS-stack(二) ActivityStack

由于篇幅问题第一篇介绍了栈的大管家,这篇介绍stack,ActivityStack类也比较恐怖有五千行代码,不过ActivityStack主要负对task的管理,对activity的管理,为ActivityStackSupervisor做了很多更底层的事情,对整个activity的管理最重要和繁多的一个环节,我们要想学习wms必须先搞清楚stack的逻辑,再搞清楚task的逻辑,最后将ams的情景进行总结,根据不同的情景再次走一次,加深印象。

首先还是先看stack维护的数据结构

 enum ActivityState {
        INITIALIZING,
        RESUMED,
        PAUSING,
        PAUSED,
        STOPPING,
        STOPPED,
        FINISHING,
        DESTROYING,
        DESTROYED
    }
  • 从ActivityState这个枚举值可以看到,一个actviity的生命周期包括上面的9个状态,stack正式负责这九个状态的切换。
  • stack的可见状态如下
    //不可见
    static final int STACK_INVISIBLE = 0;
    // 可见
    static final int STACK_VISIBLE = 1;
    //可见但是被其他stack遮挡,如透明的activity
    static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
  • 移除task的模式也有三种
  // 销毁
  static final int REMOVE_TASK_MODE_DESTROYING = 0;
    //移动,不执行一些操作,例如不从wms中移除或者最近任务移除
    static final int REMOVE_TASK_MODE_MOVING = 1;
  // 把task移动到stack顶部,把stack启动到前台
    static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
  • private final ArrayList mTaskHistory = new ArrayList<>(); task的记录
  • final ArrayList mValidateAppTokens = new ArrayList<>(); 
  • final ArrayList mLRUActivities = new ArrayList<>(); 最近最少使用的activity
  • final ArrayList mNoAnimActivities = new ArrayList<>(); 不执行activity切换动画的activity
  • ActivityRecord mPausingActivity = null; 正在执行pause的activity
  • ActivityRecord mLastPausedActivity = null; 最后一个执行pause的activity
  • ActivityRecord mLastNoHistoryActivity = null; 用户指定不显示在历史记录的activity
  • ActivityRecord mResumedActivity = null; 当先正在显示的activity
  • boolean mFullscreen = true; 堆栈是否覆盖整个屏幕
  • Rect mBounds = null; stack的大小,全屏时候为空
  • boolean mUpdateBoundsDeferred; 延迟更新边界
  • boolean mUpdateBoundsDeferredCalled; 延迟更新被调用
 final Rect mDeferredBounds = new Rect();
    final Rect mDeferredTaskBounds = new Rect();
    final Rect mDeferredTaskInsetBounds = new Rect();

同样Stack中也存在一个Handler,运行在AMS的mainHandler所在的线程中,主要的工作还是对超时的处理

  final class ActivityStackHandler extends Handler {
   
   

        ActivityStackHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case PAUSE_TIMEOUT_MSG: { //pause activity超时
                    ActivityRecord r = (ActivityRecord)msg.obj;
                    // We don't at this point know if the activity is fullscreen,
                    // so we need to be conservative and assume it isn't.
                    Slog.w(TAG, "Activity pause timeout for " + r);
                    synchronized (mService) { 
                        if (r.app != null) {
                            mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
                        }
                        activityPausedLocked(r.appToken, true);
                    }
                } break;
                case LAUNCH_TICK_MSG: { // 启动时间太长 记录log,user版本不会打印
                    ActivityRecord r = (ActivityRecord)msg.obj;
                    synchronized (mService) {
                        if (r.continueLaunchTickingLocked()) {
                            mService.logAppTooSlow(r.app, r.launchTickTime, "launching " + r);
                        }
                    }
                } break;
                case DESTROY_TIMEOUT_MSG: {
  
  //销毁超时
                    ActivityRecord r = (ActivityRecord)msg.obj;
                    // We don't at this point know if the activity is fullscreen,
                    // so we need to be conservative and assume it isn't.
                    Slog.w(TAG, "Activity destroy timeout for " + r);
                    synchronized (mService) {
                        activityDestroyedLocked(r != null ? r.appToken : null, "destroyTimeout");
                    }
                } break;
                case STOP_TIMEOUT_MSG: { // 停止超时
                    ActivityRecord r = (ActivityRecord)msg.obj;
                    // We don't at this point know if the activity is fullscreen,
                    // so we need to be conservative and assume it isn't.
                    Slog.w(TAG, "Activity stop timeout for " + r);
                    synchronized (mService) {
                        if (r.isInHistory()) {
                            activityStoppedLocked(r, null, null, null);
                        }
                    }
                } break;
                case DESTROY_ACTIVITIES_MSG: { //执行销毁activity
                    ScheduleDestroyArgs args = (ScheduleDestroyArgs)msg.obj;
                    synchronized (mService) {
                        destroyActivitiesLocked(args.mOwner, args.mReason);
                    }
                } break;
                case TRANSLUCENT_TIMEOUT_MSG: {
  
  //设置半透明超时
                    synchronized (mService) {
                        notifyActivityDrawnLocked(null);
                    }
                } break;
                case RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG: { //取消后台显示超时
                    synchronized (mService) {
                        final ActivityRecord r = getVisibleBehindActivity();
                        Slog.e(TAG, "Timeout waiting for cancelVisibleBehind player=" + r);
                        if (r != null) {
                            mService.killAppAtUsersRequest(r.app, null);
                        }
                    }
                } break;
            }
        }
    }

这一又一次验证了系统服务不能保证客户端高效可靠的执行,全部用超时处理

  • int numActivities() 函数返回stack中有多少个activity
  • 下面来看一下构造函数
 ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer,
            RecentTasks recentTasks) {
        mActivityContainer = activityContainer; //所在的activity container
        mStackSupervisor = activityContainer.getOuter(); // 栈大管家赋值
        mService = mStackSupervisor.mService; //AMS
        mHandler = new ActivityStackHandler(mService.mHandler.getLooper()); //Handler创建
        mWindowManager = mService.mWindowManager; //WMS赋值
        mStackId = activityContainer.mStackId; // stackid
        mCurrentUser = mService.mUserController.getCurrentUserIdLocked(); //当前user
        mRecentTasks = recentTasks; //recent task
        mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID
                ? new LaunchingTaskPositioner() : null; //freeform stack需要使用LaunchingTaskPositioner计算位置
    }

在看看stack创建和销毁的操作
stack创建后会马上attach display上面

void attachDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
        mDisplayId = activityDisplay.mDisplayId;
        mStacks = activityDisplay.mStacks;
        //mBounds会通过WMS返回,wms会根据docker stack情况计算出新的stack大小
        mBounds = mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
        mFullscreen = mBounds == null;
        if (mTaskPositioner != null) {
  
  // freedom stack的一些处理
            mTaskPositioner.setDisplay(activityDisplay.mDisplay);
            mTaskPositioner.configure(mBounds);
        }

        if (mStackId == DOCKED_STACK_ID) {
  
  //更新docker stack大小
            // If we created a docked stack we want to resize it so it resizes all other stacks
            // in the system.
            mStackSupervisor.resizeDockedStackLocked(
                    mBounds, null, null, null, null, PRESERVE_WINDOWS);
        }
    }
  //从display上移除stack
    void detachDisplay() {
        mDisplayId = Display.INVALID_DISPLAY;
        mStacks = null;
        if (mTaskPositioner != null) {
            mTaskPositioner.reset();
        }
        //WMS先移除
        mWindowManager.detachStack(mStackId);
        if (mStackId == DOCKED_STACK_ID) { //更新其他 stack大小
            // If we removed a docked stack we want to resize it so it resizes all other stacks
            // in the system to fullscreen.
            mStackSupervisor.resizeDockedStackLocked(
                    null, null, null, null, null, PRESERVE_WINDOWS);
        }
    }
  • 后面一些列deferUpdateBounds的操作的作用是在activity启动的时候不去更新HOME STACK的大小,直到app动画执行完成的时候再去更新,其中有三个函数,void deferUpdateBounds()表示开始执行延迟更新,而在resize的过程中,先不更新stack的边界,使用boolean updateBoundsAllowed(Rect bounds, Rect tempTaskBounds,
    Rect tempTaskInsetBounds)函数记录边界,并且设置mUpdateBoundsDeferredCalled = true;表示边界有更新,最后在activity切换动画执行完成后,使用void continueUpdateBounds()更新stack边界。

  • setBounds函数设置stack的大小

 void setBounds(Rect bounds) {
        mBounds = mFullscreen ? null : new Rect(bounds);
        if (mTaskPositioner != null) {
            mTaskPositioner.configure(bounds);
        }
    }
  • final ActivityRecord topRunningActivityLocked()  返回最stack最上面没有finish并且user可以显示的activity
  • final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) 返回不延迟显示的activity
  • final ActivityRecord topActivity() 返回没有finish的activity,不管user是不是可以显示
  • final TaskRecord topTask()
  • TaskRecord taskForIdLocked(int id)  根据id找task
  • ActivityRecord isInStackLocked(ActivityRecord r) 返回activity是否在stack中
  • moveToFront函数把stack移动到前台,并且如果指定了tsak参数,把task移动到前台
  /**
     * @param reason The reason for moving the stack to the front.
     * @param task If non-null, the task will be moved to the top of the stack.
     * */
    void moveToFront(String reason, TaskRecord task) {
        if (!isAttached()) {
  
  //1 没有attach不操作
            return;
        }

        mStacks.remove(this);
        int addIndex = mStacks.size();

        if (addIndex > 0) {
            final ActivityStack topStack = mStacks.get(addIndex - 1);
            if (StackId.isAlwaysOnTop(topStack.mStackId) && topStack != this) {
            //2 画中画的stack永远在最上面,添加到倒数第二个的位置
                // If the top stack is always on top, we move this stack just below it.
                addIndex--;
            }
        }
        //3 添加到计算出的位置
        mStacks.add(addIndex, this);

        // TODO(multi-display): Needs to also work if focus is moving to the non-home display.
        if (isOnHomeDisplay()) { //4 设置为焦点stack
            mStackSupervisor.setFocusStackUnchecked(reason, this);
        }
        if (task != null) { 
            insertTaskAtTop(task, null);
        } else {
            task = topTask();
        }
        //4移动task到顶部,通过WMS移动window
        if (task != null) {
            mWindowManager.moveTaskToTop(task.taskId);
        }
    }
  • isFocusable 返回stack是否能够获取焦点,除了画中画所在的stack,其他都默认可以接收事件,获取焦点。 对于画中画所在的stack要看它的top activity能否获取焦点
  • findTaskLocked函数比较重要,是在startActivity过程中寻找复用的task过程中使用的函数
void findTaskLocked(ActivityRecord target, FindTaskResult result) {
        Intent intent = target.intent;
        ActivityInfo info = target.info;
        ComponentName cls = intent.getComponent();
        if (info.targetActivity != null) {
        //1 指定了targetActivity的情况以target为准,
        //AndroidManifest中可以配置,一种解耦的手段
            cls = new ComponentName(info.packageName, info.targetActivity);
        }
        //2 document task的话要匹配指定的data,所以这里获取documentData
        final int userId = UserHandle.getUserId(info.applicationInfo.uid);
        boolean isDocument = intent != null & intent.isDocument();
        // If documentData is non-null then it must match the existing task data.
        Uri documentData = isDocument ? intent.getData() : null;

        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
        //3 遍历task,只是匹配task的top activity
        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
            final TaskRecord task = mTaskHistory.get(taskNdx);
            //4 voiceSession不做考虑
            if (task.voiceSession != null) {
                // We never match voice sessions; those always run independently.
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
                continue;
            }
            //5 user不匹配不做考虑
            if (task.userId != userId) {
                // Looking for a different task.
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
                continue;
            }
            //6 空task,finish的activity和user不匹配,LAUNCH_SINGLE_INSTANCE的activity不匹配。LAUNCH_SINGLE_INSTANCE的情况使用另外一个函数寻找
            final ActivityRecord r = task.getTopActivity();
            if (r == null || r.finishing || r.userId != userId ||
                    r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
                continue;
            }
            //7 类型不匹配的跳过
            if (r.mActivityType != target.mActivityType) {
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
                continue;
            }

            final Intent taskIntent = task.intent;
            final Intent affinityIntent = task.affinityIntent;
            final boolean taskIsDocument;
            final Uri taskDocumentData;
            //8 计算task的document模式和data
            if (taskIntent != null && taskIntent.isDocument()) {
                taskIsDocument = true;
                taskDocumentData = taskIntent.getData();
            } else if (affinityIntent != null && affinityIntent.isDocument()) {
                taskIsDocument = true;
                taskDocumentData = affinityIntent.getData();
            } else {
                taskIsDocument = false;
                taskDocumentData = null;
            }

            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
                    + taskIntent.getComponent().flattenToShortString()
                    + "/aff=" + r.task.rootAffinity + " to new cls="
                    + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
            // TODO Refactor to remove duplications. Check if logic can be simplified.
            //9 先根据Component查找,优先级最高
            if (taskIntent != null && taskIntent.getComponent() != null &&
                    taskIntent.getComponent().compareTo(cls) == 0 &&
                    Objects.equals(documentData, taskDocumentData)) {
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
                //dump();
                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
                        "For Intent " + intent + " bringing to top: " + r.intent);
                result.r = r;
                result.matchedByRootAffinity = false;
                break;
             //10 按照粘性复用,必须要匹配document data
            } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
                    affinityIntent.getComponent().compareTo(cls) == 0 &&
                    Objects.equals(documentData, taskDocumentData)) {
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
                //dump();
                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
                        "For Intent " + intent + " bringing to top: " + r.intent);
                result.r = r;
                result.matchedByRootAffinity = false;
                break;
            //11 根据rootAffinity匹配,也就是根节点的资源粘性,这种情况不跳出循环,默认的taskAffinity就是包名
            } else if (!isDocument && !taskIsDocument
                    && result.r == null && task.canMatchRootAffinity()) {
                if (task.rootAffinity.equals(target.taskAffinity)) {
                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
                    // It is possible for multiple tasks to have the same root affinity especially
                    // if they are in separate stacks. We save off this candidate, but keep looking
                    // to see if there is a better candidate.
                    result.r = r;
                    result.matchedByRootAffinity = true;
                }
            } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
        }
    }
  • 这个就是findActivityLocked用于寻找可以复用的activity
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
                                      boolean compareIntentFilters) {
        //1 计算目标   ComponentName                          
        ComponentName cls = intent.getComponent();
        if (info.targetActivity != null) {
            cls = new ComponentName(info.packageName, info.targetActivity);
        }
        final int userId = UserHandle.getUserId(info.applicationInfo.uid);
        //2 遍历task
        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
            final TaskRecord task = mTaskHistory.get(taskNdx);
            final boolean notCurrentUserTask =
                    !mStackSupervisor.isCurrentProfileLocked(task.userId);
            final ArrayList<Activ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TangGeeA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值