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

Commit 287952c3 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #3022508: Crash during media scan

Don't kill processes for excessive wake lock use, even if they
are in the background, as long as they have running services.

Also fix some problems with this, such as not noting the kill
in battery stats.

And add killing of processes for cpu usage as well, along with
some optimizations to computing CPU usage.

And fix BatteryWaster to be better behaving for testing these
cases.

Add new "monitor" command to am to watch as the activity manager
does stuff (so we can catch things at the point of ANR).

Finally some miscellaneous debug output for the stuff here, as
well as in progress debugging of an ANR.

Change-Id: Ib32f55ca50fb7486b4be4eb5e695f8f60c882cd1
parent f9ec03c0
Loading
Loading
Loading
Loading
+214 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
package com.android.commands.am;

import android.app.ActivityManagerNative;
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IInstrumentationWatcher;
import android.app.Instrumentation;
@@ -33,8 +34,13 @@ import android.os.ServiceManager;
import android.util.AndroidException;
import android.view.IWindowManager;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URISyntaxException;
import java.util.Iterator;
@@ -98,6 +104,8 @@ public class Am {
            sendBroadcast();
        } else if (op.equals("profile")) {
            runProfile();
        } else if (op.equals("monitor")) {
            runMonitor();
        } else {
            throw new IllegalArgumentException("Unknown command: " + op);
        }
