summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java20
-rw-r--r--core/java/android/app/ActivityManagerNative.java21
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java104
4 files changed, 125 insertions, 22 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index d8b2286..040a994 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -112,6 +112,10 @@ public class Am {
runForceStop();
} else if (op.equals("clear-data")) {
runClearData();
+ } else if (op.equals("kill")) {
+ runKill();
+ } else if (op.equals("kill-all")) {
+ runKillAll();
} else if (op.equals("instrument")) {
runInstrument();
} else if (op.equals("broadcast")) {
@@ -502,6 +506,14 @@ public class Am {
mAm.forceStopPackage(nextArgRequired());
}
+ private void runKill() throws Exception {
+ mAm.killBackgroundProcesses(nextArgRequired());
+ }
+
+ private void runKillAll() throws Exception {
+ mAm.killAllBackgroundProcesses();
+ }
+
class ClearUserDataObserver extends IPackageDataObserver.Stub {
public int status = -1;
@@ -1223,6 +1235,8 @@ public class Am {
" am startservice <INTENT>\n" +
" am force-stop <PACKAGE>\n" +
" am clear-data <PACKAGE>\n" +
+ " am kill <PACKAGE>\n" +
+ " am kill-all\n" +
" am broadcast <INTENT>\n" +
" am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
" [--no-window-animation] <COMPONENT>\n" +
@@ -1246,6 +1260,12 @@ public class Am {
"\n" +
"am force-stop: force stop everything associated with <PACKAGE>.\n" +
"\n" +
+ "am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" +
+ " processes that are safe to kill -- that is, will not impact the user\n" +
+ " experience.\n" +
+ "\n" +
+ "am kill-all: Kill all background processes.\n" +
+ "\n" +
"am clear-data: clear the user data associated with <PACKAGE>.\n" +
"\n" +
"am broadcast: send a broadcast Intent.\n" +
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b4471f0..7994d7c 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1092,6 +1092,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeNoException();
return true;
}
+
+ case KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ killAllBackgroundProcesses();
+ reply.writeNoException();
+ return true;
+ }
case FORCE_STOP_PACKAGE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
@@ -2906,7 +2913,7 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
public void killBackgroundProcesses(String packageName) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -2917,7 +2924,17 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
+ public void killAllBackgroundProcesses() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(KILL_ALL_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();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 26813bf..5222d37 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -234,6 +234,7 @@ public interface IActivityManager extends IInterface {
public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException;
public void killBackgroundProcesses(final String packageName) throws RemoteException;
+ public void killAllBackgroundProcesses() throws RemoteException;
public void forceStopPackage(final String packageName) throws RemoteException;
// Note: probably don't want to allow applications access to these.
@@ -605,4 +606,5 @@ public interface IActivityManager extends IInterface {
int GET_PROCESS_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+136;
int SHOW_BOOT_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+137;
int DISMISS_KEYGUARD_ON_NEXT_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+138;
+ int KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+139;
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d5d5ea1..71499c7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1233,6 +1233,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
Thread thread = new Thread() {
@Override public void run() {
+ StringBuilder dropBuilder = new StringBuilder(1024);
+ StringBuilder logBuilder = new StringBuilder(1024);
try {
java.lang.Process proc = Runtime.getRuntime().exec(new String[] {
"procrank", });
@@ -1246,16 +1248,29 @@ public final class ActivityManagerService extends ActivityManagerNative
break;
}
if (line.length() > 0) {
- Slog.i(TAG, line);
+ logBuilder.append(line);
+ logBuilder.append('\n');
}
+ dropBuilder.append(line);
+ dropBuilder.append('\n');
}
converter.close();
} catch (IOException e) {
}
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
- dumpApplicationMemoryUsage(null, pw, " ", new String[] { }, true);
- Slog.i(TAG, sw.toString());
+ StringWriter catSw = new StringWriter();
+ PrintWriter catPw = new PrintWriter(catSw);
+ dumpApplicationMemoryUsage(null, pw, " ", new String[] { }, true, catPw);
+ String memUsage = sw.toString();
+ dropBuilder.append('\n');
+ dropBuilder.append(memUsage);
+ dropBuilder.append(catSw.toString());
+ logBuilder.append(memUsage);
+ addErrorToDropBox("watchdog", null, "system_server", null,
+ null, "Low on memory -- no more background processes",
+ dropBuilder.toString(), null, null);
+ Slog.i(TAG, logBuilder.toString());
synchronized (ActivityManagerService.this) {
long now = SystemClock.uptimeMillis();
if (mLastMemUsageReportTime < now) {
@@ -1407,7 +1422,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
- mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false);
+ mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
}
}
@@ -3213,7 +3228,49 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
killPackageProcessesLocked(packageName, pkgUid,
- ProcessList.SERVICE_ADJ, false, true, true, false);
+ ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ public void killAllBackgroundProcesses() {
+ if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: killAllBackgroundProcesses() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized(this) {
+ ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
+ 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.persistent) {
+ // we don't kill persistent processes
+ continue;
+ }
+ if (app.removed) {
+ procs.add(app);
+ } else if (app.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+ app.removed = true;
+ procs.add(app);
+ }
+ }
+ }
+
+ int N = procs.size();
+ for (int i=0; i<N; i++) {
+ removeProcessLocked(procs.get(i), false, true, "kill all background");
+ }
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -3385,7 +3442,7 @@ public final class ActivityManagerService extends ActivityManagerNative
private final boolean killPackageProcessesLocked(String packageName, int uid,
int minOomAdj, boolean callerWillRestart, boolean allowRestart, boolean doit,
- boolean evenPersistent) {
+ boolean evenPersistent, String reason) {
ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
// Remove all processes this package may have touched: all with the
@@ -3420,7 +3477,7 @@ public final class ActivityManagerService extends ActivityManagerNative
int N = procs.size();
for (int i=0; i<N; i++) {
- removeProcessLocked(procs.get(i), callerWillRestart, allowRestart);
+ removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
}
return N > 0;
}
@@ -3451,7 +3508,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
boolean didSomething = killPackageProcessesLocked(name, uid, -100,
- callerWillRestart, false, doit, evenPersistent);
+ callerWillRestart, false, doit, evenPersistent, "force stop");
TaskRecord lastTask = null;
for (i=0; i<mMainStack.mHistory.size(); i++) {
@@ -3539,11 +3596,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private final boolean removeProcessLocked(ProcessRecord app,
- boolean callerWillRestart, boolean allowRestart) {
+ boolean callerWillRestart, boolean allowRestart, String reason) {
final String name = app.processName;
final int uid = app.info.uid;
if (DEBUG_PROCESSES) Slog.d(
- TAG, "Force removing process " + app + " (" + name
+ TAG, "Force removing proc " + app.toShortString() + " (" + name
+ "/" + uid + ")");
mProcessNames.remove(name, uid);
@@ -3558,9 +3615,10 @@ public final class ActivityManagerService extends ActivityManagerNative
mPidsSelfLocked.remove(pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
+ Slog.i(TAG, "Killing proc " + app.toShortString() + ": " + reason);
handleAppDiedLocked(app, true, allowRestart);
mLruProcesses.remove(app);
- Process.killProcess(pid);
+ Process.killProcessQuiet(pid);
if (app.persistent) {
if (!callerWillRestart) {
@@ -6869,7 +6927,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
Slog.i(TAG, "Removing system update proc: " + proc);
- removeProcessLocked(proc, true, false);
+ removeProcessLocked(proc, true, false, "system update done");
}
}
@@ -7065,7 +7123,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Don't let services in this process be restarted and potentially
// annoy the user repeatedly. Unless it is persistent, since those
// processes run critical code.
- removeProcessLocked(app, false, false);
+ removeProcessLocked(app, false, false, "crash");
mMainStack.resumeTopActivityLocked(null);
return false;
}
@@ -9321,8 +9379,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
final void dumpApplicationMemoryUsage(FileDescriptor fd,
- PrintWriter pw, String prefix, String[] args, boolean brief) {
+ PrintWriter pw, String prefix, String[] args, boolean brief,
+ PrintWriter categoryPw) {
boolean dumpAll = false;
+ boolean oomOnly = false;
int opti = 0;
while (opti < args.length) {
@@ -9333,9 +9393,12 @@ public final class ActivityManagerService extends ActivityManagerNative
opti++;
if ("-a".equals(opt)) {
dumpAll = true;
+ } else if ("--oom".equals(opt)) {
+ oomOnly = true;
} else if ("-h".equals(opt)) {
- pw.println("meminfo dump options: [-a] [process]");
+ pw.println("meminfo dump options: [-a] [--oom] [process]");
pw.println(" -a: include all available information for each process.");
+ pw.println(" --oom: only show processes organized by oom adj.");
pw.println("If [process] is specified it can be the name or ");
pw.println("pid of a specific process to dump.");
return;
@@ -9461,7 +9524,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- if (!brief) {
+ if (!brief && !oomOnly) {
pw.println();
pw.println("Total PSS by process:");
dumpMemItems(pw, " ", procMems, true);
@@ -9469,10 +9532,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
pw.println("Total PSS by OOM adjustment:");
dumpMemItems(pw, " ", oomMems, false);
- if (!brief) {
- pw.println();
- pw.println("Total PSS by category:");
- dumpMemItems(pw, " ", catMems, true);
+ if (!oomOnly) {
+ PrintWriter out = categoryPw != null ? categoryPw : pw;
+ out.println();
+ out.println("Total PSS by category:");
+ dumpMemItems(out, " ", catMems, true);
}
pw.println();
pw.print("Total PSS: "); pw.print(totalPss); pw.println(" Kb");