ActivityStackSupervisor分析

文章仅记录自己的一点分析过程,供日后参考。

1.dismissKeyguard()

先看下这个函数功能:

  void dismissKeyguard() {
        if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
        if (mDismissKeyguardOnNextActivity) {
            mDismissKeyguardOnNextActivity = false;
            mWindowManager.dismissKeyguard();
        }
    }
函数很简单,判断mDismissKeyguardOnNextActivity为true,然后调用mWindowManager.dismissKeyguard()-->PhoneWindowManager.dismissKeyguardLw().
   public void dismissKeyguardLw() {
        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { 
            mHandler.post(new Runnable() {
                public void run() {
                    if (mKeyguardDelegate.isDismissable()) {
                        // Can we just finish the keyguard straight away?
                        mKeyguardDelegate.keyguardDone(false, true);
                    } else {
                        // ask the keyguard to prompt the user to authenticate if necessary
                        mKeyguardDelegate.dismiss();
                    }
                }
            });
        }
    }
上面的代码逻辑是如果keyguard当前是显示状态,那么就进行解锁,否则直接返回。解锁时再判断当前keyguard是否设置了密码保护,如果设置了那么走mKeyguardDelegate.dismiss(),如果没设置,那就调用mKeyguardDelegate.keyguardDone(false, true)直接解锁keyguard。

dismissKeyguard()函数就是提供了一个给AMS侧使用的解锁keyguard接口。但是能不能调用真正解锁还得过mDismissKeyguardOnNextActivity变量这一关呀,这个变量在dismissKeyguardOnNextActivity()-->setDismissKeyguard(true)中赋值为true。dismissKeyguardOnNextActivity()是提供给launcher应用使用的。然而在AMS中的很多地方又调用setDismissKeyguard(false),一般情况是在startActivityLocked()一个activity,当出现权限等异常情况时调用。

2.resumeHomeActivity(ActivityRecord prev)

   boolean resumeHomeActivity(ActivityRecord prev) {
        moveHomeToTop();
        if (prev != null) {
            prev.task.mOnTopOfHome = false;
        }
        ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
        if (r != null && r.isHomeActivity()) {
            mService.setFocusedActivityLocked(r);
            return resumeTopActivitiesLocked(mHomeStack, prev, null);
        }
        return mService.startHomeActivityLocked(mCurrentUser);
    }
函数首先调用moveHomeToTop()来将HomeStack移到前台,然后再把launcher所在的Task移到顶端,这样下面调用resumeTopActivitiesLocked()时便能找到正确的ActivityStack和Task来启动。有个小细节需要注意的是:如果prev不为null,表示是从pre直接起launcher的,此时将prev.task.mOnTopOfHome设为FALSE。

3.TaskRecord.mOnTopOfHome

为什么要设为FALSE?要搞清这个问题需要完全理解mOnTopOfHome这个变量的设计思想。源码对mOnTopOfHome的解释如下:

/** Launch the home activity when leaving this task. */
只要是TaskRecord设置了mOnTopOfHome为true,待leaving这个Task时便回到桌面,这个解释是绝对正确的吗?还有什么叫leaving this task?这个得好好研究下。要研究清楚mOnTopOfHome,必然要研究使用mOnTopOfHome的各种场景,从场景中还原出最准确的理解。mOnTopOfHome作为判断条件的地方只有7处,分别在removeTask()、moveTaskToBackLocked()、removeActivityFromHistoryLocked()、adjustFocusedActivityLocked()、resumeTopActivityLocked()、isActivityOverHome()六个函数中。下面来一个个研究这几个函数(还好不多)。

㈠、isActivityOverHome()

/**
     * Determine if home should be visible below the passed record.
     * @param record activity we are querying for.
     * @return true if home is visible below the passed activity, false otherwise.
     */
    boolean isActivityOverHome(ActivityRecord record) {
        // Start at record and go down, look for either home or a visible fullscreen activity.
        final TaskRecord recordTask = record.task;
        for (int taskNdx = mTaskHistory.indexOf(recordTask); taskNdx >= 0; --taskNdx) {
            TaskRecord task = mTaskHistory.get(taskNdx);
            final ArrayList<ActivityRecord> activities = task.mActivities;
            final int startNdx =
                    task == recordTask ? activities.indexOf(record) : activities.size() - 1;
            for (int activityNdx = startNdx; activityNdx >= 0; --activityNdx) {
                final ActivityRecord r = activities.get(activityNdx);
                if (r.isHomeActivity()) {
                    return true;
                }
                if (!r.finishing && r.fullscreen) {
                    // Passed activity is over a fullscreen activity.
                    return false;
                }
            }
            if (task.mOnTopOfHome) {
                // Got to the bottom of a task on top of home without finding a visible fullscreen
                // activity. Home is visible.
                return true;
            }
        }
        // Got to the bottom of this stack and still don't know. If this is over the home stack
        // then record is over home. May not work if we ever get more than two layers.
        return mStackSupervisor.isFrontStack(this);
    }

