Kill the task killers.

The ActivityManager.restartPackage() API is now deprecated, and no longer
allows applications to mess up the state of other applications.  This was
being abused by task killers, causing users to think their other applications
had bugs.

A new API is introduced for task killers,
ActivityManager.killBackgroundProcesses(), which allows these applications
to kill processes but only the same amount that the out of memory
killer does, thus causing no permanent damage.  The old restartPackage()
API is now a wrapper for calling this new API.

There is also a new private forceStopPackage() API that is used for the
system's force stop UI which does what the old restartPackage() API did.
diff --git a/api/current.xml b/api/current.xml
index 1b5cd4d..335c8da 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -595,6 +595,17 @@
  visibility="public"
 >
 </field>
+<field name="KILL_BACKGROUND_PROCESSES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.KILL_BACKGROUND_PROCESSES&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="MANAGE_ACCOUNTS"
  type="java.lang.String"
  transient="false"
@@ -899,7 +910,7 @@
  value="&quot;android.permission.RESTART_PACKAGES&quot;"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -17534,7 +17545,7 @@
 <exception name="SecurityException" type="java.lang.SecurityException">
 </exception>
 </method>
-<method name="restartPackage"
+<method name="killBackgroundProcesses"
  return="void"
  abstract="false"
  native="false"
@@ -17547,6 +17558,19 @@
 <parameter name="packageName" type="java.lang.String">
 </parameter>
 </method>
+<method name="restartPackage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
 <field name="RECENT_WITH_EXCLUDED"
  type="int"
  transient="false"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7d07604..930ab65 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -891,6 +891,38 @@
     }
     
     /**
+     * @deprecated This is now just a wrapper for
+     * {@link #killBackgroundProcesses(String)}; the previous behavior here
+     * is no longer available to applications because it allows them to
+     * break other applications by removing their alarms, stopping their
+     * services, etc.
+     */
+    @Deprecated
+    public void restartPackage(String packageName) {
+        killBackgroundProcesses(packageName);
+    }
+    
+    /**
+     * Have the system immediately kill all background processes associated
+     * with the given package.  This is the same as the kernel killing those
+     * processes to reclaim memory; the system will take care of restarting
+     * these processes in the future as needed.
+     * 
+     * <p>You must hold the permission
+     * {@link android.Manifest.permission#KILL_BACKGROUND_PROCESSES} to be able to
+     * call this method.
+     * 
+     * @param packageName The name of the package whose processes are to
+     * be killed.
+     */
+    public void killBackgroundProcesses(String packageName) {
+        try {
+            ActivityManagerNative.getDefault().killBackgroundProcesses(packageName);
+        } catch (RemoteException e) {
+        }
+    }
+    
+    /**
      * Have the system perform a force stop of everything associated with
      * the given application package.  All processes that share its uid
      * will be killed, all services it has running stopped, all activities
@@ -899,14 +931,18 @@
      * be stopped, notifications removed, etc.
      * 
      * <p>You must hold the permission
-     * {@link android.Manifest.permission#RESTART_PACKAGES} to be able to
+     * {@link android.Manifest.permission#FORCE_STOP_PACKAGES} to be able to
      * call this method.
      * 
      * @param packageName The name of the package to be stopped.
+     * 
+     * @hide This is not available to third party applications due to
+     * it allowing them to break other applications by stopping their
+     * services, removing their alarms, etc.
      */
-    public void restartPackage(String packageName) {
+    public void forceStopPackage(String packageName) {
         try {
-            ActivityManagerNative.getDefault().restartPackage(packageName);
+            ActivityManagerNative.getDefault().forceStopPackage(packageName);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 90f46dd..09b88ee 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1007,10 +1007,18 @@
             return true;
         }
 
-        case RESTART_PACKAGE_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);            
+        case KILL_BACKGROUND_PROCESSES_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
             String packageName = data.readString();
-            restartPackage(packageName);
+            killBackgroundProcesses(packageName);
+            reply.writeNoException();
+            return true;
+        }
+        
+        case FORCE_STOP_PACKAGE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String packageName = data.readString();
+            forceStopPackage(packageName);
             reply.writeNoException();
             return true;
         }
@@ -2388,12 +2396,23 @@
         reply.recycle();
     }
     
