recent移除task时,结束其所有进程和service(全Android版本)
Android原生系统在清理后台应用时,其实并不能清理所有进程。例如:
在点击系统自带的播放器以后,播放音乐的时候,在最近任务栏recents列表中,点击全部清除,发现音乐播放器还在播放音乐。
现提供两种解决方案
一、Launcher中forceStopPackage
Android9
vendor下面的launcher 里面
RecentsView.java
TaskActionController.java
removeTask 方法里面
- ActivityManagerWrapper.getInstance().removeTask(task.key.id);
+ final ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
+ String pkgName = task.key.getPackageName();
+ Log.d(TAG, "Stopping pkgName " + pkgName);
+ am.forceStopPackage(pkgName);
Android13
alps_mssi/frameworks/base/data/etc/com.android.launcher3.xml
<permission name="android.permission.STOP_APP_SWITCHES"/>
+ <permission name="android.permission.FORCE_STOP_PACKAGES"/>
alps_mssi/vendor/mediatek/proprietary/packages/apps/Launcher3/quickstep/AndroidManifest.xml
+ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
alps_mssi/vendor/mediatek/proprietary/packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/RecentsView.java
import java.util.Objects;
import java.util.function.Consumer;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+
/**
* A list of recent tasks.
*/
@@ -3127,12 +3130,16 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
if (success) {
if (shouldRemoveTask) {
if (dismissedTaskView.getTask() != null) {
+ //andy
+ String pkgname = dismissedTaskView.getTask().key.getPackageName();
+ Log.e("andy---RecentsView","pkgname="+pkgname);
+
if (ENABLE_QUICKSTEP_LIVE_TILE.get()
&& dismissedTaskView.isRunningTask()) {
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
- () -> removeTaskInternal(dismissedTaskViewId));
+ () -> removeTaskInternal(dismissedTaskViewId,pkgname));
} else {
- removeTaskInternal(dismissedTaskViewId);
+ removeTaskInternal(dismissedTaskViewId,pkgname);
}
mActivity.getStatsLogManager().logger()
.withItemInfo(dismissedTaskView.getItemInfo())
@@ -3401,7 +3408,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
return lastVisibleIndex;
}
- private void removeTaskInternal(int dismissedTaskViewId) {
+ private void removeTaskInternal(int dismissedTaskViewId, String pkgname) {
int[] taskIds = getTaskIdsForTaskViewId(dismissedTaskViewId);
int primaryTaskId = taskIds[0];
int secondaryTaskId = taskIds[1];
@@ -3411,6 +3418,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
if (secondaryTaskId != -1) {
ActivityManagerWrapper.getInstance().removeTask(secondaryTaskId);
}
+ //andy
+ ActivityManager am = (ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE);
+ Log.e("andy---RecentsView---", "pkgname = " + pkgname);
+ am.forceStopPackage(pkgname);
},
REMOVE_TASK_WAIT_FOR_APP_STOP_MS);
}
@@ -3436,6 +3447,12 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
int count = getTaskViewCount();
for (int i = 0; i < count; i++) {
addDismissedTaskAnimations(requireTaskViewAt(i), duration, anim);
+ //andy
+ String pkgname = requireTaskViewAt(i).getTask().key.getPackageName();
+ Log.e("andy---RecentsView---createAllTasksDismissAnimation---","pkgname="+pkgname);
+ ActivityManager am = (ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE);
+ am.forceStopPackage(pkgname);
+
}
mPendingAnimation = anim;
二、AMS中判断前台service也杀死
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
Android6
在最近的任务界面,把正在播放的音乐关掉,播放的音乐没有停止
@Override
public boolean removeTask(int taskId) {
synchronized (this) {
enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
"removeTask()");
long ident = Binder.clearCallingIdentity();
try {
return removeTaskByIdLocked(taskId, true);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
private boolean removeTaskByIdLocked(int taskId, boolean killProcess) {
TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
/// M: BMW. [ALPS01455940], remove task which not in recent task
/// but we really want to remove. Add recent task will auto remove
/// duplicate task record (the same task affinity) @{
if (MultiWindowProxy.isSupported() && tr == null) {
ArrayList<ActivityStack> stackList = mStackSupervisor.getStacks();
for (int i = 0; i < stackList.size(); i++) {
ActivityStack stack = stackList.get(i);
TaskRecord task = stack.topTask();
if (MultiWindowProxy.getInstance().isFloatingStack(stack.mStackId)
&& task != null && task.taskId == taskId) {
tr = task;
}
}
}
/// @}
if (tr != null) {
tr.removeTaskActivitiesLocked();
cleanUpRemovedTaskLocked(tr, killProcess);
if (tr.isPersistable) {
notifyTaskPersisterLocked(null, true);
}
return true;
}
Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);
return false;
}
private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess) {
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.
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();
ArrayList<ProcessRecord> procsToKill = new ArrayList<>();
ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
for (int i = 0; i < pmap.size(); i++) {
SparseArray<ProcessRecord> 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 == 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).task;
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 == Process.THREAD_GROUP_BG_NONINTERACTIVE
&& pr.curReceiver == null) {
pr.kill("remove task", true);
} else {
// We delay killing processes that are not in the background or running a receiver.
pr.waitingToKill = "remove task";
}
}
}
可以看到,如果是foreground的service,就不会kill掉进程
让service 不调用 public final void startForeground(int id, Notification notification);
问题解决
但如果不调用这个,service就是后台的,系统内存紧张时就会被杀掉,
后续看看有没有别的解决办法~
改framework?实在不行就这么干
Android7
private 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.
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();
ArrayList<ProcessRecord> procsToKill = new ArrayList<>();
ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
for (int i = 0; i < pmap.size(); i++) {
SparseArray<ProcessRecord> 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 == 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).task;
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.curReceiver == null) {
pr.kill("remove task", true);
- } else {
- // We delay killing processes that are not in the background or running a receiver.
- pr.waitingToKill = "remove task";
- }
}
}
Android11
packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
frameworks/base/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
void removeTask(Task task, boolean killProcess, boolean removeFromRecents, String reason) {
if (task.mInRemoveTask) {
// Prevent recursion.
return;
}
task.mInRemoveTask = true;
try {
task.performClearTask(reason);
cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
mService.getLockTaskController().clearLockedTask(task);
mService.getTaskChangeNotificationController().notifyTaskStackChanged();
if (task.isPersistable) {
mService.notifyTaskPersisterLocked(null, true);
}
} finally {
task.mInRemoveTask = false;
}
}
void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) {
if (removeFromRecents) {
mRecentTasks.remove(task);
}
ComponentName component = task.getBaseIntent().getComponent();
if (component == null) {
Slog.w(TAG, "No component for base intent of task: " + task);
return;
}
// Find any running services associated with this app and stop if needed.
final Message msg = PooledLambda.obtainMessage(ActivityManagerInternal::cleanUpServices,
mService.mAmInternal, task.mUserId, component, new Intent(task.getBaseIntent()));
mService.mH.sendMessage(msg);
if (!killProcess) {
return;
}
// Determine if the process(es) for this task should be killed.
final String pkg = component.getPackageName();
ArrayList<Object> procsToKill = new ArrayList<>();
ArrayMap<String, SparseArray<WindowProcessController>> pmap =
mService.mProcessNames.getMap();
for (int i = 0; i < pmap.size(); i++) {
SparseArray<WindowProcessController> uids = pmap.valueAt(i);
for (int j = 0; j < uids.size(); j++) {
WindowProcessController proc = uids.valueAt(j);
if (proc.mUserId != task.mUserId) {
// 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.mPkgList.contains(pkg)) {
// Don't kill process that is not associated with this task.
continue;
}
if (!proc.shouldKillProcessForRemovedTask(task)) {
// Don't kill process(es) that has an activity in a different task that is also
// in recents, or has an activity not stopped.
return;
}
// core modify start
/*if (proc.hasForegroundServices()) {
// Don't kill process(es) with foreground service.
return;
}*/
// core modify end
// Add process to kill list.
procsToKill.add(proc);
}
}
// Kill the running processes. Post on handle since we don't want to hold the service lock
// while calling into AM.
final Message m = PooledLambda.obtainMessage(
ActivityManagerInternal::killProcessesForRemovedTask, mService.mAmInternal,
procsToKill);
mService.mH.sendMessage(m);
}
public void killProcessesForRemovedTask(ArrayList<Object> procsToKill) {
synchronized (ActivityManagerService.this) {
for (int i = 0; i < procsToKill.size(); i++) {
final WindowProcessController wpc =
(WindowProcessController) procsToKill.get(i);
final ProcessRecord pr = (ProcessRecord) wpc.mOwner;
// core modify start
/*if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
&& pr.curReceivers.isEmpty()) {*/
pr.kill("remove task", ApplicationExitInfo.REASON_USER_REQUESTED,
ApplicationExitInfo.SUBREASON_UNKNOWN, true);
/* } else {
// We delay killing processes that are not in the background or running a
// receiver.
pr.waitingToKill = "remove task";
}*/
// core modify end
}
}
}