diff options
author | Wale Ogunwale <ogunwale@google.com> | 2014-10-23 15:55:23 -0700 |
---|---|---|
committer | Wale Ogunwale <ogunwale@google.com> | 2014-11-04 10:59:31 -0800 |
commit | d54b578e47fb410c776bb3a4272c2c523153f657 (patch) | |
tree | 19e21c01839d987d47bb74725c3f055f59566b09 | |
parent | fe91d4e6a2ef4e51910965ea258f91c14f5ee0dc (diff) | |
download | frameworks_base-d54b578e47fb410c776bb3a4272c2c523153f657.zip frameworks_base-d54b578e47fb410c776bb3a4272c2c523153f657.tar.gz frameworks_base-d54b578e47fb410c776bb3a4272c2c523153f657.tar.bz2 |
Fix issue #17305377: Don't kill process if it still has tasks.
We previously killed a process when one of its task was
swiped away in the recents UI. This had negative performance
implications for apps with multiple tasks in recents. Now we
will only kill the process if there are no more tasks associated
with it.
Changed also removes the need for the
ActivityManager.REMOVE_TASK_KILL_PROCESS since ActivityManager
will now only kill a task process if it process has no out
standing tasks.
Bug: 17305377
Change-Id: Ibc39bb328d13c7eab05c04798c2f14887923d9d4
9 files changed, 74 insertions, 92 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 37e8aa4..a285932 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1243,26 +1243,16 @@ public class ActivityManager { } /** - * If set, the process of the root activity of the task will be killed - * as part of removing the task. - * @hide - */ - public static final int REMOVE_TASK_KILL_PROCESS = 0x0001; - - /** * Completely remove the given task. * * @param taskId Identifier of the task to be removed. - * @param flags Additional operational flags. May be 0 or - * {@link #REMOVE_TASK_KILL_PROCESS}. * @return Returns true if the given task was found and removed. * * @hide */ - public boolean removeTask(int taskId, int flags) - throws SecurityException { + public boolean removeTask(int taskId) throws SecurityException { try { - return ActivityManagerNative.getDefault().removeTask(taskId, flags); + return ActivityManagerNative.getDefault().removeTask(taskId); } catch (RemoteException e) { // System dead, we will be dead too soon! return false; diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 4e2ff0b..bc7114b 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1884,8 +1884,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM { data.enforceInterface(IActivityManager.descriptor); int taskId = data.readInt(); - int fl = data.readInt(); - boolean result = removeTask(taskId, fl); + boolean result = removeTask(taskId); reply.writeNoException(); reply.writeInt(result ? 1 : 0); return true; @@ -4778,12 +4777,11 @@ class ActivityManagerProxy implements IActivityManager return result; } - public boolean removeTask(int taskId, int flags) throws RemoteException { + public boolean removeTask(int taskId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(taskId); - data.writeInt(flags); mRemote.transact(REMOVE_TASK_TRANSACTION, data, reply, 0); reply.readException(); boolean result = reply.readInt() != 0; diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index be26f30..efcb197 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -373,7 +373,7 @@ public interface IActivityManager extends IInterface { public boolean isUserRunning(int userid, boolean orStopping) throws RemoteException; public int[] getRunningUserIds() throws RemoteException; - public boolean removeTask(int taskId, int flags) throws RemoteException; + public boolean removeTask(int taskId) throws RemoteException; public void registerProcessObserver(IProcessObserver observer) throws RemoteException; public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException; diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java index 2a782cc..4c3460e 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java @@ -728,7 +728,7 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener final ActivityManager am = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE); if (am != null) { - am.removeTask(ad.persistentTaskId, ActivityManager.REMOVE_TASK_KILL_PROCESS); + am.removeTask(ad.persistentTaskId); // Accessibility feedback setContentDescription( diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 71a3ef1..b661385 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -291,18 +291,18 @@ public class SystemServicesProxy { } } - /** Removes the task and kills the process */ - public void removeTask(int taskId, boolean isDocument) { + /** Removes the task */ + public void removeTask(int taskId) { if (mAm == null) return; if (Constants.DebugFlags.App.EnableSystemServicesProxy) return; - // Remove the task, and only kill the process if it is not a document - mAm.removeTask(taskId, isDocument ? 0 : ActivityManager.REMOVE_TASK_KILL_PROCESS); + // Remove the task. + mAm.removeTask(taskId); } /** * Returns the activity info for a given component name. - * + * * @param cn The component name of the activity. * @param userId The userId of the user that this is for. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java index a0dee07..e1179fa 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -17,7 +17,6 @@ package com.android.systemui.recents.misc; import android.animation.Animator; -import android.content.Intent; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Rect; @@ -184,12 +183,6 @@ public class Utilities { sPropertyMethod.invoke(null, property, value); } - /** Returns whether the specified intent is a document. */ - public static boolean isDocument(Intent intent) { - int flags = intent.getFlags(); - return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT; - } - /** * Cancels an animation ensuring that if it has listeners, onCancel and onEnd * are not called. diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index 6b0d306..ff0330d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -34,7 +34,6 @@ import android.widget.FrameLayout; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.RecentsPackageMonitor; import com.android.systemui.recents.model.RecentsTaskLoader; import com.android.systemui.recents.model.Task; @@ -522,8 +521,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV loader.deleteTaskData(t, false); // Remove the old task from activity manager - RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(t.key.id, - Utilities.isDocument(t.key.baseIntent)); + RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(t.key.id); } @Override diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9179cc4..91e2df0 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1836,8 +1836,8 @@ public final class ActivityManagerService extends ActivityManagerNative ComponentName cn = tr.intent.getComponent(); if (cn != null && cn.getPackageName().equals(packageName)) { - // If the package name matches, remove the task and kill the process - removeTaskByIdLocked(tr.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS); + // If the package name matches, remove the task + removeTaskByIdLocked(tr.taskId, true); } } } @@ -1891,9 +1891,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Prune all the tasks with removed components from the list of recent tasks synchronized (ActivityManagerService.this) { for (int i = tasksToRemove.size() - 1; i >= 0; i--) { - // Remove the task but don't kill the process (since other components in that - // package may still be running and in the background) - removeTaskByIdLocked(tasksToRemove.get(i), 0); + removeTaskByIdLocked(tasksToRemove.get(i), false); } } } @@ -4313,9 +4311,9 @@ public final class ActivityManagerService extends ActivityManagerNative boolean res; if (finishTask && r == rootR) { // If requested, remove the task that is associated to this activity only if it - // was the root activity in the task. The result code and data is ignored because - // we don't support returning them across task boundaries. - res = removeTaskByIdLocked(tr.taskId, 0); + // was the root activity in the task. The result code and data is ignored + // because we don't support returning them across task boundaries. + res = removeTaskByIdLocked(tr.taskId, false); } else { res = tr.stack.requestFinishActivityLocked(token, resultCode, resultData, "app-request", true); @@ -5142,7 +5140,7 @@ public final class ActivityManagerService extends ActivityManagerNative tr.getBaseIntent().getComponent().getPackageName(); if (tr.userId != userId) continue; if (!taskPackageName.equals(packageName)) continue; - removeTaskByIdLocked(tr.taskId, 0); + removeTaskByIdLocked(tr.taskId, false); } } @@ -8287,52 +8285,65 @@ public final class ActivityManagerService extends ActivityManagerNative return mTaskPersister.getTaskDescriptionIcon(filename); } - private void cleanUpRemovedTaskLocked(TaskRecord tr, int flags) { + private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess) { mRecentTasks.remove(tr); tr.removedFromRecents(mTaskPersister); - final boolean killProcesses = (flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0; - Intent baseIntent = new Intent( - tr.intent != null ? tr.intent : tr.affinityIntent); - ComponentName component = baseIntent.getComponent(); + ComponentName component = tr.getBaseIntent().getComponent(); if (component == null) { - Slog.w(TAG, "Now component for base intent of task: " + tr); + Slog.w(TAG, "No component for base intent of task: " + tr); return; } - // Find any running services associated with this app. - mServices.cleanUpRemovedTaskLocked(tr, component, baseIntent); + if (!killProcess) { + return; + } - if (killProcesses) { - // Find any running processes associated with this app. - final String pkg = component.getPackageName(); - ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(); - 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) { - continue; - } - if (!proc.pkgList.containsKey(pkg)) { - continue; - } - procs.add(proc); - } - } + // Determine if the process(es) for this task should be killed. + final String pkg = component.getPackageName(); + ArrayList<ProcessRecord> procsToKill = new ArrayList<ProcessRecord>(); + ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap(); + for (int i = 0; i < pmap.size(); i++) { - // Kill the running processes. - for (int i=0; i<procs.size(); i++) { - ProcessRecord pr = procs.get(i); - if (pr == mHomeProcess) { + 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 (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) { - pr.kill("remove task", true); - } else { - pr.waitingToKill = "remove task"; + 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; + } } + + // Add process to kill list. + procsToKill.add(proc); + } + } + + // Find any running services associated with this app and stop if needed. + mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent())); + + // 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.kill("remove task", true); + } else { + pr.waitingToKill = "remove task"; } } } @@ -8341,15 +8352,14 @@ public final class ActivityManagerService extends ActivityManagerNative * Removes the task with the specified task id. * * @param taskId Identifier of the task to be removed. - * @param flags Additional operational flags. May be 0 or - * {@link ActivityManager#REMOVE_TASK_KILL_PROCESS}. + * @param killProcess Kill any process associated with the task if possible. * @return Returns true if the given task was found and removed. */ - private boolean removeTaskByIdLocked(int taskId, int flags) { + private boolean removeTaskByIdLocked(int taskId, boolean killProcess) { TaskRecord tr = recentTaskForIdLocked(taskId); if (tr != null) { tr.removeTaskActivitiesLocked(); - cleanUpRemovedTaskLocked(tr, flags); + cleanUpRemovedTaskLocked(tr, killProcess); if (tr.isPersistable) { notifyTaskPersisterLocked(null, true); } @@ -8359,19 +8369,19 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public boolean removeTask(int taskId, int flags) { + public boolean removeTask(int taskId) { synchronized (this) { enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, "removeTask()"); long ident = Binder.clearCallingIdentity(); try { - return removeTaskByIdLocked(taskId, flags); + return removeTaskByIdLocked(taskId, true); } finally { Binder.restoreCallingIdentity(ident); } } } - + /** * TODO: Add mController hook */ @@ -19167,16 +19177,9 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (ActivityManagerService.this) { long origId = Binder.clearCallingIdentity(); try { - TaskRecord tr = recentTaskForIdLocked(mTaskId); - if (tr == null) { + if (!removeTaskByIdLocked(mTaskId, false)) { throw new IllegalArgumentException("Unable to find task ID " + mTaskId); } - // Only kill the process if we are not a new document - int flags = tr.getBaseIntent().getFlags(); - boolean isDocument = (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) == - Intent.FLAG_ACTIVITY_NEW_DOCUMENT; - removeTaskByIdLocked(mTaskId, - !isDocument ? ActivityManager.REMOVE_TASK_KILL_PROCESS : 0); } finally { Binder.restoreCallingIdentity(origId); } diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java index 6837d22..94874c8 100644 --- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java +++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java @@ -127,7 +127,7 @@ public class ActivityTestMain extends Activity { @Override public boolean onLongClick(View v) { if (task.id >= 0 && thumbs != null) { - mAm.removeTask(task.id, ActivityManager.REMOVE_TASK_KILL_PROCESS); + mAm.removeTask(task.id); buildUi(); return true; } |