这个函数非常好理解,解释已经说得很清楚了,就是判断launcher是否会显示在参数给出的Activity之下。首先明白Activity是处在一个ActivityTask中的,所以逻辑就变成了判断launcher是否会显示在参数给出的Activity所在的ActivityTask中的所有Activity之下。这个说法还不太精确,准备的说是所处ActivityTask的参数Activity及以下的所有Activity。如果在这些Activity中找到一个全屏的,并且没有被finish的Activity,那么表示launcher就不会显示在参数Activity之下。如果在 这个Task中没有找到符合那两个条件的Activity,那么就看task.mOnTopOfHome是否为true, 如果为true,那么就返回true;如果整个Stack中都还没确认是否显示launcher,那么就依据mStackSupervisor.isFrontStack(this)来判断,其实这是由bug的,做多窗口时这个地方肯定要做修改,注释也说明了多于2个stack就会有问题。

从这个函数中已经隐约知道这个mOnTopOfHome变量的作用了,在Android4.4之前,只有一个Stack,所有的Task都放在mTaskHistoty中,现在有两个(多窗口有多个)ActivityStack,Task的管理变得相对来说复杂一些了,还好Google把其中一个ActivityStack定制为HomeStack,一般情况可认为就代表着launcher。那么问题来了?不是挖掘机哪家强的问题,是如何统一管理HomeStack跟另一个activityStack中的Task,Google借助了mOnTopOfHome这个属性,虽然有两个mTaskHistory,但你可以根据ActivityTask.mOnTopOfHome的值把这两个mTaskHistory合成一个mTaskHistory。反过来说就是Android 4.4 把Android 4.4之前的一个ActivityStack中的所有Task拆分到两个ActivityStack中,拆分规则就是把launcher和后台Activity拆分到一个ActivityStack(HomeStack)中,其他的所有Task放在另一个ActivityStack中,但是所有的Task还是要维持像4.4之前只有一个mTaskHistory那样后进后出的逻辑,比如从launcher启动微信,微信又启动相机,那么在非HomeStack中相机Task在栈顶,launcher最低,然而launcher Task又不在这个非HomeStack中管理,这个时候就需要mOnTopOfHome来标注一下微信所在Task之下就应该是launcher所在的Task。这样就达到了所有Task的统一管理。

所以mOnTopOfHome应该这么理解:mOnTopOfHome=true表示在整个Task栈管理中,当前这个Task紧着的下一个Task就是launcher所在的Task。嗯,这么理解,上面的isActivityOverHome()就变得更加容易理解了。相信后面那5个函数理解起来也非常容易理解了,都不用看了。哈哈,太开心了有没有。

㈡、ActivityStack.removeTask()

   boolean removeTask(TaskRecord task) {
        final int taskNdx = mTaskHistory.indexOf(task);
        final int topTaskNdx = mTaskHistory.size() - 1;
        if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
            mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
        }
        mTaskHistory.remove(task);
        return mTaskHistory.isEmpty();
    }
在整个Task管理中,如果移除的Task的mOnTopOfHome值为true,并且该Task不位于栈顶,那么肯定要把该Task的上一个Task.mOnTopOfHome设为true,不然逻辑就不对了。如果移除的Task位于栈顶或是mOnTopOfHome值不为true,那就直接remove掉即可。
㈢、ActivityStack.moveTaskToBackLocked()

  /**
     * Worker method for rearranging history stack. Implements the function of moving all
     * activities for a specific task (gathering them if disjoint) into a single group at the
     * bottom of the stack.
     *
     * If a watcher is installed, the action is preflighted and the watcher has an opportunity
     * to premeptively cancel the move.
     *
     * @param taskId The taskId to collect and move to the bottom.
     * @return Returns true if the move completed, false if not.
     */
    final boolean moveTaskToBackLocked(int taskId, ActivityRecord reason) {
        Slog.i(TAG, "moveTaskToBack: " + taskId);

        // If we have a watcher, preflight the move before committing to it.  First check
        // for *other* available tasks, but if none are available, then try again allowing the
        // current task to be selected.
        if (mStackSupervisor.isFrontStack(this) && mService.mController != null) {   //①一般mController 为null,所以这个逻辑不执行。

            ActivityRecord next = topRunningActivityLocked(null, taskId);
            if (next == null) {
                next = topRunningActivityLocked(null, 0);
            }
            if (next != null) {
                // ask watcher if this is allowed
                boolean moveOK = true;
                try {
                    moveOK = mService.mController.activityResuming(next.packageName);
                } catch (RemoteException e) {
                    mService.mController = null;
                    Watchdog.getInstance().setActivityController(null);
                }
                if (!moveOK) {
                    return false;
                }
            }
        }

        if (DEBUG_TRANSITION) Slog.v(TAG,
                "Prepare to back transition: task=" + taskId);

        final TaskRecord tr = taskForIdLocked(taskId);
        if (tr == null) {
            return false;
        }

        mTaskHistory.remove(tr);    //②将指定的Task移到mTaskHistory的最低端。
        mTaskHistory.add(0, tr);

        // There is an assumption that moving a task to the back moves it behind the home activity.
        // We make sure here that some activity in the stack will launch home.
        ActivityRecord lastActivity = null;
        int numTasks = mTaskHistory.size();
        for (int taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {   //③Task移到最低端还不够,还需一个Task.mOnTopOfHome设为true;

            final TaskRecord task = mTaskHistory.get(taskNdx);
            if (task.mOnTopOfHome) {
                break;
            }
            if (taskNdx == 1) {
                // Set the last task before tr to go to home.
                task.mOnTopOfHome = true;
            }
        }

        if (reason != null &&
                (reason.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
            ActivityRecord r = topRunningActivityLocked(null);
            if (r != null) {
                mNoAnimActivities.add(r);
            }
        } else {
            mWindowManager.prepareAppTr
  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值