Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e4d4fbc8 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

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
parent 665e105f
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -109,6 +109,10 @@ public class Am {
            runStartService();
        } else if (op.equals("force-stop")) {
            runForceStop();
        } else if (op.equals("kill")) {
            runKill();
        } else if (op.equals("kill-all")) {
            runKillAll();
        } else if (op.equals("instrument")) {
            runInstrument();
        } else if (op.equals("broadcast")) {
@@ -484,6 +488,14 @@ public class Am {
        mAm.forceStopPackage(nextArgRequired());
    }

    private void runKill() throws Exception {
        mAm.killBackgroundProcesses(nextArgRequired());
    }

    private void runKillAll() throws Exception {
        mAm.killAllBackgroundProcesses();
    }

    private void sendBroadcast() throws Exception {
        Intent intent = makeIntent();
        IntentReceiver receiver = new IntentReceiver();
@@ -1179,6 +1191,8 @@ public class Am {
                "               [--R COUNT] [-S] <INTENT>\n" +
                "       am startservice <INTENT>\n" +
                "       am force-stop <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" +
@@ -1202,6 +1216,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 broadcast: send a broadcast Intent.\n" +
                "\n" +
                "am instrument: start an Instrumentation.  Typically this target <COMPONENT>\n" +
+19 −2
Original line number Diff line number Diff line
@@ -1093,6 +1093,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
            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);
            String packageName = data.readString();
@@ -2918,6 +2925,16 @@ class ActivityManagerProxy implements IActivityManager
        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();
+2 −0
Original line number Diff line number Diff line
@@ -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;
}
+84 −20
Original line number Diff line number Diff line
@@ -1220,6 +1220,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", });
@@ -1233,16 +1235,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) {
@@ -1394,7 +1409,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                return;
            }
            mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args, false);
            mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args, false, null);
        }
    }
@@ -3192,7 +3207,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);
@@ -3364,7 +3421,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
@@ -3399,7 +3456,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;
    }
@@ -3430,7 +3487,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++) {
@@ -3518,11 +3575,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);
@@ -3537,9 +3594,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) {
@@ -6846,7 +6904,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");
                }
            }
            
@@ -7042,7 +7100,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;
            }
@@ -9298,8 +9356,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) {
@@ -9310,9 +9370,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;
@@ -9438,7 +9501,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                }
            }
            if (!brief) {
            if (!brief && !oomOnly) {
                pw.println();
                pw.println("Total PSS by process:");
                dumpMemItems(pw, "  ", procMems, true);
@@ -9446,10 +9509,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");