1.先从UI切入问题分析,使用Monitor—Hierarchy View找到清除任务X按钮对应的id为r.id.dismiss_task,并且属于SystemUI
2.到SystemUI定位到包含dismiss_task的是TaskViewHeader.java,该按钮对应的onClick事件为:
TaskView tv = Utilities.findParent(this, TaskView.class); tv.dismissTask(); // Keep track of deletions by the dismiss button MetricsLogger.histogram(getContext(), "overview_task_dismissed_source", Constants.Metrics.DismissSourceHeaderButton);
3.查看TaskView.java中的dismissTask
void dismissTask() { // Animate out the view and call the callback final TaskView tv = this; DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv); dismissEvent.addPostAnimationCallback(new Runnable() { @Override public void run() { EventBus.getDefault().send(new TaskViewDismissedEvent(mTask, tv, new AnimationProps(TaskStackView.DEFAULT_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN))); } }); EventBus.getDefault().send(dismissEvent); }
这里EventBus send一个DismissTaskViewEvent,处理完成会回调再发生一个TaskViewDismissedEvent
5.定位到处理DismissTaskViewEvent是在TaskStackView.java
public final void onBusEvent(DismissTaskViewEvent event) { // For visible children, defer removing the task until after the animation mAnimationHelper.startDeleteTaskAnimation( event.taskView, useGridLayout(), event.getAnimationTrigger()); }
处理TaskViewDismissedEvent
public final void onBusEvent(TaskViewDismissedEvent event) { // Announce for accessibility announceForAccessibility(getContext().getString( R.string.accessibility_recents_item_dismissed, event.task.title)); if (useGridLayout() && event.animation != null) { event.animation.setListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animator) { if (mTaskViewFocusFrame != null) { // Resize the grid layout task view focus frame mTaskViewFocusFrame.resize(); } } }); } // Remove the task from the stack mStack.removeTask(event.task, event.animation, false /* fromDockGesture */); EventBus.getDefault().send(new DeleteTaskDataEvent(event.task)); if (mStack.getTaskCount() > 0 && Recents.getConfiguration().isLowRamDevice) { EventBus.getDefault().send(new ShowStackActionButtonEvent(false /* translate */)); } MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS, event.task.key.getComponent().toString()); }
6.接着DeleteTaskDataEvent在RecentsActivity.java处理
public final void onBusEvent(DeleteTaskDataEvent event) { // Remove any stored data from the loader RecentsTaskLoader loader = Recents.getTaskLoader(); loader.deleteTaskData(event.task, false); // Remove the task from activity manager SystemServicesProxy ssp = Recents.getSystemServices(); ssp.removeTask(event.task.key.id); }
7.SystemServicesProxy.java中removeTask
/** Removes the task */ public void removeTask(final int taskId) { if (mAm == null) return; if (RecentsDebugFlags.Static.EnableMockTasks) return; // Remove the task. mUiOffloadThread.submit(() -> { mAm.removeTask(taskId); }); }
这里就是关键代码了,通过调用ActivityManager的removeTask来删除任务
8.通过ActivityManager.java其对应的是ActivityManagerService.java
@Override public boolean removeTask(int taskId) { enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, "removeTask()"); synchronized (this) { final long ident = Binder.clearCallingIdentity(); try { return mStackSupervisor.removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS); } finally { Binder.restoreCallingIdentity(ident); } } }
9.ActivityStackSupervisor.java
boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents, boolean pauseImmediately) { final TaskRecord tr = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID); if (tr != null) { tr.removeTaskActivitiesLocked(pauseImmediately); cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents); if (tr.isPersistable) { mService.notifyTaskPersisterLocked(null, true); } return true; } Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId); return false; }
void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess, boolean removeFromRecents) { if (removeFromRecents) { mRecentTasks.remove(tr); tr.removedFromRecents(); } ComponentName component = tr.getBaseIntent().getComponent(); if (component == null) { Slog.w(TAG, "No component for base intent of task: " + tr); return; } // Find any running services associated with this app and stop if needed. mService.mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent())); if (!killProcess) { return; } // Determine if the process(es) for this task should be killed. final String pkg = component.getPackageName(); ArrayListprocsToKill = new ArrayList<>(); ArrayMap > pmap = mService.mProcessNames.getMap(); for (int i = 0; i < pmap.size(); i++) { SparseArray uids = pmap.valueAt(i); for (int j = 0; j < uids.size(); j++) { ProcessRecord proc = uids.valueAt(j); if (proc.userId != tr.userId) { // Don't kill process for a different user. continue; } if (proc == mService.mHomeProcess) { // Don't kill the home process along with tasks from the same package. continue; } if (!proc.pkgList.containsKey(pkg)) { // Don't kill process that is not associated with this task. continue; } for (int k = 0; k < proc.activities.size(); k++) { TaskRecord otherTask = proc.activities.get(k).getTask(); if (tr.taskId != otherTask.taskId && otherTask.inRecents) { // Don't kill process(es) that has an activity in a different task that is // also in recents. return; } } if (proc.foregroundServices) { // Don't kill process(es) with foreground service. return; } // Add process to kill list. procsToKill.add(proc); } } // Kill the running processes. for (int i = 0; i < procsToKill.size(); i++) { ProcessRecord pr = procsToKill.get(i); if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND && pr.curReceivers.isEmpty()) { pr.kill("remove task", true); } else { // We delay killing processes that are not in the background or running a receiver. pr.waitingToKill = "remove task"; } } }
通过上述定位会发现music app包含了前台的服务foregroundServices,所以其process不会被kill掉。这个是google原生设计的。
那解决该问题,我们可以增加判断如果是removeFromRecents 为true时将其包含foregroundServices也kill掉