AppTask.moveToFront()源码分析

news/2024/12/2 15:31:52/

ActivityManager.AppTask.moveToFront()执行后,导致其他AppTask退到了后台,点击返回直接回到了桌面(HomeScreen),没有回到上一个AppTask。
下面分析一下源码看看为什么其他AppTask退到了后台,如何解决该问题。

@SystemService(Context.ACTIVITY_SERVICE)
public class ActivityManager {/*** The AppTask allows you to manage your own application's tasks.* See {@link android.app.ActivityManager#getAppTasks()}*/public static class AppTask {private IAppTask mAppTaskImpl;/** @hide */public AppTask(IAppTask task) {mAppTaskImpl = task;}/*** Bring this task to the foreground.  If it contains activities, they will be* brought to the foreground with it and their instances re-created if needed.* If it doesn't contain activities, the root activity of the task will be* re-launched.*/public void moveToFront() {try {ActivityThread thread = ActivityThread.currentActivityThread();IApplicationThread appThread = thread.getApplicationThread();String packageName = ActivityThread.currentPackageName();mAppTaskImpl.moveToFront(appThread, packageName);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
/*** An implementation of IAppTask, that allows an app to manage its own tasks via* {@link android.app.ActivityManager.AppTask}.  We keep track of the callingUid to ensure that* only the process that calls getAppTasks() can call the AppTask methods.*/
class AppTaskImpl extends IAppTask.Stub {@Overridepublic void moveToFront(IApplicationThread appThread, String callingPackage) {checkCaller();// Will bring task to front if it already has a root activity.final int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();mService.assertPackageMatchesCallingUid(callingPackage);final long origId = Binder.clearCallingIdentity();try {synchronized (mService.mGlobalLock) {WindowProcessController callerApp = null;if (appThread != null) {callerApp = mService.getProcessController(appThread);}final ActivityStarter starter = mService.getActivityStartController().obtainStarter(null /* intent */, "moveToFront");if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,callingPackage, -1, -1, callerApp, null, false, null)) {if (!mService.isBackgroundActivityStartsEnabled()) {return;}}}mService.mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, mTaskId,null /* options */);} finally {Binder.restoreCallingIdentity(origId);}}
// TODO: This class has become a dumping ground. Let's
// - Move things relating to the hierarchy to RootWindowContainer
// - Move things relating to activity life cycles to maybe a new class called ActivityLifeCycler
// - Move interface things to ActivityTaskManagerService.
// - All other little things to other files.
public class ActivityTaskSupervisor implements RecentTasks.Callbacks {/*** Start the given task from the recent tasks. Do not hold WM global lock when calling this* method to avoid potential deadlock or permission deny by UriGrantsManager when resolving* activity (see {@link ActivityStarter.Request#resolveActivity} and* {@link com.android.server.am.ContentProviderHelper#checkContentProviderUriPermission}).** @return The result code of starter.*/int startActivityFromRecents(int callingPid, int callingUid, int taskId,SafeActivityOptions options) {final Task task;final int taskCallingUid;final String callingPackage;final String callingFeatureId;final Intent intent;final int userId;final ActivityOptions activityOptions = options != null? options.getOptions(this): null;boolean moveHomeTaskForward = true;synchronized (mService.mGlobalLock) {int activityType = ACTIVITY_TYPE_UNDEFINED;if (activityOptions != null) {activityType = activityOptions.getLaunchActivityType();final int windowingMode = activityOptions.getLaunchWindowingMode();if (activityOptions.freezeRecentTasksReordering()&& mService.checkPermission(MANAGE_ACTIVITY_TASKS, callingPid, callingUid)== PERMISSION_GRANTED) {mRecentTasks.setFreezeTaskListReordering();}if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY|| activityOptions.getLaunchRootTask() != null) {// Don't move home activity forward if we are launching into primary split or// there is a launch root set.moveHomeTaskForward = false;}}if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {throw new IllegalArgumentException("startActivityFromRecents: Task "+ taskId + " can't be launch in the home/recents root task.");}boolean shouldStartActivity = false;mService.deferWindowLayout();try {task = mRootWindowContainer.anyTaskForId(taskId,MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);if (task == null) {mWindowManager.executeAppTransition();throw new IllegalArgumentException("startActivityFromRecents: Task " + taskId + " not found.");}if (moveHomeTaskForward) {// We always want to return to the home activity instead of the recents// activity from whatever is started from the recents activity, so move// the home root task forward.// TODO (b/115289124): Multi-display supports for recents.mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeRootTaskToFront("startActivityFromRecents");}// If the user must confirm credentials (e.g. when first launching a work// app and the Work Challenge is present) let startActivityInPackage handle// the intercepting.if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)&& task.getRootActivity() != null) {final ActivityRecord targetActivity = task.getTopNonFinishingActivity();mRootWindowContainer.startPowerModeLaunchIfNeeded(true /* forceSend */, targetActivity);final LaunchingState launchingState =mActivityMetricsLogger.notifyActivityLaunching(task.intent);try {mService.moveTaskToFrontLocked(null /* appThread */,null /* callingPackage */, task.mTaskId, 0, options);// Apply options to prevent pendingOptions be taken when scheduling// activity lifecycle transaction to make sure the override pending app// transition will be applied immediately.targetActivity.applyOptionsAnimation();} finally {mActivityMetricsLogger.notifyActivityLaunched(launchingState,START_TASK_TO_FRONT, false /* newActivityCreated */,targetActivity, activityOptions);}mService.getActivityStartController().postStartActivityProcessingForLastStarter(task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT,task.getRootTask());// As it doesn't go to ActivityStarter.executeRequest() path, we need to resume// app switching here also.mService.resumeAppSwitches();return ActivityManager.START_TASK_TO_FRONT;}// The task is empty or needs to show the confirmation for credential.shouldStartActivity = true;} finally {if (!shouldStartActivity) {mService.continueWindowLayout();}}taskCallingUid = task.mCallingUid;callingPackage = task.mCallingPackage;callingFeatureId = task.mCallingFeatureId;intent = task.intent;intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);userId = task.mUserId;}// ActivityStarter will acquire the lock where the places need, so execute the request// outside of the lock.try {return mService.getActivityStartController().startActivityInPackage(taskCallingUid,callingPid, callingUid, callingPackage, callingFeatureId, intent, null, null,null, 0, 0, options, userId, task, "startActivityFromRecents",false /* validateIncomingUser */, null /* originatingPendingIntent */,false /* allowBackgroundActivityStart */);} finally {synchronized (mService.mGlobalLock) {mService.continueWindowLayout();}}}
/*** System service for managing activities and their containers (task, displays,... ).** {@hide}*/
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {void moveTaskToFrontLocked(@Nullable IApplicationThread appThread,@Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options) {final int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();assertPackageMatchesCallingUid(callingPackage);final long origId = Binder.clearCallingIdentity();WindowProcessController callerApp = null;if (appThread != null) {callerApp = getProcessController(appThread);}final ActivityStarter starter = getActivityStartController().obtainStarter(null /* intent */, "moveTaskToFront");if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,-1, callerApp, null, false, null)) {if (!isBackgroundActivityStartsEnabled()) {return;}}try {final Task task = mRootWindowContainer.anyTaskForId(taskId);if (task == null) {ProtoLog.d(WM_DEBUG_TASKS, "Could not find task for id: %d", taskId);SafeActivityOptions.abort(options);return;}if (getLockTaskController().isLockTaskModeViolation(task)) {Slog.e(TAG, "moveTaskToFront: Attempt to violate Lock Task Mode");SafeActivityOptions.abort(options);return;}ActivityOptions realOptions = options != null? options.getOptions(mTaskSupervisor): null;mTaskSupervisor.findTaskToMoveToFront(task, flags, realOptions, "moveTaskToFront",false /* forceNonResizable */);final ActivityRecord topActivity = task.getTopNonFinishingActivity();if (topActivity != null) {// We are reshowing a task, use a starting window to hide the initial draw delay// so the transition can start earlier.topActivity.showStartingWindow(true /* taskSwitch */);}} finally {Binder.restoreCallingIdentity(origId);}}
// TODO: This class has become a dumping ground. Let's
// - Move things relating to the hierarchy to RootWindowContainer
// - Move things relating to activity life cycles to maybe a new class called ActivityLifeCycler
// - Move interface things to ActivityTaskManagerService.
// - All other little things to other files.
public class ActivityTaskSupervisor implements RecentTasks.Callbacks {/** This doesn't just find a task, it also moves the task to front. */void findTaskToMoveToFront(Task task, int flags, ActivityOptions options, String reason,boolean forceNonResizeable) {Task currentRootTask = task.getRootTask();if (currentRootTask == null) {Slog.e(TAG, "findTaskToMoveToFront: can't move task="+ task + " to front. Root task is null");return;}try {if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {mUserLeaving = true;}task.mTransitionController.requestTransitionIfNeeded(TRANSIT_TO_FRONT,0 /* flags */, task, task /* readyGroupRef */,options != null ? options.getRemoteTransition() : null);reason = reason + " findTaskToMoveToFront";boolean reparented = false;if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) {final Rect bounds = options.getLaunchBounds();task.setBounds(bounds);Task launchRootTask =mRootWindowContainer.getLaunchRootTask(null, options, task, ON_TOP);if (launchRootTask != currentRootTask) {moveHomeRootTaskToFrontIfNeeded(flags, launchRootTask.getDisplayArea(), reason);task.reparent(launchRootTask, ON_TOP, REPARENT_KEEP_ROOT_TASK_AT_FRONT,!ANIMATE, DEFER_RESUME, reason);currentRootTask = launchRootTask;reparented = true;// task.reparent() should already placed the task on top,// still need moveTaskToFrontLocked() below for any transition settings.}if (launchRootTask.shouldResizeRootTaskWithLaunchBounds()) {launchRootTask.resize(bounds, !PRESERVE_WINDOWS, !DEFER_RESUME);} else {// WM resizeTask must be done after the task is moved to the correct stack,// because Task's setBounds() also updates dim layer's bounds, but that has// dependency on the root task.task.resize(false /* relayout */, false /* forced */);}}if (!reparented) {moveHomeRootTaskToFrontIfNeeded(flags, currentRootTask.getDisplayArea(), reason);}final ActivityRecord r = task.getTopNonFinishingActivity();currentRootTask.moveTaskToFront(task, false /* noAnimation */, options,r == null ? null : r.appTimeTracker, reason);if (DEBUG_ROOT_TASK) Slog.d(TAG_ROOT_TASK,"findTaskToMoveToFront: moved to front of root task=" + currentRootTask);handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,mRootWindowContainer.getDefaultTaskDisplayArea(), currentRootTask,forceNonResizeable);} finally {mUserLeaving = false;}}
/*** {@link Task} is a TaskFragment that can contain a group of activities to perform a certain job.* Activities of the same task affinities usually group in the same {@link Task}. A {@link Task}* can also be an entity that showing in the Recents Screen for a job that user interacted with.* A {@link Task} can also contain other {@link Task}s.*/
class Task extends TaskFragment {final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,AppTimeTracker timeTracker, String reason) {moveTaskToFront(tr, noAnimation, options, timeTracker, !DEFER_RESUME, reason);}final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,AppTimeTracker timeTracker, boolean deferResume, String reason) {if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);final Task topRootTask = getDisplayArea().getTopRootTask();final ActivityRecord topActivity = topRootTask != null? topRootTask.getTopNonFinishingActivity() : null;if (tr != this && !tr.isDescendantOf(this)) {// nothing to do!if (noAnimation) {ActivityOptions.abort(options);} else {updateTransitLocked(TRANSIT_TO_FRONT, options);}return;}if (timeTracker != null) {// The caller wants a time tracker associated with this task.final PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setAppTimeTracker,PooledLambda.__(ActivityRecord.class), timeTracker);tr.forAllActivities(c);c.recycle();}try {// Defer updating the IME target since the new IME target will try to get computed// before updating all closing and opening apps, which can cause the ime target to// get calculated incorrectly.mDisplayContent.deferUpdateImeTarget();// Don't refocus if invisible to current userfinal ActivityRecord top = tr.getTopNonFinishingActivity();if (top == null || !top.showToCurrentUser()) {positionChildAtTop(tr);if (top != null) {mTaskSupervisor.mRecentTasks.add(top.getTask());}ActivityOptions.abort(options);return;}// Set focus to the top running activity of this task and move all its parents to top.top.moveFocusableActivityToTop(reason);if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);if (noAnimation) {mDisplayContent.prepareAppTransition(TRANSIT_NONE);mTaskSupervisor.mNoAnimActivities.add(top);ActivityOptions.abort(options);} else {updateTransitLocked(TRANSIT_TO_FRONT, options);}// If a new task is moved to the front, then mark the existing top activity as// supporting// picture-in-picture while paused only if the task would not be considered an oerlay// on top// of the current activity (eg. not fullscreen, or the assistant)if (canEnterPipOnTaskSwitch(topActivity, tr, null /* toFrontActivity */,options)) {topActivity.supportsEnterPipOnTaskSwitch = true;}if (!deferResume) {mRootWindowContainer.resumeFocusedTasksTopActivities();}} finally {mDisplayContent.continueUpdateImeTarget();}}
/*** An entry in the history task, representing an activity.*/
final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {/*** Move activity with its root task to front and make the root task focused.* @param reason the reason to move to top* @return {@code true} if the root task is focusable and has been moved to top or the activity*         is not yet resumed while the root task is already on top, {@code false} otherwise.*/boolean moveFocusableActivityToTop(String reason) {if (!isFocusable()) {ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: unfocusable "+ "activity=%s", this);return false;}final Task rootTask = getRootTask();if (rootTask == null) {Slog.w(TAG, "moveFocusableActivityToTop: invalid root task: activity="+ this + " task=" + task);return false;}if (mRootWindowContainer.getTopResumedActivity() == this&& getDisplayContent().mFocusedApp == this) {ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: already on top, "+ "activity=%s", this);return !isState(RESUMED);}ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: activity=%s", this);rootTask.moveToFront(reason, task);// Report top activity change to tracking services and WMif (mRootWindowContainer.getTopResumedActivity() == this) {mAtmService.setResumedActivityUncheckLocked(this, reason);}return true;}
/*** {@link Task} is a TaskFragment that can contain a group of activities to perform a certain job.* Activities of the same task affinities usually group in the same {@link Task}. A {@link Task}* can also be an entity that showing in the Recents Screen for a job that user interacted with.* A {@link Task} can also contain other {@link Task}s.*/
class Task extends TaskFragment {void moveToFront(String reason, Task task) {if (inSplitScreenSecondaryWindowingMode()) {// If the root task is in split-screen secondary mode, we need to make sure we move the// primary split-screen root task forward in the case it is currently behind a// fullscreen root task so both halves of the split-screen appear on-top and the// fullscreen root task isn't cutting between them.// TODO(b/70677280): This is a workaround until we can fix as part of b/70677280.final TaskDisplayArea taskDisplayArea = getDisplayArea();final Task topFullScreenRootTask =taskDisplayArea.getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);if (topFullScreenRootTask != null) {final Task primarySplitScreenRootTask =taskDisplayArea.getRootSplitScreenPrimaryTask();if (primarySplitScreenRootTask != null&& topFullScreenRootTask.compareTo(primarySplitScreenRootTask) > 0) {primarySplitScreenRootTask.moveToFrontInner(reason + " splitScreenToTop",null /* task */);}}} else if (mMoveAdjacentTogether && getAdjacentTaskFragment() != null) {final Task adjacentTask = getAdjacentTaskFragment().asTask();if (adjacentTask != null) {adjacentTask.moveToFrontInner(reason + " adjacentTaskToTop", null /* task */);}}moveToFrontInner(reason, task);}/*** @param reason The reason for moving the root task to the front.* @param task If non-null, the task will be moved to the top of the root task.*/@VisibleForTestingvoid moveToFrontInner(String reason, Task task) {if (!isAttached()) {return;}final TaskDisplayArea taskDisplayArea = getDisplayArea();if (!isActivityTypeHome() && returnsToHomeRootTask()) {// Make sure the root home task is behind this root task since that is where we// should return to when this root task is no longer visible.taskDisplayArea.moveHomeRootTaskToFront(reason + " returnToHome");}final Task lastFocusedTask = isRootTask() ? taskDisplayArea.getFocusedRootTask() : null;if (task == null) {task = this;}task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */);taskDisplayArea.updateLastFocusedRootTask(lastFocusedTask, reason);}
/*** {@link Task} is a TaskFragment that can contain a group of activities to perform a certain job.* Activities of the same task affinities usually group in the same {@link Task}. A {@link Task}* can also be an entity that showing in the Recents Screen for a job that user interacted with.* A {@link Task} can also contain other {@link Task}s.*/
class Task extends TaskFragment {@Overridevoid positionChildAt(int position, WindowContainer child, boolean includingParents) {final boolean toTop = position >= (mChildren.size() - 1);position = getAdjustedChildPosition(child, position);super.positionChildAt(position, child, includingParents);// Log positioning.if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "positionChildAt: child=" + child+ " position=" + position + " parent=" + this);final Task task = child.asTask();if (task != null) {task.updateTaskMovement(toTop, position);}}void updateTaskMovement(boolean toTop, int position) {EventLogTags.writeWmTaskMoved(mTaskId, toTop ? 1 : 0, position);final TaskDisplayArea taskDisplayArea = getDisplayArea();if (taskDisplayArea != null && isLeafTask()) {taskDisplayArea.onLeafTaskMoved(this, toTop);}if (isPersistable) {mLastTimeMoved = System.currentTimeMillis();}}

/*** {@link DisplayArea} that represents a section of a screen that contains app window containers.** The children can be either {@link Task} or {@link TaskDisplayArea}.*/
final class TaskDisplayArea extends DisplayArea<WindowContainer> {void onLeafTaskMoved(Task t, boolean toTop) {if (!toTop) {if (t.mTaskId == mLastLeafTaskToFrontId) {mLastLeafTaskToFrontId = INVALID_TASK_ID;}return;}if (t.mTaskId == mLastLeafTaskToFrontId || t.topRunningActivityLocked() == null) {return;}mLastLeafTaskToFrontId = t.mTaskId;EventLogTags.writeWmTaskToFront(t.mUserId, t.mTaskId);// Notifying only when a leaf task moved to front. Or the listeners would be notified// couple times from the leaf task all the way up to the root task.mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront(t.getTaskInfo());}
class TaskChangeNotificationController {void notifyTaskMovedToFront(TaskInfo ti) {final Message msg = mHandler.obtainMessage(NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG, ti);forAllLocalListeners(mNotifyTaskMovedToFront, msg);msg.sendToTarget();}

http://www.ppmy.cn/news/347618.html

相关文章

提升网络安全的关键利器:EventLog Analyzer

导语&#xff1a; 随着网络攻击和数据泄露事件的不断增加&#xff0c;企业对于网络安全的关注度也日益提高。在这样的背景下&#xff0c;安全信息与事件管理系统&#xff08;SIEM&#xff09;成为了提升网络安全的关键利器之一。本文将重点介绍一款强大的SIEM工具——EventLog…

MySQL 日期与时间函数

一、获取日期、时间 函数用法CURDATE()&#xff0c;CURRENT_DATE()返回当前日期&#xff0c;只包含年、月、日CURTIME() &#xff0c; CURRENT_TIME()返回当前时间&#xff0c;只包含时、分、秒NOW() &#xff0c; SYSDATE()&#xff0c;CURRENT_TIMESTAMP() &#xff0c; LOC…

漂白剂哪种好:

市面上的漂白剂主要分为「液体状」&#xff08;漂白水&#xff09;及「粉末状」&#xff08;漂白粉或漂白素&#xff09;两大类&#xff0c;那么这两大类漂白剂漂白剂哪种好呢&#xff1f;其实不同品牌之间的配方又各有特色&#xff0c;必须配合想清洁的污垢种类选择适当的配方…

AJAX详解

目录 AJAX(Asynchronous Javascript And Xml) 传统请求及缺点 AJAX概述 绑定事件 XMLHttpRequest对象 AJAX GET请求 AJAX GET请求的缓存问题 AJAX POST请求 JSON对象 基于JSON的数据交互 基于XML的数据交换 AJAX乱码问题 AJAX的异步与同步 AJAX代码封装 AJAX实现…

第四章 频率域滤波

4频率域滤波 4.1背景 4.1.1傅里叶级数和变换史 任何周期函数都可以表示为不同频率的正余弦之和。 4.2基本概念 4.2.1复数 复数C的定义&#xff08; j − 1 j\sqrt{-1} j−1 ​&#xff09;&#xff1a; C R j I CRjI CRjI 极坐标下 C ∣ C ∣ ( cos ⁡ θ j sin ⁡ …

Vivado 下 IP核之FIFO 实验

Vivado 下 IP核之FIFO 实验 FIFO&#xff08;First In First Out&#xff0c;即先进先出&#xff09;&#xff0c;是一种数据缓存器&#xff0c;用来实现数据先进先出的读写方式。在FPGA 或者 ASIC 中使用到的 FIFO 一般指的是对数据的存储具有先进先出特性的缓存器&#xff0c…

【Python实战】Python采集王者最低战力信息

前言 王者新赛季马上就要开始了&#xff0c;大家都开始冲榜了&#xff0c;准备拿一个小省标&#xff0c;那么&#xff0c;本文&#xff0c;就来练习获取各地最低战力的爬虫采集实战。 环境使用 python 3.9pycharm 模块使用 requests 模块介绍 requests requests是一个很实用…

什么是API测试?开发必知的8种API自动化测试类型

API测试 API自动化测试在产品质量控制和CI/CD流程检测中扮演着非常重要的角色。与GUI测试不同&#xff0c;API测试可以更灵活应地适应发布周期短和频繁变更的需求或产品&#xff0c;而且也不会破坏测试输出结果。 什么是API测试&#xff1f; API是应用程序编程接口的首字母缩…