深入理解AMS之Activity管理

深入探讨Android系统中Activity的生命周期状态,ActivityRecord、TaskRecord的管理机制,以及ActivityStackSupervisor如何调整堆栈焦点,实现不同Activity的切换与管理。

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

Activity状态

  Activity在应用端由ActivityClientRecord负责描述其生命周期的过程与状态,但最终这些过程与状态是由ActivityManagerService(以下简称AMS)来管理和控制的。类似于应用进程在AMS中使用ProcessRecord描述,安卓四大组件在AMS中也拥有对应的对象来描述。

  • BroadcastRecord:描述了应用进程的BroadcastReceiver,由BroadcastQueue负责管理。
  • ServiceRecord:描述了Service服务组件,由ActiveServices负责管理。
  • ContentProviderRecord:描述ContentProvider内容提供者,由ProviderMap管理。
  • ActivityRecord:用于描述Activity,由ActivityStackSupervisor进行管理。

  正如深入理解AMS之Activity对Activity的介绍那样,Activity直观上来说就意指一个个的窗口页面。安卓为了有效管理窗口页面的交互过程与状态,衍生出了Activity生命周期的概念。AMS为了管理Activity在这些生命周期间的状态迁移,定义了如下Activity可能经历到的状态:

// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java$ActivityState
    enum ActivityState {
        INITIALIZING,//正在初始化
        RESUMED,//恢复前台状态
        PAUSING,//正在暂停
        PAUSED,//暂停状态
        STOPPING,//正在停止
        STOPPED,//停止状态
        FINISHING,//正在移除
        DESTROYING,//正在销毁
        DESTROYED//销毁状态
    }

  上述这些状态并不难理解,其中某些状态的定义甚至与Activity生命周期方法暗暗相合。ActivityRecord中的state成员正是为了描述其对应的Activity所处的状态。

// frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
    ActivityState state;    // current state we are in

管理者的诞生

  在AMS中,ActivityStackSupervisor(以下简称ASS)负责管理Activity,从其类名含义上而言,ActivityStack是Activity任务栈,Supervisor意为监管者,两者合而为一也很清晰地表明了ASS的作用。

  ASS在深入理解AMS之启动过程一文中介绍AMS构造方法时被创建。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    public ActivityStackSupervisor(ActivityManagerService service) {
        mService = service;
        mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
    }

  在ASS构造方法中获取了在AMS中创建的ServiceThread线程(这个线程本质上是一个HandlerThread线程)的Looper,并据此创建了属于ASS独有的Handler,此后往这个mHandler发送的Message最终都会在AMS的服务线程中执行。

  在ASS被创建完成后并不意味着这个管理者可以立即为Activity服务了,事实上Activity创建时需要指定显示屏幕(一般情况下,使用了默认屏幕所以可以不指定)和创建Window窗口,这就还需要等待DMS与WMS初始化完成,在SystemServer中DMS与WMS先后完成初始化后会调用AMS.setWindowManager()方法并进而通知ASS。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java#setWindowManager
    void setWindowManager(WindowManagerService wm) {
        synchronized (mService) {
            mWindowManager = wm;
            mDisplayManager =
                    (DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE);
            mDisplayManager.registerDisplayListener(this, null);

            Display[] displays = mDisplayManager.getDisplays();
            for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) {
                final int displayId = displays[displayNdx].getDisplayId();
                ActivityDisplay activityDisplay = new ActivityDisplay(displayId);
                if (activityDisplay.mDisplay == null) {
                    throw new IllegalStateException("Default Display does not exist");
                }
                mActivityDisplays.put(displayId, activityDisplay);
            }
            createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY);
            mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);
            //...
        }
    }

  当代码进行到此处,ASS就要着手准备Activity的管理环境了。在介绍上述代码的作用之前,有几个必要的类需要先了解一下:

  • ActivityDisplay。在ASS中用于描述显示屏幕,其构造方法传入其负责描述屏幕的displayId,这样ActivityDisplay创建时就可据此知道其所描述屏幕的各项属性。ASS中所有的ActivityDisplay都会被保存在成员mActivityDisplays中。
// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java$ActivityDisplay
    class ActivityDisplay {
        //...
        final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
        
        ActivityDisplay(int displayId) {
            final Display display = mDisplayManager.getDisplay(displayId);
            if (display == null) {
                return;
            }
            init(display);
        }

        void init(Display display) {
            mDisplay = display;
            mDisplayId = display.getDisplayId();
            mDisplay.getDisplayInfo(mDisplayInfo);
        }
        //...
    }

  在ActivityDisplay中有个非常重要的集合mStacks,这个集合管理了其所描述的显示屏幕的所有ActivityStack,换言之,此屏幕上的所有ActivityStack都在此集合中有记录,可以通过attachActivities()和detachActivitiesLocked()方法来增删这些ActivityStack。

  除此之外,在ASS中还提供了对虚拟屏幕的显示需求的类VirtualActivityDisplay类(继承自ActivityDisplay),这个描述类的构造方法需要传入虚拟屏幕的宽、高、屏幕密度,之后通过DMS的createVirtualDisplay将这个display构建出来。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java$VirtualActivityDisplay
    class VirtualActivityDisplay extends ActivityDisplay {
        VirtualDisplay mVirtualDisplay;
        VirtualActivityDisplay(int width, int height, int density) {
            DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
            mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, null,
                    VIRTUAL_DISPLAY_BASE_NAME, width, height, density, null,
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY, null, null);//根据参数构建虚拟屏幕
            init(mVirtualDisplay.getDisplay());
            mWindowManager.handleDisplayAdded(mDisplayId);//通知WMS屏幕增加
        }
  • ActivityContainer。ActivityStack的容器类,它负责描述ActivityStack,包括其StackId、所属Display、容器状态等。ActivityContainer继承自IActivityContainer.Stub,支持binder调用,显而易见的是,它与其负责描述ActivityStack是一对一关系。
// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java$ActivityContainer
    class ActivityContainer extends android.app.IActivityContainer.Stub {
        //...
        final int mStackId;
        IActivityContainerCallback mCallback = null;
        final ActivityStack mStack;
        //...
        ActivityDisplay mActivityDisplay;
        int mContainerState = CONTAINER_STATE_HAS_SURFACE;

        ActivityContainer(int stackId) {
            synchronized (mService) {
                mStackId = stackId;
                mStack = new ActivityStack(this);
                //...
            }
        }

  • ActivityStack。Stack在计算机术语中意为FIFO类型的线性栈,此处我们把ActivityStack称为任务栈(之后本文任务栈皆指ActivityStack)。如果我们把向XXX商家付款、与XXX进行微信聊天、上淘宝买手机理解为一个个任务的话,那么这些任务按时间来排序就会形成任务序列,这个任务序列就组成ActivityStack。安卓则对这些任务栈的区分更为严格,在副屏处理的任务会放入副屏任务栈中,由副屏ActivityDisplay进行管理。

  • TaskRecord。TaskRecord是任务记录的意思,如果我们把上淘宝买手机称作一个任务,那么这个任务至少有那么几步操作:1.进淘宝首页搜手机关键词,2.列表页寻找心仪手机,3.进入详情页购买并付款。这几步操作构成了多个Activity页面组成的显示序列,这就是一个TaskRecord,由于按返回按键后会回到上一个显示页面,我们也可以称之为返回栈。在系统中,多个TaskRecord可组成一个ActivityStack,由ActivityStack的成员mTaskHistory负责记录。

  • ActivityRecord。上边已经介绍过,Activity主要用于描述一个Activity。但是需要注意的是:一个ActivityRecord描述了一个启动的Activity,但是一个Activity却可以由于启动方式的原因存在多个ActivityRecord。

  再回到ASS.setWindowManager()方法中,我们可以看见其通过DMS.getDisplays()获取已有的显示屏幕并通过ActivityDisplay来描述这些Display。然后为默认屏幕创建了HomeStack,这个操作通过方法createStackOnDisplay()完成。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    private int createStackOnDisplay(int stackId, int displayId) {
        ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
        if (activityDisplay == null) {
            return -1;
        }

        ActivityContainer activityContainer = new ActivityContainer(stackId);
        mActivityContainers.put(stackId, activityContainer);
        activityContainer.attachToDisplayLocked(activityDisplay);
        return stackId;
    }

  对于主屏也就是DEFAULT_DISPLAY默认屏幕来说,其一般拥有两个ActivityStack:其一为此处创建的HomeStack,主要负责管理Launcher中的安卓桌面和SystemUI中的最近任务列表;另一个就是管理其他应用Activity的NormalStack。这两种Stack及其内容我们可以通过命令dumpsys activity activities查看。

HomeStack与NormalStack本质上都是ActivityStack,此处是基于其功能上的不同才将这两种ActivityStack分别命名。

  安卓系统启动后首先显示的是存放于HomeStack的安卓桌面Launcher,所以ASS在启动时就会将HomeStack初始化,并将其记录为焦点Stack。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java#setWindowManager
        mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);

  上述代码中焦点Stack(即FocusedStack)意指上次启动的Activity所处的Stack,初始情况下将其记录为HomeStack也无可非议,但若之后普通应用Activity启动,则focus会转移到NormalStack身上。为了区分Activity是应该放入HomeStack还是NormalStack中进行管理,每个ActivityRecord都有一个成员变量mActivityType来辨识其类型,ActivityRecord的可能类型如下:

// frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
    static final int APPLICATION_ACTIVITY_TYPE = 0;
    static final int HOME_ACTIVITY_TYPE = 1;
    static final int RECENTS_ACTIVITY_TYPE = 2;

  很容易想象,若当前创建的ActivityRecord类型以HOME或RECENT开头,则应该存入HomeStack进行管理。

ActivityStack

  ASS中的HomeStack和NormalStack分别存放不同类型的ActivityRecord,且对ActivityRecord的实际管理操作也是由它负责。出于管理需要,在ActivityStack中形成了庞大的成员体系。

  下边是用于管理ActivityRecord的集合部分。

ArrayList泛型类型作用
mTaskHistoryTaskRecord管理了属于当前stack的各种Task任务,按时间序列排序,
mLRUActivitiesActivityRecord按LRU排序的所有启动过的Activity,第一个元素为LRU元素
mNoAnimActivitiesActivityRecord集合中的Activity不考虑状态迁移动画

  下边是用于管理ActivityRecord的状态部分。

ActivityRecord作用
mPausingActivity当前正在暂停的Activity
mLastPausedActivity上一个处于暂停状态的Activity
mLastNoHistoryActivity上一个不会有历史记录的Activity
mResumedActivity当前出于恢复状态(即出于前台)的Activity,可能为空
mLastStartedActivity上一个被启动的Activity

  ActivityStack主要负责管理Task任务。当我们调用startActivity()时,ASS会判断当前将要启动的Activity是否需要新的Task,如果需要的话就创建TaskRecord并交由ActivityStack的startActivityLocked()方法来负责执行。

  startActivityLocked()方法具体内容如下所示,我们仅关注其Task任务部分。

// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
    final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) {
        TaskRecord rTask = r.task;
        final int taskId = rTask.taskId;
        if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
        
            insertTaskAtTop(rTask);//把rTask挪至ActivityStack的栈顶
            mWindowManager.moveTaskToTop(taskId);//关联WMS
        }
        TaskRecord task = null;
        //...
        task = r.task;
        task.addActivityToTop(r);//把要启动的ActivityRecord挪至TaskRecord栈顶
        task.setFrontOfTask();//将当前TaskRecord的frontOfTask变量置为true,Stack中其他TaskRecord相应变量置为false。
        r.putInHistory();//将当前ActivityRecord置为可放入history记录中
        //...
        if (doResume) {
            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);//将stack任务栈顶的task恢复,主要是task返回栈中的栈顶Activity恢复。
        }
    }

  上述方法中insertTaskAtTop()方法就是把当前的task放入ActivityStack的成员mTaskHistory中进行管理。

  mTaskHistory中的TaskRecord根据其所处的ActivityStack类型的不同,可以区分为HomeTask及ApplicationTask,这点同ActivityRecord的类型区分极为相似。这种相似性是理所当然的,因为TaskRecord类型的区分主要依据其栈底ActivityRecord元素的类型。由此,TaskRecord中有以下方法判断其自身类型。

// frameworks/base/services/core/java/com/android/server/am/TaskRecord.java
    boolean isHomeTask() {
        return taskType == HOME_ACTIVITY_TYPE;
    }

    boolean isApplicationTask() {
        return taskType == APPLICATION_ACTIVITY_TYPE;
    }

    boolean isOverHomeStack() {
        return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
    }

stack切换

  在介绍Stack切换之前,我们先了解一下FocusedStack的概念。

