Skip to content

Commit e4d4fbc

Browse files
author
Dianne Hackborn
committed
Add drop box reports of low memory.
We are tagging these as "watchdog" to make them visible in the reporting tools. Also new am command to kill all background processes, mostly to make it easier to test this stuff. Change-Id: Ib9dc4747cd8bd44156fdf11d6a087cd4272203eb
1 parent 665e105 commit e4d4fbc

File tree

4 files changed

+125
-22
lines changed

4 files changed

+125
-22
lines changed

cmds/am/src/com/android/commands/am/Am.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ private void run(String[] args) throws Exception {
109109
runStartService();
110110
} else if (op.equals("force-stop")) {
111111
runForceStop();
112+
} else if (op.equals("kill")) {
113+
runKill();
114+
} else if (op.equals("kill-all")) {
115+
runKillAll();
112116
} else if (op.equals("instrument")) {
113117
runInstrument();
114118
} else if (op.equals("broadcast")) {
@@ -484,6 +488,14 @@ private void runForceStop() throws Exception {
484488
mAm.forceStopPackage(nextArgRequired());
485489
}
486490

491+
private void runKill() throws Exception {
492+
mAm.killBackgroundProcesses(nextArgRequired());
493+
}
494+
495+
private void runKillAll() throws Exception {
496+
mAm.killAllBackgroundProcesses();
497+
}
498+
487499
private void sendBroadcast() throws Exception {
488500
Intent intent = makeIntent();
489501
IntentReceiver receiver = new IntentReceiver();
@@ -1179,6 +1191,8 @@ private static void showUsage() {
11791191
" [--R COUNT] [-S] <INTENT>\n" +
11801192
" am startservice <INTENT>\n" +
11811193
" am force-stop <PACKAGE>\n" +
1194+
" am kill <PACKAGE>\n" +
1195+
" am kill-all\n" +
11821196
" am broadcast <INTENT>\n" +
11831197
" am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
11841198
" [--no-window-animation] <COMPONENT>\n" +
@@ -1202,6 +1216,12 @@ private static void showUsage() {
12021216
"\n" +
12031217
"am force-stop: force stop everything associated with <PACKAGE>.\n" +
12041218
"\n" +
1219+
"am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" +
1220+
" processes that are safe to kill -- that is, will not impact the user\n" +
1221+
" experience.\n" +
1222+
"\n" +
1223+
"am kill-all: Kill all background processes.\n" +
1224+
"\n" +
12051225
"am broadcast: send a broadcast Intent.\n" +
12061226
"\n" +
12071227
"am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" +

core/java/android/app/ActivityManagerNative.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,13 @@ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
10921092
reply.writeNoException();
10931093
return true;
10941094
}
1095+
1096+
case KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION: {
1097+
data.enforceInterface(IActivityManager.descriptor);
1098+
killAllBackgroundProcesses();
1099+
reply.writeNoException();
1100+
return true;
1101+
}
10951102

10961103
case FORCE_STOP_PACKAGE_TRANSACTION: {
10971104
data.enforceInterface(IActivityManager.descriptor);
@@ -2906,7 +2913,7 @@ public void signalPersistentProcesses(int sig) throws RemoteException {
29062913
data.recycle();
29072914
reply.recycle();
29082915
}
2909-
2916+
29102917
public void killBackgroundProcesses(String packageName) throws RemoteException {
29112918
Parcel data = Parcel.obtain();
29122919
Parcel reply = Parcel.obtain();
@@ -2917,7 +2924,17 @@ public void killBackgroundProcesses(String packageName) throws RemoteException {
29172924
data.recycle();
29182925
reply.recycle();
29192926
}
2920-
2927+
2928+
public void killAllBackgroundProcesses() throws RemoteException {
2929+
Parcel data = Parcel.obtain();
2930+
Parcel reply = Parcel.obtain();
2931+
data.writeInterfaceToken(IActivityManager.descriptor);
2932+
mRemote.transact(KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION, data, reply, 0);
2933+
reply.readException();
2934+
data.recycle();
2935+
reply.recycle();
2936+
}
2937+
29212938
public void forceStopPackage(String packageName) throws RemoteException {
29222939
Parcel data = Parcel.obtain();
29232940
Parcel reply = Parcel.obtain();

core/java/android/app/IActivityManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ public void showWaitingForDebugger(IApplicationThread who, boolean waiting)
234234
public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException;
235235

236236
public void killBackgroundProcesses(final String packageName) throws RemoteException;
237+
public void killAllBackgroundProcesses() throws RemoteException;
237238
public void forceStopPackage(final String packageName) throws RemoteException;
238239

239240
// Note: probably don't want to allow applications access to these.
@@ -605,4 +606,5 @@ private WaitResult(Parcel source) {
605606
int GET_PROCESS_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+136;
606607
int SHOW_BOOT_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+137;
607608
int DISMISS_KEYGUARD_ON_NEXT_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+138;
609+
int KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+139;
608610
}

services/java/com/android/server/am/ActivityManagerService.java

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,8 @@ public void handleMessage(Message msg) {
12201220
}
12211221
Thread thread = new Thread() {
12221222
@Override public void run() {
1223+
StringBuilder dropBuilder = new StringBuilder(1024);
1224+
StringBuilder logBuilder = new StringBuilder(1024);
12231225
try {
12241226
java.lang.Process proc = Runtime.getRuntime().exec(new String[] {
12251227
"procrank", });
@@ -1233,16 +1235,29 @@ public void handleMessage(Message msg) {
12331235
break;
12341236
}
12351237
if (line.length() > 0) {
1236-
Slog.i(TAG, line);
1238+
logBuilder.append(line);
1239+
logBuilder.append('\n');
12371240
}
1241+
dropBuilder.append(line);
1242+
dropBuilder.append('\n');
12381243
}
12391244
converter.close();
12401245
} catch (IOException e) {
12411246
}
12421247
StringWriter sw = new StringWriter();
12431248
PrintWriter pw = new PrintWriter(sw);
1244-
dumpApplicationMemoryUsage(null, pw, " ", new String[] { }, true);
1245-
Slog.i(TAG, sw.toString());
1249+
StringWriter catSw = new StringWriter();
1250+
PrintWriter catPw = new PrintWriter(catSw);
1251+
dumpApplicationMemoryUsage(null, pw, " ", new String[] { }, true, catPw);
1252+
String memUsage = sw.toString();
1253+
dropBuilder.append('\n');
1254+
dropBuilder.append(memUsage);
1255+
dropBuilder.append(catSw.toString());
1256+
logBuilder.append(memUsage);
1257+
addErrorToDropBox("watchdog", null, "system_server", null,
1258+
null, "Low on memory -- no more background processes",
1259+
dropBuilder.toString(), null, null);
1260+
Slog.i(TAG, logBuilder.toString());
12461261
synchronized (ActivityManagerService.this) {
12471262
long now = SystemClock.uptimeMillis();
12481263
if (mLastMemUsageReportTime < now) {
@@ -1394,7 +1409,7 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
13941409
return;
13951410
}
13961411

1397-
mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false);
1412+
mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
13981413
}
13991414
}
14001415

@@ -3192,7 +3207,49 @@ public void killBackgroundProcesses(final String packageName) {
31923207
return;
31933208
}
31943209
killPackageProcessesLocked(packageName, pkgUid,
3195-
ProcessList.SERVICE_ADJ, false, true, true, false);
3210+
ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
3211+
}
3212+
} finally {
3213+
Binder.restoreCallingIdentity(callingId);
3214+
}
3215+
}
3216+
3217+
public void killAllBackgroundProcesses() {
3218+
if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
3219+
!= PackageManager.PERMISSION_GRANTED) {
3220+
String msg = "Permission Denial: killAllBackgroundProcesses() from pid="
3221+
+ Binder.getCallingPid()
3222+
+ ", uid=" + Binder.getCallingUid()
3223+
+ " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
3224+
Slog.w(TAG, msg);
3225+
throw new SecurityException(msg);
3226+
}
3227+
3228+
long callingId = Binder.clearCallingIdentity();
3229+
try {
3230+
synchronized(this) {
3231+
ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
3232+
for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
3233+
final int NA = apps.size();
3234+
for (int ia=0; ia<NA; ia++) {
3235+
ProcessRecord app = apps.valueAt(ia);
3236+
if (app.persistent) {
3237+
// we don't kill persistent processes
3238+
continue;
3239+
}
3240+
if (app.removed) {
3241+
procs.add(app);
3242+
} else if (app.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
3243+
app.removed = true;
3244+
procs.add(app);
3245+
}
3246+
}
3247+
}
3248+
3249+
int N = procs.size();
3250+
for (int i=0; i<N; i++) {
3251+
removeProcessLocked(procs.get(i), false, true, "kill all background");
3252+
}
31963253
}
31973254
} finally {
31983255
Binder.restoreCallingIdentity(callingId);
@@ -3364,7 +3421,7 @@ private void forceStopPackageLocked(final String packageName, int uid) {
33643421

33653422
private final boolean killPackageProcessesLocked(String packageName, int uid,
33663423
int minOomAdj, boolean callerWillRestart, boolean allowRestart, boolean doit,
3367-
boolean evenPersistent) {
3424+
boolean evenPersistent, String reason) {
33683425
ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
33693426

33703427
// Remove all processes this package may have touched: all with the
@@ -3399,7 +3456,7 @@ private final boolean killPackageProcessesLocked(String packageName, int uid,
33993456

34003457
int N = procs.size();
34013458
for (int i=0; i<N; i++) {
3402-
removeProcessLocked(procs.get(i), callerWillRestart, allowRestart);
3459+
removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
34033460
}
34043461
return N > 0;
34053462
}
@@ -3430,7 +3487,7 @@ private final boolean forceStopPackageLocked(String name, int uid,
34303487
}
34313488

34323489
boolean didSomething = killPackageProcessesLocked(name, uid, -100,
3433-
callerWillRestart, false, doit, evenPersistent);
3490+
callerWillRestart, false, doit, evenPersistent, "force stop");
34343491

34353492
TaskRecord lastTask = null;
34363493
for (i=0; i<mMainStack.mHistory.size(); i++) {
@@ -3518,11 +3575,11 @@ private final boolean forceStopPackageLocked(String name, int uid,
35183575
}
35193576

35203577
private final boolean removeProcessLocked(ProcessRecord app,
3521-
boolean callerWillRestart, boolean allowRestart) {
3578+
boolean callerWillRestart, boolean allowRestart, String reason) {
35223579
final String name = app.processName;
35233580
final int uid = app.info.uid;
35243581
if (DEBUG_PROCESSES) Slog.d(
3525-
TAG, "Force removing process " + app + " (" + name
3582+
TAG, "Force removing proc " + app.toShortString() + " (" + name
35263583
+ "/" + uid + ")");
35273584

35283585
mProcessNames.remove(name, uid);
@@ -3537,9 +3594,10 @@ private final boolean removeProcessLocked(ProcessRecord app,
35373594
mPidsSelfLocked.remove(pid);
35383595
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
35393596
}
3597+
Slog.i(TAG, "Killing proc " + app.toShortString() + ": " + reason);
35403598
handleAppDiedLocked(app, true, allowRestart);
35413599
mLruProcesses.remove(app);
3542-
Process.killProcess(pid);
3600+
Process.killProcessQuiet(pid);
35433601

35443602
if (app.persistent) {
35453603
if (!callerWillRestart) {
@@ -6846,7 +6904,7 @@ public void run() {
68466904
for (int i=procsToKill.size()-1; i>=0; i--) {
68476905
ProcessRecord proc = procsToKill.get(i);
68486906
Slog.i(TAG, "Removing system update proc: " + proc);
6849-
removeProcessLocked(proc, true, false);
6907+
removeProcessLocked(proc, true, false, "system update done");
68506908
}
68516909
}
68526910

@@ -7042,7 +7100,7 @@ private boolean handleAppCrashLocked(ProcessRecord app) {
70427100
// Don't let services in this process be restarted and potentially
70437101
// annoy the user repeatedly. Unless it is persistent, since those
70447102
// processes run critical code.
7045-
removeProcessLocked(app, false, false);
7103+
removeProcessLocked(app, false, false, "crash");
70467104
mMainStack.resumeTopActivityLocked(null);
70477105
return false;
70487106
}
@@ -9298,8 +9356,10 @@ public int compare(MemItem lhs, MemItem rhs) {
92989356
}
92999357

93009358
final void dumpApplicationMemoryUsage(FileDescriptor fd,
9301-
PrintWriter pw, String prefix, String[] args, boolean brief) {
9359+
PrintWriter pw, String prefix, String[] args, boolean brief,
9360+
PrintWriter categoryPw) {
93029361
boolean dumpAll = false;
9362+
boolean oomOnly = false;
93039363

93049364
int opti = 0;
93059365
while (opti < args.length) {
@@ -9310,9 +9370,12 @@ final void dumpApplicationMemoryUsage(FileDescriptor fd,
93109370
opti++;
93119371
if ("-a".equals(opt)) {
93129372
dumpAll = true;
9373+
} else if ("--oom".equals(opt)) {
9374+
oomOnly = true;
93139375
} else if ("-h".equals(opt)) {
9314-
pw.println("meminfo dump options: [-a] [process]");
9376+
pw.println("meminfo dump options: [-a] [--oom] [process]");
93159377
pw.println(" -a: include all available information for each process.");
9378+
pw.println(" --oom: only show processes organized by oom adj.");
93169379
pw.println("If [process] is specified it can be the name or ");
93179380
pw.println("pid of a specific process to dump.");
93189381
return;
@@ -9438,18 +9501,19 @@ final void dumpApplicationMemoryUsage(FileDescriptor fd,
94389501
}
94399502
}
94409503

9441-
if (!brief) {
9504+
if (!brief && !oomOnly) {
94429505
pw.println();
94439506
pw.println("Total PSS by process:");
94449507
dumpMemItems(pw, " ", procMems, true);
94459508
pw.println();
94469509
}
94479510
pw.println("Total PSS by OOM adjustment:");
94489511
dumpMemItems(pw, " ", oomMems, false);
9449-
if (!brief) {
9450-
pw.println();
9451-
pw.println("Total PSS by category:");
9452-
dumpMemItems(pw, " ", catMems, true);
9512+
if (!oomOnly) {
9513+
PrintWriter out = categoryPw != null ? categoryPw : pw;
9514+
out.println();
9515+
out.println("Total PSS by category:");
9516+
dumpMemItems(out, " ", catMems, true);
94539517
}
94549518
pw.println();
94559519
pw.print("Total PSS: "); pw.print(totalPss); pw.println(" Kb");

0 commit comments

Comments
 (0)