-    public void restartPackage(String packageName) throws RemoteException {
+    public void killBackgroundProcesses(String packageName) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(packageName);
-        mRemote.transact(RESTART_PACKAGE_TRANSACTION, data, reply, 0);
+        mRemote.transact(KILL_BACKGROUND_PROCESSES_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+    
+    public void forceStopPackage(String packageName) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(packageName);
+        mRemote.transact(FORCE_STOP_PACKAGE_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ca6bfa7..016d465 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -216,7 +216,8 @@
     
     public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException;
     
-    public void restartPackage(final String packageName) throws RemoteException;
+    public void killBackgroundProcesses(final String packageName) throws RemoteException;
+    public void forceStopPackage(final String packageName) throws RemoteException;
     
     // Note: probably don't want to allow applications access to these.
     public void goingToSleep() throws RemoteException;
@@ -424,7 +425,7 @@
     int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+75;
     int GET_PROCESSES_IN_ERROR_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+76;
     int CLEAR_APP_DATA_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+77;
-    int RESTART_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
+    int FORCE_STOP_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
     int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
     int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
     int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
@@ -448,4 +449,5 @@
     int START_ACTIVITY_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+99;
     int OVERRIDE_PENDING_TRANSITION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+100;
     int HANDLE_APPLICATION_WTF_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+101;
+    int KILL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+102;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 72ad324..d202372 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -556,12 +556,30 @@
         android:label="@string/permlab_changeConfiguration"
         android:description="@string/permdesc_changeConfiguration" />
 
-    <!-- Allows an application to restart other applications. -->
+    <!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
+        API is no longer supported. -->
     <permission android:name="android.permission.RESTART_PACKAGES"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_restartPackages"
-        android:description="@string/permdesc_restartPackages" />
+        android:protectionLevel="normal"
+        android:label="@string/permlab_killBackgroundProcesses"
+        android:description="@string/permdesc_killBackgroundProcesses" />
+
+    <!-- Allows an application to call
+        {@link android.app.ActivityManager#killBackgroundProcesses}. -->
+    <permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="normal"
+        android:label="@string/permlab_killBackgroundProcesses"
+        android:description="@string/permdesc_killBackgroundProcesses" />
+
+    <!-- Allows an application to call
+        {@link android.app.ActivityManager#forceStopPackage}.
+        @hide -->
+    <permission android:name="android.permission.FORCE_STOP_PACKAGES"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_forceStopPackages"
+        android:description="@string/permdesc_forceStopPackages" />
 
     <!-- Allows an application to retrieve state dump information from system
          services. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bc354c5..4fb476b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -462,10 +462,17 @@
         size.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_restartPackages">restart other applications</string>
+    <string name="permlab_killBackgroundProcesses">kill background processes</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_restartPackages">Allows an application to
-        forcibly restart other applications.</string>
+    <string name="permdesc_killBackgroundProcesses">Allows an application to
+        kill background processes of other applications, even if memory
+        isn\'t low.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_forceStopPackages">force stop other applications</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_forceStopPackages">Allows an application to
+        forcibly stop other applications.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_forceBack">force application to close</string>
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index bf436b6..7f12b6d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1194,7 +1194,7 @@
                     int uid = msg.arg1;
                     boolean restart = (msg.arg2 == 1);
                     String pkg = (String) msg.obj;
-                    uninstallPackageLocked(pkg, uid, restart);
+                    forceStopPackageLocked(pkg, uid, restart);
                 }
             } break;
             }
@@ -2734,8 +2734,7 @@
                 // Whoops, need to restart this activity!
                 next.state = lastState;
                 mResumedActivity = lastResumedActivity;
-                if (Config.LOGD) Log.d(TAG,
-                        "Restarting because process died: " + next);
+                Log.i(TAG, "Restarting because process died: " + next);
                 if (!next.hasBeenLaunched) {
                     next.hasBeenLaunched = true;
                 } else {
@@ -4293,7 +4292,9 @@
         
         cleanUpActivityLocked(r, false);
 
-        if (r.app != null) {
+        final boolean hadApp = r.app != null;
+        
+        if (hadApp) {
             if (removeFromApp) {
                 int idx = r.app.activities.indexOf(r);
                 if (idx >= 0) {
@@ -4350,16 +4351,14 @@
 
         r.configChangeFlags = 0;
         
-        if (!mLRUActivities.remove(r)) {
+        if (!mLRUActivities.remove(r) && hadApp) {
             Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
         }
         
         return removedFromHistory;
     }
 
-    private static void removeHistoryRecordsForAppLocked(ArrayList list,
-                                                         ProcessRecord app)
-    {
+    private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
         int i = list.size();
         if (localLOGV) Log.v(
             TAG, "Removing app " + app + " from list " + list
@@ -4550,7 +4549,7 @@
                     scheduleAppGcsLocked();
                 }
             }
-        } else if (Config.LOGD) {
+        } else if (DEBUG_PROCESSES) {
             Log.d(TAG, "Received spurious death notification for thread "
                     + thread.asBinder());
         }
@@ -4852,7 +4851,7 @@
                         android.Manifest.permission.CLEAR_APP_USER_DATA,
                         pid, uid, -1)
                         == PackageManager.PERMISSION_GRANTED) {
-                    restartPackageLocked(packageName, pkgUid);
+                    forceStopPackageLocked(packageName, pkgUid);
                 } else {
                     throw new SecurityException(pid+" does not have permission:"+
                             android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
@@ -4877,13 +4876,15 @@
         return true;
     }
 
-    public void restartPackage(final String packageName) {
-        if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
-                != PackageManager.PERMISSION_GRANTED) {
-            String msg = "Permission Denial: restartPackage() from pid="
+    public void killBackgroundProcesses(final String packageName) {
+        if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
+                != PackageManager.PERMISSION_GRANTED &&
+                checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
+                        != PackageManager.PERMISSION_GRANTED) {
+            String msg = "Permission Denial: killBackgroundProcesses() from pid="
                     + Binder.getCallingPid()
                     + ", uid=" + Binder.getCallingUid()
-                    + " requires " + android.Manifest.permission.RESTART_PACKAGES;
+                    + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
             Log.w(TAG, msg);
             throw new SecurityException(msg);
         }
@@ -4901,7 +4902,39 @@
                     Log.w(TAG, "Invalid packageName: " + packageName);
                     return;
                 }
-                restartPackageLocked(packageName, pkgUid);
+                killPackageProcessesLocked(packageName, pkgUid,
+                        SECONDARY_SERVER_ADJ, false);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
+    public void forceStopPackage(final String packageName) {
+        if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
+                != PackageManager.PERMISSION_GRANTED) {
+            String msg = "Permission Denial: forceStopPackage() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
+            Log.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        
+        long callingId = Binder.clearCallingIdentity();
+        try {
+            IPackageManager pm = ActivityThread.getPackageManager();
+            int pkgUid = -1;
+            synchronized(this) {
+                try {
+                    pkgUid = pm.getPackageUid(packageName);
+                } catch (RemoteException e) {
+                }
+                if (pkgUid == -1) {
+                    Log.w(TAG, "Invalid packageName: " + packageName);
+                    return;
+                }
+                forceStopPackageLocked(packageName, pkgUid);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -5011,8 +5044,8 @@
         }
     }
 
-    private void restartPackageLocked(final String packageName, int uid) {
-        uninstallPackageLocked(packageName, uid, false);
+    private void forceStopPackageLocked(final String packageName, int uid) {
+        forceStopPackageLocked(packageName, uid, false);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
         intent.putExtra(Intent.EXTRA_UID, uid);
@@ -5021,13 +5054,41 @@
                 false, false, MY_PID, Process.SYSTEM_UID);
     }
     
-    private final void uninstallPackageLocked(String name, int uid,
-            boolean callerWillRestart) {
-        if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
+    private final void killPackageProcessesLocked(String packageName, int uid,
+            int minOomAdj, boolean callerWillRestart) {
+        ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
 
+        // Remove all processes this package may have touched: all with the
+        // same UID (except for the system or root user), and all whose name
+        // matches the package name.
+        final String procNamePrefix = packageName + ":";
+        for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
+            final int NA = apps.size();
+            for (int ia=0; ia<NA; ia++) {
+                ProcessRecord app = apps.valueAt(ia);
+                if (app.removed) {
+                    procs.add(app);
+                } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
+                        || app.processName.equals(packageName)
+                        || app.processName.startsWith(procNamePrefix)) {
+                    if (app.setAdj >= minOomAdj) {
+                        app.removed = true;
+                        procs.add(app);
+                    }
+                }
+            }
+        }
+        
+        int N = procs.size();
+        for (int i=0; i<N; i++) {
+            removeProcessLocked(procs.get(i), callerWillRestart);
+        }
+    }
+    
+    private final void forceStopPackageLocked(String name, int uid,
+            boolean callerWillRestart) {
         int i, N;
 
-        final String procNamePrefix = name + ":";
         if (uid < 0) {
             try {
                 uid = ActivityThread.getPackageManager().getPackageUid(name);
@@ -5035,6 +5096,8 @@
             }
         }
 
+        Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
+
         Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
         while (badApps.hasNext()) {
             SparseArray<Long> ba = badApps.next();
@@ -5043,37 +5106,12 @@
             }
         }
 
-        ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
-
-        // Remove all processes this package may have touched: all with the
-        // same UID (except for the system or root user), and all whose name
-        // matches the package name.
-        for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
-            final int NA = apps.size();
-            for (int ia=0; ia<NA; ia++) {
-                ProcessRecord app = apps.valueAt(ia);
-                if (app.removed) {
-                    procs.add(app);
-                } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
-                        || app.processName.equals(name)
-                        || app.processName.startsWith(procNamePrefix)) {
-                    app.removed = true;
-                    procs.add(app);
-                }
-            }
-        }
-
-        N = procs.size();
-        for (i=0; i<N; i++) {
-            removeProcessLocked(procs.get(i), callerWillRestart);
-        }
+        killPackageProcessesLocked(name, uid, -100, callerWillRestart);
         
         for (i=mHistory.size()-1; i>=0; i--) {
             HistoryRecord r = (HistoryRecord)mHistory.get(i);
             if (r.packageName.equals(name)) {
-                if (Config.LOGD) Log.d(
-                    TAG, "  Force finishing activity "
-                    + r.intent.getComponent().flattenToShortString());
+                Log.i(TAG, "  Force finishing activity " + r);
                 if (r.app != null) {
                     r.app.removed = true;
                 }
@@ -5085,6 +5123,7 @@
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
         for (ServiceRecord service : mServices.values()) {
             if (service.packageName.equals(name)) {
+                Log.i(TAG, "  Force stopping service " + service);
                 if (service.app != null) {
                     service.app.removed = true;
                 }
@@ -5104,7 +5143,7 @@
     private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
         final String name = app.processName;
         final int uid = app.info.uid;
-        if (Config.LOGD) Log.d(
+        if (DEBUG_PROCESSES) Log.d(
             TAG, "Force removing process " + app + " (" + name
             + "/" + uid + ")");
 
@@ -7861,7 +7900,7 @@
 
         synchronized(this) {
             int count = mHistory.size();
-            if (Config.LOGD) Log.d(
+            if (DEBUG_SWITCH) Log.d(
                 TAG, "Performing unhandledBack(): stack size = " + count);
             if (count > 1) {
                 final long origId = Binder.clearCallingIdentity();
@@ -8062,7 +8101,7 @@
             mDebugTransient = !persistent;
             if (packageName != null) {
                 final long origId = Binder.clearCallingIdentity();
-                uninstallPackageLocked(packageName, -1, false);
+                forceStopPackageLocked(packageName, -1, false);
                 Binder.restoreCallingIdentity(origId);
             }
         }
@@ -8686,8 +8725,7 @@
             for (int i=mHistory.size()-1; i>=0; i--) {
                 HistoryRecord r = (HistoryRecord)mHistory.get(i);
                 if (r.app == app) {
-                    if (Config.LOGD) Log.d(
-                        TAG, "  Force finishing activity "
+                    Log.w(TAG, "  Force finishing activity "
                         + r.intent.getComponent().flattenToShortString());
                     finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
                 }
@@ -11922,7 +11960,7 @@
                     String ssp;
                     if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                         if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
-                            uninstallPackageLocked(ssp,
+                            forceStopPackageLocked(ssp,
                                     intent.getIntExtra(Intent.EXTRA_UID, -1), false);
                             AttributeCache ac = AttributeCache.instance();
                             if (ac != null) {
@@ -12890,7 +12928,7 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
-            uninstallPackageLocked(ii.targetPackage, -1, true);
+            forceStopPackageLocked(ii.targetPackage, -1, true);
             ProcessRecord app = addAppLocked(ai);
             app.instrumentationClass = className;
             app.instrumentationInfo = ai;
@@ -12945,7 +12983,7 @@
         app.instrumentationProfileFile = null;
         app.instrumentationArguments = null;
 
-        uninstallPackageLocked(app.processName, -1, false);
+        forceStopPackageLocked(app.processName, -1, false);
     }
 
     public void finishInstrumentation(IApplicationThread target,