AMS干货技能:如何监听Task前后台切换事件之TaskStackListener原理剖析

背景:

原文参考:https://mp.weixin.qq.com/s/a7-miyycYYOeOO_ijZ5tDA
在平常系统开发过程中,经常有需求可能需要监听当前系统前台展示的Activity是哪个?什么时候Activity退出了?当前分屏的显示的是哪个Task,分屏是不是退出了?

普通全屏Activity相关:
比如下图有普通Activity跳转常见行为
在这里插入图片描述需求就是需要看看当前哪个Activity或者app在前台。
分屏Activity相关:
经常会有Activity进入分屏模式,进入后有退出分屏模式,回到Activity全屏
在这里插入图片描述需求也是需要监听当前Activity是否还处于分屏还是全屏,分屏和全屏时候分别哪些Activity,分屏的side和main对应的Activity是谁?

这些监听AMS中Activity的情况需求还是非常常见,马哥在系统应用中也找到了相关的一些实现案例,今天马哥带大家来一起实战剖析一下如何监听AMS这些Activity状态。

源码及实战案例剖析

下面针对上面的需求,这里分别进行介绍相关的接口

普通全屏Activity相关的监听接口
frameworks/base/core/java/android/app/TaskStackListener.java


/**
 * Classes interested in observing only a subset of changes using ITaskStackListener can extend
 * this class to avoid having to implement all the methods.
 *
 * @hide
 */
public abstract class TaskStackListener extends ITaskStackListener.Stub {

    /** Whether this listener and the callback dispatcher are in different processes. */
    private boolean mIsRemote = true;

    @UnsupportedAppUsage
    public TaskStackListener() {
    }

    /** Indicates that this listener lives in system server. */
    public void setIsLocal() {
        mIsRemote = false;
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onTaskStackChanged() throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityPinned(String packageName, int userId, int taskId, int rootTaskId)
            throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityUnpinned() throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
            boolean clearedTask, boolean wasVisible) throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityForcedResizable(String packageName, int taskId, int reason)
            throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityDismissingDockedTask() throws RemoteException {
    }

    @Override
    public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
            int requestedDisplayId) throws RemoteException {
        onActivityLaunchOnSecondaryDisplayFailed();
    }

    /**
     * @deprecated see {@link
     *         #onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo, int)}
     */
    @Deprecated
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityLaunchOnSecondaryDisplayFailed() throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo,
            int requestedDisplayId) throws RemoteException {
    }

    @Override
    public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onTaskRemoved(int taskId) throws RemoteException {
    }

    @Override
    public void onTaskMovedToFront(RunningTaskInfo taskInfo)
            throws RemoteException {
        onTaskMovedToFront(taskInfo.taskId);
    }

    /**
     * @deprecated see {@link #onTaskMovedToFront(RunningTaskInfo)}
     */
    @Deprecated
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onTaskMovedToFront(int taskId) throws RemoteException {
    }

    @Override
    public void onTaskRemovalStarted(RunningTaskInfo taskInfo)
            throws RemoteException {
        onTaskRemovalStarted(taskInfo.taskId);
    }

    /**
     * @deprecated see {@link #onTaskRemovalStarted(RunningTaskInfo)}
     */
    @Deprecated
    public void onTaskRemovalStarted(int taskId) throws RemoteException {
    }

    @Override
    public void onTaskDescriptionChanged(RunningTaskInfo taskInfo)
            throws RemoteException {
        onTaskDescriptionChanged(taskInfo.taskId, taskInfo.taskDescription);
    }

    /**
     * @deprecated see {@link #onTaskDescriptionChanged(RunningTaskInfo)}
     */
    @Deprecated
    public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td)
            throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation)
            throws RemoteException {
    }

    @Override
    public void onTaskProfileLocked(RunningTaskInfo taskInfo, int userId)
            throws RemoteException {
        onTaskProfileLocked(taskInfo);
    }

    /**
     * @deprecated see {@link #onTaskProfileLocked(RunningTaskInfo, int)}
     */
    @Deprecated
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onTaskProfileLocked(RunningTaskInfo taskInfo)
            throws RemoteException {
    }

    @Override
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) throws RemoteException {
        if (mIsRemote && snapshot != null && snapshot.getHardwareBuffer() != null) {
            // Preemptively clear any reference to the buffer
            snapshot.getHardwareBuffer().close();
        }
    }

    @Override
    public void onTaskSnapshotInvalidated(int taskId) { }

    @Override
    public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo)
            throws RemoteException {
    }

    @Override
    public void onTaskDisplayChanged(int taskId, int newDisplayId) throws RemoteException {
    }

    @Override
    public void onRecentTaskListUpdated() throws RemoteException {
    }

    @Override
    public void onRecentTaskListFrozenChanged(boolean frozen) {
    }

    @Override
    public void onTaskFocusChanged(int taskId, boolean focused) {
    }

    @Override
    public void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
    }

    @Override
    public void onActivityRotation(int displayId) {
    }

    @Override
    public void onTaskMovedToBack(RunningTaskInfo taskInfo) {
    }

    @Override
    public void onLockTaskModeChanged(int mode) {
    }
}