@@ -424,6 +432,210 @@ public class Am {
        }
    }

    class MyActivityController extends IActivityController.Stub {
        static final int STATE_NORMAL = 0;
        static final int STATE_CRASHED = 1;
        static final int STATE_EARLY_ANR = 2;
        static final int STATE_ANR = 3;

        int mState;

        static final int RESULT_DEFAULT = 0;

        static final int RESULT_CRASH_DIALOG = 0;
        static final int RESULT_CRASH_KILL = 1;

        static final int RESULT_EARLY_ANR_CONTINUE = 0;
        static final int RESULT_EARLY_ANR_KILL = 1;

        static final int RESULT_ANR_DIALOG = 0;
        static final int RESULT_ANR_KILL = 1;
        static final int RESULT_ANR_WAIT = 1;

        int mResult;

        @Override
        public boolean activityResuming(String pkg) throws RemoteException {
            synchronized (this) {
                System.out.println("** Activity resuming: " + pkg);
            }
            return true;
        }

        @Override
        public boolean activityStarting(Intent intent, String pkg) throws RemoteException {
            synchronized (this) {
                System.out.println("** Activity starting: " + pkg);
            }
            return true;
        }

        @Override
        public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg,
                long timeMillis, String stackTrace) throws RemoteException {
            synchronized (this) {
                System.out.println("** ERROR: PROCESS CRASHED");
                System.out.println("processName: " + processName);
                System.out.println("processPid: " + pid);
                System.out.println("shortMsg: " + shortMsg);
                System.out.println("longMsg: " + longMsg);
                System.out.println("timeMillis: " + timeMillis);
                System.out.println("stack:");
                System.out.print(stackTrace);
                System.out.println("#");
                int result = waitControllerLocked(STATE_CRASHED);
                return result == RESULT_CRASH_KILL ? false : true;
            }
        }

        @Override
        public int appEarlyNotResponding(String processName, int pid, String annotation)
                throws RemoteException {
            synchronized (this) {
                System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING");
                System.out.println("processName: " + processName);
                System.out.println("processPid: " + pid);
                System.out.println("annotation: " + annotation);
                int result = waitControllerLocked(STATE_EARLY_ANR);
                if (result == RESULT_EARLY_ANR_KILL) return -1;
                return 0;
            }
        }

        @Override
        public int appNotResponding(String processName, int pid, String processStats)
                throws RemoteException {
            synchronized (this) {
                System.out.println("** ERROR: PROCESS NOT RESPONDING");
                System.out.println("processName: " + processName);
                System.out.println("processPid: " + pid);
                System.out.println("processStats:");
                System.out.print(processStats);
                System.out.println("#");
                int result = waitControllerLocked(STATE_ANR);
                if (result == RESULT_ANR_KILL) return -1;
                if (result == RESULT_ANR_WAIT) return 1;
                return 0;
            }
        }

        int waitControllerLocked(int state) {
            mState = state;
            System.out.println("");
            printMessageForState();

            while (mState != STATE_NORMAL) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }

            return mResult;
        }

        void resumeController(int result) {
            synchronized (this) {
                mState = STATE_NORMAL;
                mResult = result;
                notifyAll();
            }
        }

        void printMessageForState() {
            switch (mState) {
                case STATE_NORMAL:
                    System.out.println("Monitoring activity manager...  available commands:");
                    break;
                case STATE_CRASHED:
                    System.out.println("Waiting after crash...  available commands:");
                    System.out.println("(c)ontinue: show crash dialog");
                    System.out.println("(k)ill: immediately kill app");
                    break;
                case STATE_EARLY_ANR:
                    System.out.println("Waiting after early ANR...  available commands:");
                    System.out.println("(c)ontinue: standard ANR processing");
                    System.out.println("(k)ill: immediately kill app");
                    break;
                case STATE_ANR:
                    System.out.println("Waiting after ANR...  available commands:");
                    System.out.println("(c)ontinue: show ANR dialog");
                    System.out.println("(k)ill: immediately kill app");
                    System.out.println("(w)ait: wait some more");
                    break;
            }
            System.out.println("(q)uit: finish monitoring");
        }

        void run() throws RemoteException {
            try {
                printMessageForState();

                mAm.setActivityController(this);
                mState = STATE_NORMAL;

                InputStreamReader converter = new InputStreamReader(System.in);
                BufferedReader in = new BufferedReader(converter);
                String line;

                while ((line = in.readLine()) != null) {
                    boolean addNewline = true;
                    if (line.length() <= 0) {
                        addNewline = false;
                    } else if ("q".equals(line) || "quit".equals(line)) {
                        resumeController(RESULT_DEFAULT);
                        break;
                    } else if (mState == STATE_CRASHED) {
                        if ("c".equals(line) || "continue".equals(line)) {
                            resumeController(RESULT_CRASH_DIALOG);
                        } else if ("k".equals(line) || "kill".equals(line)) {
                            resumeController(RESULT_CRASH_KILL);
                        } else {
                            System.out.println("Invalid command: " + line);
                        }
                    } else if (mState == STATE_ANR) {
                        if ("c".equals(line) || "continue".equals(line)) {
                            resumeController(RESULT_ANR_DIALOG);
                        } else if ("k".equals(line) || "kill".equals(line)) {
                            resumeController(RESULT_ANR_KILL);
                        } else if ("w".equals(line) || "wait".equals(line)) {
                            resumeController(RESULT_ANR_WAIT);
                        } else {
                            System.out.println("Invalid command: " + line);
                        }
                    } else if (mState == STATE_EARLY_ANR) {
                        if ("c".equals(line) || "continue".equals(line)) {
                            resumeController(RESULT_EARLY_ANR_CONTINUE);
                        } else if ("k".equals(line) || "kill".equals(line)) {
                            resumeController(RESULT_EARLY_ANR_KILL);
                        } else {
                            System.out.println("Invalid command: " + line);
                        }
                    } else {
                        System.out.println("Invalid command: " + line);
                    }

                    synchronized (this) {
                        if (addNewline) {
                            System.out.println("");
                        }
                        printMessageForState();
                    }
                }

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                mAm.setActivityController(null);
            }
        }
    }

    private void runMonitor() throws Exception {
        MyActivityController controller = new MyActivityController();
        controller.run();
    }

    private class IntentReceiver extends IIntentReceiver.Stub {
        private boolean mFinished = false;

@@ -594,6 +806,8 @@ public class Am {
                "    start profiling: am profile <PROCESS> start <FILE>\n" +
                "    stop profiling: am profile <PROCESS> stop\n" +
                "\n" +
                "    start monitoring: am monitor\n" +
                "\n" +
                "    <INTENT> specifications include these flags:\n" +
                "        [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
                "        [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
+11 −2
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ import android.util.Config;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.LogPrinter;
import android.util.Slog;
import android.view.Display;
import android.view.View;
@@ -118,6 +119,7 @@ public final class ActivityThread {
    private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565;
    private static final boolean DEBUG = false;
    static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
    static final boolean DEBUG_MESSAGES = false;
    static final boolean DEBUG_BROADCAST = false;
    private static final boolean DEBUG_RESULTS = false;
    private static final boolean DEBUG_BACKUP = false;
@@ -874,7 +876,7 @@ public final class ActivityThread {
        public static final int DISPATCH_PACKAGE_BROADCAST = 133;
        public static final int SCHEDULE_CRASH          = 134;
        String codeToString(int code) {
            if (localLOGV) {
            if (DEBUG_MESSAGES) {
                switch (code) {
                    case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
                    case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY";
@@ -916,6 +918,7 @@ public final class ActivityThread {
            return "(unknown)";
        }
        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what);
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;
@@ -1037,6 +1040,7 @@ public final class ActivityThread {
                case SCHEDULE_CRASH:
                    throw new RemoteServiceException((String)msg.obj);
            }
            if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
        }

        void maybeSnapshot() {
@@ -1484,7 +1488,7 @@ public final class ActivityThread {

    private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
        synchronized (this) {
            if (localLOGV) Slog.v(
            if (DEBUG_MESSAGES) Slog.v(
                TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
                + ": " + arg1 + " / " + obj);
            Message msg = Message.obtain();
@@ -3608,6 +3612,11 @@ public final class ActivityThread {
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();

        if (Process.supportsProcesses()) {
+5 −0
Original line number Diff line number Diff line
@@ -47,6 +47,11 @@ interface IActivityController
            String shortMsg, String longMsg,
            long timeMillis, String stackTrace);
    
    /**
     * Early call as soon as an ANR is detected.
     */
    int appEarlyNotResponding(String processName, int pid, String annotation);

    /**
     * An application process is not responding.  Return 0 to show the "app
     * not responding" dialog, 1 to continue waiting, or -1 to kill it
+18 −6
Original line number Diff line number Diff line
@@ -301,7 +301,11 @@ public abstract class BatteryStats implements Parcelable {
         */
        public static abstract class Proc {

            public static class ExcessiveWake {
            public static class ExcessivePower {
                public static final int TYPE_WAKE = 1;
                public static final int TYPE_CPU = 2;

                public int type;
                public long overTime;
                public long usedTime;
            }
@@ -343,9 +347,9 @@ public abstract class BatteryStats implements Parcelable {
             */
            public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);

            public abstract int countExcessiveWakes();
            public abstract int countExcessivePowers();

            public abstract ExcessiveWake getExcessiveWake(int i);
            public abstract ExcessivePower getExcessivePower(int i);
        }

        /**
@@ -1593,7 +1597,7 @@ public abstract class BatteryStats implements Parcelable {
                    systemTime = ps.getSystemTime(which);
                    starts = ps.getStarts(which);
                    numExcessive = which == STATS_SINCE_CHARGED
                            ? ps.countExcessiveWakes() : 0;
                            ? ps.countExcessivePowers() : 0;

                    if (userTime != 0 || systemTime != 0 || starts != 0
                            || numExcessive != 0) {
@@ -1609,9 +1613,17 @@ public abstract class BatteryStats implements Parcelable {
                        }
                        pw.println(sb.toString());
                        for (int e=0; e<numExcessive; e++) {
                            Uid.Proc.ExcessiveWake ew = ps.getExcessiveWake(e);
                            Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e);
                            if (ew != null) {
                                pw.print(prefix); pw.print("      * Killed for wake lock use: ");
                                pw.print(prefix); pw.print("      * Killed for ");
                                        if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) {
                                            pw.print("wake lock");
                                        } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) {
                                            pw.print("cpu");
                                        } else {
                                            pw.print("unknown");
                                        }
                                        pw.print(" use: ");
                                        TimeUtils.formatDuration(ew.usedTime, pw);
                                        pw.print(" over ");
                                        TimeUtils.formatDuration(ew.overTime, pw);
+53 −25
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ public final class BatteryStatsImpl extends BatteryStats {
    private static final int MAGIC = 0xBA757475; // 'BATSTATS' 

    // Current on-disk Parcel version
    private static final int VERSION = 51;
    private static final int VERSION = 52;

    // Maximum number of items we will record in the history.
    private static final int MAX_HISTORY_ITEMS = 2000;
@@ -85,7 +85,7 @@ public final class BatteryStatsImpl extends BatteryStats {

    static final int MSG_UPDATE_WAKELOCKS = 1;
    static final int MSG_REPORT_POWER_CHANGE = 2;
    static final long DELAY_UPDATE_WAKELOCKS = 15*1000;
    static final long DELAY_UPDATE_WAKELOCKS = 5*1000;

    public interface BatteryCallback {
        public void batteryNeedsCpuUpdate();
@@ -1474,6 +1474,13 @@ public final class BatteryStatsImpl extends BatteryStats {
        }
    }

    public void reportExcessiveCpuLocked(int uid, String proc, long overTime, long usedTime) {
        Uid u = mUidStats.get(uid);
        if (u != null) {
            u.reportExcessiveCpuLocked(proc, overTime, usedTime);
        }
    }

    int mSensorNesting;

    public void noteStartSensorLocked(int uid, int sensor) {
@@ -2975,7 +2982,7 @@ public final class BatteryStatsImpl extends BatteryStats {

            SamplingCounter[] mSpeedBins;

            ArrayList<ExcessiveWake> mExcessiveWake;
            ArrayList<ExcessivePower> mExcessivePower;

            Proc() {
                mUnpluggables.add(this);
@@ -3003,55 +3010,69 @@ public final class BatteryStatsImpl extends BatteryStats {
                }
            }
            
            public int countExcessiveWakes() {
                return mExcessiveWake != null ? mExcessiveWake.size() : 0;
            public int countExcessivePowers() {
                return mExcessivePower != null ? mExcessivePower.size() : 0;
            }

            public ExcessiveWake getExcessiveWake(int i) {
                if (mExcessiveWake != null) {
                    return mExcessiveWake.get(i);
            public ExcessivePower getExcessivePower(int i) {
                if (mExcessivePower != null) {
                    return mExcessivePower.get(i);
                }
                return null;
            }

            public void addExcessiveWake(long overTime, long usedTime) {
                if (mExcessiveWake == null) {
                    mExcessiveWake = new ArrayList<ExcessiveWake>();
                if (mExcessivePower == null) {
                    mExcessivePower = new ArrayList<ExcessivePower>();
                }
                ExcessiveWake ew = new ExcessiveWake();
                ExcessivePower ew = new ExcessivePower();
                ew.type = ExcessivePower.TYPE_WAKE;
                ew.overTime = overTime;
                ew.usedTime = usedTime;
                mExcessiveWake.add(ew);
                mExcessivePower.add(ew);
            }

            void writeExcessiveWakeToParcelLocked(Parcel out) {
                if (mExcessiveWake == null) {
            public void addExcessiveCpu(long overTime, long usedTime) {
                if (mExcessivePower == null) {
                    mExcessivePower = new ArrayList<ExcessivePower>();
                }
                ExcessivePower ew = new ExcessivePower();
                ew.type = ExcessivePower.TYPE_CPU;
                ew.overTime = overTime;
                ew.usedTime = usedTime;
                mExcessivePower.add(ew);
            }

            void writeExcessivePowerToParcelLocked(Parcel out) {
                if (mExcessivePower == null) {
                    out.writeInt(0);
                    return;
                }

                final int N = mExcessiveWake.size();
                final int N = mExcessivePower.size();
                out.writeInt(N);
                for (int i=0; i<N; i++) {
                    ExcessiveWake ew = mExcessiveWake.get(i);
                    ExcessivePower ew = mExcessivePower.get(i);
                    out.writeInt(ew.type);
                    out.writeLong(ew.overTime);
                    out.writeLong(ew.usedTime);
                }
            }

            void readExcessiveWakeFromParcelLocked(Parcel in) {
            void readExcessivePowerFromParcelLocked(Parcel in) {
                final int N = in.readInt();
                if (N == 0) {
                    mExcessiveWake = null;
                    mExcessivePower = null;
                    return;
                }

                mExcessiveWake = new ArrayList<ExcessiveWake>();
                mExcessivePower = new ArrayList<ExcessivePower>();
                for (int i=0; i<N; i++) {
                    ExcessiveWake ew = new ExcessiveWake();
                    ExcessivePower ew = new ExcessivePower();
                    ew.type = in.readInt();
                    ew.overTime = in.readLong();
                    ew.usedTime = in.readLong();
                    mExcessiveWake.add(ew);
                    mExcessivePower.add(ew);
                }
            }

@@ -3080,7 +3101,7 @@ public final class BatteryStatsImpl extends BatteryStats {
                    }
                }

                writeExcessiveWakeToParcelLocked(out);
                writeExcessivePowerToParcelLocked(out);
            }

            void readFromParcelLocked(Parcel in) {
@@ -3110,7 +3131,7 @@ public final class BatteryStatsImpl extends BatteryStats {
                    }
                }

                readExcessiveWakeFromParcelLocked(in);
                readExcessivePowerFromParcelLocked(in);
            }

            public BatteryStatsImpl getBatteryStats() {
@@ -3744,6 +3765,13 @@ public final class BatteryStatsImpl extends BatteryStats {
            }
        }
        
        public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
            Proc p = getProcessStatsLocked(proc);
            if (p != null) {
                p.addExcessiveCpu(overTime, usedTime);
            }
        }

        public void noteStartSensor(int sensor) {
            StopwatchTimer t = getSensorTimerLocked(sensor, true);
            if (t != null) {
@@ -4686,7 +4714,7 @@ public final class BatteryStatsImpl extends BatteryStats {
                        p.mSpeedBins[i].readSummaryFromParcelLocked(in);
                    }
                }
                p.readExcessiveWakeFromParcelLocked(in);
                p.readExcessivePowerFromParcelLocked(in);
            }

            NP = in.readInt();
@@ -4885,7 +4913,7 @@ public final class BatteryStatsImpl extends BatteryStats {
                            out.writeInt(0);
                        }
                    }
                    ps.writeExcessiveWakeToParcelLocked(out);
                    ps.writeExcessivePowerToParcelLocked(out);
                }
            }

Loading