ActivityStackSupervisor分析

本文详细探讨了Android系统中ActivityStackSupervisor的几个关键功能,包括dismissKeyguard()的解锁逻辑、resumeHomeActivity()的行为、TaskRecord的mOnTopOfHome属性的意义及其应用场景。通过分析源码,揭示了Android如何管理HomeStack和其他ActivityStack,以及在任务切换、销毁等活动中的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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
AMS(Activity Manager Service)是 Android 系统中的一个重要组件,主要负责管理应用程序的生命周期和任务栈。AMS 的启动流程是 Android 系统中的一个核心流程,下面我们来简单分析一下其启动流程的代码实现。 AMS 的启动流程可以分为以下几个步骤: 1. 接收启动请求 AMS 接收到启动请求后会将请求封装成一个 ActivityRecord 对象,并将该对象加入到 ActivityStackSupervisor 中的 mPendingActivityLaunches 队列中等待处理。 2. 处理启动请求 ActivityStackSupervisor 中的 mPendingActivityLaunches 队列中的 ActivityRecord 对象会被逐个处理,AMS 会根据启动请求的类型(new task、single task、single top、single instance、standard)以及启动模式(standard、singleTop、singleTask、singleInstance)来决定如何启动 Activity。 3. 构建 Intent AMS 在处理启动请求时会根据传入的参数构建一个 Intent 对象,Intent 对象中包含了要启动的 Activity 类名、Intent 的类型、Action、Data 等信息。 4. 查找合适的 Activity 栈 AMS 会根据 Intent 对象的启动模式以及任务栈顶的 Activity 情况来查找合适的 Activity 栈。如果是新任务或者 singleTask 启动模式,则会创建一个新的任务栈;如果是 singleInstance 启动模式,则会创建一个独立的任务栈。 5. 启动 Activity AMS 会根据查找到的 Activity 栈信息来启动 Activity。如果是 standard 启动模式,则会创建一个新的 Activity 实例并加入到任务栈中;如果是 singleTop 启动模式,则会检查任务栈顶部的 Activity 是否与要启动的 Activity 类型相同,如果相同则不创建新的 Activity 实例,否则新建一个 Activity 实例并加入到任务栈中;如果是 singleTask 启动模式,则会检查任务栈中是否已经存在该 Activity 类型的实例,如果存在则将该实例移到栈顶,否则创建新的 Activity 实例并加入到任务栈中;如果是 singleInstance 启动模式,则会创建一个新的任务栈并将该 Activity 实例放入其中。 6. 更新任务栈信息 AMS 在启动 Activity 后会更新任务栈的相关信息,包括任务栈中 Activity 的数量、栈顶 Activity 的信息、任务栈是否为空等。 以上就是 AMS 的启动流程代码分析的简单介绍。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值