上面就是经典的监听系统task相关的情况的TaskStackListener,task变化的相关回调方法很多,它实际上是一个binder的实现端 ITaskStackListener.Stub,它的客户调用端,那当然是ATMS端。

看看TaskStackListener的使用方式:
一般TaskStackListener都是需要进行继承使用

    private class Impl extends TaskStackListener implements Handler.Callback {

然后把这里的Impl进行注册到ATMS中

                    ActivityTaskManager.getService().registerTaskStackListener(this);

如果不需要监听了请记得注销

                    ActivityTaskManager.getService().unregisterTaskStackListener(this);

注册后就可以针对自己感兴趣的一些回调进行处理。

最常用的就是如下这些接口:

    default void onTaskCreated(int taskId, ComponentName componentName) { }
    default void onTaskRemoved(int taskId) { }
    default void onTaskMovedToFront(int taskId) { }

    default void onTaskMovedToFront(RunningTaskInfo taskInfo) {
        onTaskMovedToFront(taskInfo.taskId);
    }

这块的具体继承使用TaskStackListener大家可以参考aosp源码

frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
在这里插入图片描述可以看到这里接收到了系统短的binder调用后,立即是通过handler把消息转到自己的handler线程中进行处理,主要还是为了性能等情况考虑。

ATMS端通知TaskStackListener原理

先看看注册的方法:

ActivityTaskManager.getService().registerTaskStackListener(this);

调用后直接调用到system_server进程的ActivityTaskManagerService

frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java


    /** Sets the task stack listener that gets callbacks when a task stack changes. */
    @Override
    public void registerTaskStackListener(ITaskStackListener listener) {
        enforceTaskPermission("registerTaskStackListener()");
        mTaskChangeNotificationController.registerTaskStackListener(listener);
    }

再看看mTaskChangeNotificationController的registerTaskStackListener方法

    public void registerTaskStackListener(ITaskStackListener listener) {
        if (listener instanceof Binder) {//一般系统自己进程的注册
            synchronized (mLocalTaskStackListeners) {
                if (!mLocalTaskStackListeners.contains(listener)) {
                    if (listener instanceof TaskStackListener) {
                        ((TaskStackListener) listener).setIsLocal();
                    }
                    mLocalTaskStackListeners.add(listener);
                }
            }
        } else if (listener != null) {//一般系统app属于远端,走这个
            synchronized (mRemoteTaskStackListeners) {
                mRemoteTaskStackListeners.register(listener);
            }
        }
    }

远端最后保存在mCallbacks这个集合中

 /**
     * Add a new callback to the list.  This callback will remain in the list
     * until a corresponding call to {@link #unregister} or its hosting process
     * goes away.  If the callback was already registered (determined by
     * checking to see if the {@link IInterface#asBinder callback.asBinder()}
     * object is already in the list), then it will be left as-is.
     * Registrations are not counted; a single call to {@link #unregister}
     * will remove a callback after any number calls to register it.
     *
     * @param callback The callback interface to be added to the list.  Must
     * not be null -- passing null here will cause a NullPointerException.
     * Most services will want to check for null before calling this with
     * an object given from a client, so that clients can't crash the
     * service with bad data.
     *
     * @param cookie Optional additional data to be associated with this
     * callback.
     * 
     * @return Returns true if the callback was successfully added to the list.
     * Returns false if it was not added, either because {@link #kill} had
     * previously been called or the callback's process has gone away.
     *
     * @see #unregister
     * @see #kill
     * @see #onCallbackDied
     */
    public boolean register(E callback, Object cookie) {

            IBinder binder = callback.asBinder();
            try {
                Callback cb = new Callback(callback, cookie);//创建Callback
                unregister(callback);
                binder.linkToDeath(cb, 0);
                mCallbacks.put(binder, cb);//放入集合
                return true;
      
    }

那么什么时候mTaskChangeNotificationController通知呢?

这里就需要到各个Task的操作业务中去看,这里以TaskRemove为案例剖析:
Task中触发removeIfPossible方法时候会调用mTaskChangeNotificationController进行通知
frameworks/base/services/core/java/com/android/server/wm/Task.java

void removeIfPossible(String reason) {
    
        removeImmediately(reason);
        if (isLeafTask) {
            //mTaskChangeNotificationController进行通知notifyTaskRemoved
            mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);

         
    }

对应通知方法:
frameworks/base/services/core/java/com/android/server/wm/TaskChangeNotificationController.java

   void notifyTaskRemoved(int taskId) {
   //构造一个NOTIFY_TASK_REMOVED_LISTENERS_MSG的msg,注意msg中第一个arg是taskId
        final Message msg = mHandler.obtainMessage(NOTIFY_TASK_REMOVED_LISTENERS_MSG,
                taskId, 0 /* unused */);
                //注意这里传递是mNotifyTaskRemoved
         //这个是回调自己的local listener
        forAllLocalListeners(mNotifyTaskRemoved, msg);
        //发送msg,主要是进行跨进程回调
        msg.sendToTarget();
    }

本地端回调可以,看看mNotifyTaskRemoved

   private final TaskStackConsumer mNotifyTaskRemoved = (l, m) -> {
        l.onTaskRemoved(m.arg1);
    };

实际上就是个lamada表达式,会调用第一个参的onTaskRemoved。

这里重点看看远端的handler处理。
再看看forAllLocalListeners通知所有的listeners


 private class MainHandler extends Handler {
        public MainHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                    case NOTIFY_TASK_REMOVED_LISTENERS_MSG:
                    forAllRemoteListeners(mNotifyTaskRemoved, msg);
                    break;

frameworks/base/services/core/java/com/android/server/wm/TaskChangeNotificationController.java

    private void forAllRemoteListeners(TaskStackConsumer callback, Message message) {
        synchronized (mRemoteTaskStackListeners) {
            for (int i = mRemoteTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
                try {
                //使用前面register构造的Callback进行回调到远端
                    // Make a one-way callback to the listener
                    callback.accept(mRemoteTaskStackListeners.getBroadcastItem(i), message);
                } catch (RemoteException e) {
                    // Handled by the RemoteCallbackList.
                }
            }
            mRemoteTaskStackListeners.finishBroadcast();
        }
    }

实战监听log打印

下面来展示一下上面的TaskStackListener监听的效果,这块我们就直接使用Launcher代码中TopTaskTracker类来进行实战测试,通过log打印既可以看出Task相关变化

packages/apps/Launcher3/quickstep/src/com/android/quickstep/TopTaskTracker.java
在这里插入图片描述
操作桌面点击进入Activity,然后退出Activity,看看日志的输出情况:

test@test:~/aosp15/development/samples$ adb logcat -s TopTaskTracker



--------- beginning of main
//桌面点击dialer到前台
11-12 11:23:04.895  1226  1226 I TopTaskTracker: onTaskMovedToFront: (moved taskInfo to front) taskId=148, baseIntent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 pkg=com.android.dialer cmp=com.android.dialer/.main.impl.MainActivity }

//dialer退出前台,桌面到前台
11-12 11:23:10.619  1226  1226 I TopTaskTracker: onTaskMovedToFront: (moved taskInfo to front) taskId=147, baseIntent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.uioverrides.QuickstepLauncher }

//在recent中移除dialer的task
11-12 11:23:22.853  1226  1226 I TopTaskTracker: onTaskRemoved: taskId=148
11-12 11:23:22.853  1226  1226 I TopTaskTracker: onTaskRemoved: taskId=148

更多framework实战开发干货,请关注下面“千里马学框架”

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

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

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

打赏作者

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

抵扣说明:

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

余额充值