FocusedStack同HomeStack、NormalStack一样,在本文中都是一个抽象概念而并非具体java类。在ASS管理多ActivityStack的过程中,处于显示状态的ActivityRecord所在的ActivityStack就被成为FocusedStack。系统初始化完成后Launcher桌面处于显示状态,所以HomeStack就被默认设为FocusedStack,但当我们点击桌面上的某个应用后,这时候就是NormalStack处于焦点的了。

  ASS所负责启动的ActivityRecord因为其类型的不同需要存放在不同的ActivityStack中。所以每启动一次Activity,其所处的ActivityStack就需要检查一次是否是当前FocusedStack,如果不是则需要调整FocusedStack,这个调整过程是由下边adjustStackFocus()方法控制的。

  根据要启动的Activity是属于HomeStack还是NormalStack,adjustStackFocus()方法的内容可以据此分为两个分支。我们先来看下HomeStack分支的内容。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {
        final TaskRecord task = r.task;

        // On leanback only devices we should keep all activities in the same stack.
        if (!mLeanbackOnlyDevice &&
                (r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
            //NormalStack分支,此处不展开
        }
        return mHomeStack;
    }

  如上可见,如果当前系统是Leanback TV系统,或者要启动的Activity属于HomeStack所管辖的类型(HOME_ACTIVITY_TYPE或RECENTS_ACTIVITY_TYPE),则adjustStackFocus()方法返回的是HomeStack。否则,则需要调整focus即进入if语句中的NormalStack分支。

  以下即是adjustStackFocus()方法真正要调整focus的完整过程。

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java#adjustStackFocus
            //part1
            if (task != null) {//如果启动r是需要新建Task的,则此处task为空,否则则进入此循环。
                final ActivityStack taskStack = task.stack;
                if (taskStack.isOnHomeDisplay()) {//主屏上的stack
                    if (mFocusedStack != taskStack) {
                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting " +
                                "focused stack to r=" + r + " task=" + task);
                        mFocusedStack = taskStack;
                    } else {
                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                            "adjustStackFocus: Focused stack already=" + mFocusedStack);
                    }
                }
                return taskStack;//如果ActivityRecord是普通应用且指定了Task,则此处变焦后返回stack
            }
            //part2
            final ActivityContainer container = r.mInitialActivityContainer;//r创建时指定
            if (container != null) {
                // The first time put it on the desired stack, after this put on task stack.
                r.mInitialActivityContainer = null;
                return container.mStack;
            }
            //part3
            if (mFocusedStack != mHomeStack && (!newTask ||
                    mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {//主要不是Virtual的,isEligible都返回true
                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                        "adjustStackFocus: Have a focused stack=" + mFocusedStack);
                return mFocusedStack;
            }
            //part4
            final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;//取到主屏上所有stack
            for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = homeDisplayStacks.get(stackNdx);
                if (!stack.isHomeStack()) {
                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                            "adjustStackFocus: Setting focused stack=" + stack);
                    mFocusedStack = stack;
                    return mFocusedStack;
                }
            }
            //part5
			//考虑到第一次adjust情形时normal stack还并未创建
            // Need to create an app stack for this user.
            int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
                    " stackId=" + stackId);
            mFocusedStack = getStack(stackId);
            return mFocusedStack;

这个相应的调整过程如代码中所示的那样可以划分为5种情形。

  1. 当前启动的Activity已找到Task容纳,属于非newTask的情形。如果已有task存放,则可据此找到Task所属ActivityStack,并且如果被启动的Activity是主屏Activity,则可调整focus(说明focus这个概念只有主屏有)。
  2. 当前启动的Activity指定了想要存放的ActivityContainer(即ActivityStack)。ActivityContainer是ActivityStack的容器类,它们是一对一的关系。此处若果指明了启动Activity的存放容器mInitialActivityContainer,就意味着Activity找到了ActivityStack来存放。
  3. 当前处于focus态的ActivityStack并非HomeStack(说明focus至少已调整过一次)。走到此处的Activity显然没有指定其所处的Task,只要当前的focus不是在HomeStack或虚拟出来的Stack上,则直接返回当前FocusedStack。
  4. 当前focus从初始化以来未调整过,但主屏已有多个ActivityStack。此情形则直接找到此Display中栈顶非Home类型的Stack并作为focus返回。
  5. 当前主屏只有HomeStack存在。此情形则需要创建一个新的ActivityStack并指定为FocusedStack以存放ActivityRecord。

  在调整完focus之后一般情况下还需要通过ActivityStack的moveToFront()方法把调整后的FocusedStack置为所属Display的栈顶元素。

// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
    final void moveToFront() {
        if (isAttached()) {
            if (isOnHomeDisplay()) {
                mStackSupervisor.moveHomeStack(isHomeStack());
            }
            mStacks.remove(this);
            mStacks.add(this);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值