背景:
原文参考: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实战开发干货,请关注下面“千里马学框架”
4951

被折叠的 条评论
为什么被折叠?



