Fix issue #17323751: Additional items in aggregated battery stats

- Now aggregate number of times each process has crashed and ANRed.
- Now aggregate total number of connectivity changes.
- Now record connectivity changes in the history.

Crash and ANR counts are new entries at the end of "pr" in checkin.

Connectivity change counts is a new entry at the end of "m" in checkin.

Connectivity changes in the history checkin are Ecn and include the
type of connection and its state.

Change-Id: I0c01186446034cf6c3fb97d45f5e3b5c69a0438a
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 11fc69e..5fd697a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -459,6 +459,20 @@
             public abstract int getStarts(int which);
 
             /**
+             * Returns the number of times the process has crashed.
+             *
+             * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
+             */
+            public abstract int getNumCrashes(int which);
+
+            /**
+             * Returns the number of times the process has ANRed.
+             *
+             * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
+             */
+            public abstract int getNumAnrs(int which);
+
+            /**
              * Returns the cpu time spent in microseconds while the process was in the foreground.
              * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              * @return foreground cpu time in microseconds
@@ -694,8 +708,10 @@
         public static final int EVENT_USER_RUNNING = 0x0007;
         // Events for foreground user.
         public static final int EVENT_USER_FOREGROUND = 0x0008;
+        // Events for connectivity changed.
+        public static final int EVENT_CONNECTIVITY_CHANGED = 0x0009;
         // Number of event types.
-        public static final int EVENT_COUNT = 0x0009;
+        public static final int EVENT_COUNT = 0x000a;
         // Mask to extract out only the type part of the event.
         public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
 
@@ -1107,6 +1123,13 @@
     public abstract int getLowPowerModeEnabledCount(int which);
 
     /**
+     * Returns the number of times that connectivity state changed.
+     *
+     * {@hide}
+     */
+    public abstract int getNumConnectivityChange(int which);
+
+    /**
      * Returns the time in microseconds that the phone has been on while the device was
      * running on battery.
      * 
@@ -1306,11 +1329,11 @@
     };
 
     public static final String[] HISTORY_EVENT_NAMES = new String[] {
-            "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg"
+            "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn"
     };
 
     public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
-            "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf"
+            "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn"
     };
 
     /**
@@ -1871,6 +1894,7 @@
         final long screenOnTime = getScreenOnTime(rawRealtime, which);
         final long interactiveTime = getInteractiveTime(rawRealtime, which);
         final long lowPowerModeEnabledTime = getLowPowerModeEnabledTime(rawRealtime, which);
+        final int connChanges = getNumConnectivityChange(which);
         final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
         final long wifiOnTime = getWifiOnTime(rawRealtime, which);
         final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
@@ -1941,7 +1965,7 @@
                 fullWakeLockTimeTotal / 1000, partialWakeLockTimeTotal / 1000,
                 0 /*legacy input event count*/, getMobileRadioActiveTime(rawRealtime, which) / 1000,
                 getMobileRadioActiveAdjustedTime(which) / 1000, interactiveTime / 1000,
-                lowPowerModeEnabledTime / 1000);
+                lowPowerModeEnabledTime / 1000, connChanges);
         
         // Dump screen brightness stats
         Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -2271,12 +2295,14 @@
                     final long userMillis = ps.getUserTime(which) * 10;
                     final long systemMillis = ps.getSystemTime(which) * 10;
                     final long foregroundMillis = ps.getForegroundTime(which) * 10;
-                    final long starts = ps.getStarts(which);
+                    final int starts = ps.getStarts(which);
+                    final int numCrashes = ps.getNumCrashes(which);
+                    final int numAnrs = ps.getNumAnrs(which);
 
                     if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0
-                            || starts != 0) {
+                            || starts != 0 || numAnrs != 0 || numCrashes != 0) {
                         dumpLine(pw, uid, category, PROCESS_DATA, ent.getKey(), userMillis,
-                                systemMillis, foregroundMillis, starts);
+                                systemMillis, foregroundMillis, starts, numAnrs, numCrashes);
                     }
                 }
             }
@@ -2457,6 +2483,11 @@
                     sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
                     sb.append(") "); sb.append(getPhoneOnCount(which));
         }
+        int connChanges = getNumConnectivityChange(which);
+        if (connChanges != 0) {
+            pw.print(prefix);
+            pw.print("  Connectivity changes: "); pw.println(connChanges);
+        }
 
         // Calculate wakelock times across all uids.
         long fullWakeLockTimeTotalMicros = 0;
@@ -3273,11 +3304,13 @@
                     systemTime = ps.getSystemTime(which);
                     foregroundTime = ps.getForegroundTime(which);
                     starts = ps.getStarts(which);
+                    final int numCrashes = ps.getNumCrashes(which);
+                    final int numAnrs = ps.getNumAnrs(which);
                     numExcessive = which == STATS_SINCE_CHARGED
                             ? ps.countExcessivePowers() : 0;
 
                     if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0
-                            || numExcessive != 0) {
+                            || numExcessive != 0 || numCrashes != 0 || numAnrs != 0) {
                         sb.setLength(0);
                         sb.append(prefix); sb.append("    Proc ");
                                 sb.append(ent.getKey()); sb.append(":\n");
@@ -3285,9 +3318,26 @@
                                 formatTime(sb, userTime); sb.append("usr + ");
                                 formatTime(sb, systemTime); sb.append("krn ; ");
                                 formatTime(sb, foregroundTime); sb.append("fg");
-                        if (starts != 0) {
+                        if (starts != 0 || numCrashes != 0 || numAnrs != 0) {
                             sb.append("\n"); sb.append(prefix); sb.append("      ");
-                                    sb.append(starts); sb.append(" proc starts");
+                            boolean hasOne = false;
+                            if (starts != 0) {
+                                hasOne = true;
+                                sb.append(starts); sb.append(" starts");
+                            }
+                            if (numCrashes != 0) {
+                                if (hasOne) {
+                                    sb.append(", ");
+                                }
+                                hasOne = true;
+                                sb.append(numCrashes); sb.append(" crashes");
+                            }
+                            if (numAnrs != 0) {
+                                if (hasOne) {
+                                    sb.append(", ");
+                                }
+                                sb.append(numAnrs); sb.append(" anrs");
+                            }
                         }
                         pw.println(sb.toString());
                         for (int e=0; e<numExcessive; e++) {
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index a9b3571..121485a 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -295,6 +295,11 @@
         return bytes;
     }
 
+    static void wtfQuiet(int logId, String tag, String msg, boolean system) {
+        TerribleFailure what = new TerribleFailure(msg, null);
+        sWtfHandler.onTerribleFailure(tag, what, system);
+    }
+
     /**
      * Sets the terrible failure handler, for testing.
      *
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index e92b846..58a2703 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -83,6 +83,13 @@
     }
 
     /**
+     * Like {@link #wtf(String, String)}, but does not output anything to the log.
+     */
+    public static void wtfQuiet(String tag, String msg) {
+        Log.wtfQuiet(Log.LOG_ID_SYSTEM, tag, msg, true);
+    }
+
+    /**
      * Like {@link Log#wtfStack(String, String)}, but will never cause the caller to crash, and
      * will always be handled asynchronously.  Primarily for use by coding running within
      * the system process.
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 55b3ecc..87b6ed7 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -77,6 +77,7 @@
     void noteScreenBrightness(int brightness);
     void noteUserActivity(int uid, int event);
     void noteInteractive(boolean interactive);
+    void noteConnectivityChanged(int type, String extra);
     void noteMobileRadioPowerState(int powerState, long timestampNs);
     void notePhoneOn();
     void notePhoneOff();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0dfb11a..8ceee20 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -94,7 +94,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 115 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 116 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -374,6 +374,10 @@
     private int mPhoneServiceStateRaw = -1;
     private int mPhoneSimStateRaw = -1;
 
+    private int mNumConnectivityChange;
+    private int mLoadedNumConnectivityChange;
+    private int mUnpluggedNumConnectivityChange;
+
     /*
      * Holds a SamplingTimer associated with each kernel wakelock name being tracked.
      */
@@ -2540,6 +2544,22 @@
         addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_START, name, uid);
     }
 
+    public void noteProcessCrashLocked(String name, int uid) {
+        uid = mapUid(uid);
+        if (isOnBattery()) {
+            Uid u = getUidStatsLocked(uid);
+            u.getProcessStatsLocked(name).incNumCrashesLocked();
+        }
+    }
+
+    public void noteProcessAnrLocked(String name, int uid) {
+        uid = mapUid(uid);
+        if (isOnBattery()) {
+            Uid u = getUidStatsLocked(uid);
+            u.getProcessStatsLocked(name).incNumAnrsLocked();
+        }
+    }
+
     public void noteProcessStateLocked(String name, int uid, int state) {
         uid = mapUid(uid);
         final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -3109,6 +3129,14 @@
         }
     }
 
+    public void noteConnectivityChangedLocked(int type, String extra) {
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long uptime = SystemClock.uptimeMillis();
+        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_CONNECTIVITY_CHANGED,
+                extra, type);
+        mNumConnectivityChange++;
+    }
+
     public void noteMobileRadioPowerState(int powerState, long timestampNs) {
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         final long uptime = SystemClock.uptimeMillis();
@@ -3965,6 +3993,16 @@
         return mLowPowerModeEnabledTimer.getCountLocked(which);
     }
 
+    @Override public int getNumConnectivityChange(int which) {
+        int val = mNumConnectivityChange;
+        if (which == STATS_CURRENT) {
+            val -= mLoadedNumConnectivityChange;
+        } else if (which == STATS_SINCE_UNPLUGGED) {
+            val -= mUnpluggedNumConnectivityChange;
+        }
+        return val;
+    }
+
     @Override public long getPhoneOnTime(long elapsedRealtimeUs, int which) {
         return mPhoneOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
@@ -5374,6 +5412,16 @@
             int mStarts;
 
             /**
+             * Number of times the process has crashed.
+             */
+            int mNumCrashes;
+
+            /**
+             * Number of times the process has had an ANR.
+             */
+            int mNumAnrs;
+
+            /**
              * The amount of user time loaded from a previous save.
              */
             long mLoadedUserTime;
@@ -5394,24 +5442,14 @@
             int mLoadedStarts;
 
             /**
-             * The amount of user time loaded from the previous run.
+             * Number of times the process has crashed from a previous save.
              */
-            long mLastUserTime;
+            int mLoadedNumCrashes;
 
             /**
-             * The amount of system time loaded from the previous run.
+             * Number of times the process has had an ANR from a previous save.
              */
-            long mLastSystemTime;
-
-            /**
-             * The amount of foreground time loaded from the previous run
-             */
-            long mLastForegroundTime;
-
-            /**
-             * The number of times the process has started from the previous run.
-             */
-            int mLastStarts;
+            int mLoadedNumAnrs;
 
             /**
              * The amount of user time when last unplugged.
@@ -5434,6 +5472,16 @@
             int mUnpluggedStarts;
 
             /**
+             * Number of times the process has crashed before unplugged.
+             */
+            int mUnpluggedNumCrashes;
+
+            /**
+             * Number of times the process has had an ANR before unplugged.
+             */
+            int mUnpluggedNumAnrs;
+
+            /**
              * Current process state.
              */
             int mProcessState = PROCESS_STATE_NONE;
@@ -5453,6 +5501,8 @@
                 mUnpluggedSystemTime = mSystemTime;
                 mUnpluggedForegroundTime = mForegroundTime;
                 mUnpluggedStarts = mStarts;
+                mUnpluggedNumCrashes = mNumCrashes;
+                mUnpluggedNumAnrs = mNumAnrs;
             }
 
             public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -5460,13 +5510,11 @@
 
             void reset() {
                 mUserTime = mSystemTime = mForegroundTime = 0;
-                mStarts = 0;
+                mStarts = mNumCrashes = mNumAnrs = 0;
                 mLoadedUserTime = mLoadedSystemTime = mLoadedForegroundTime = 0;
-                mLoadedStarts = 0;
-                mLastUserTime = mLastSystemTime = mLastForegroundTime = 0;
-                mLastStarts = 0;
+                mLoadedStarts = mLoadedNumCrashes = mLoadedNumAnrs = 0;
                 mUnpluggedUserTime = mUnpluggedSystemTime = mUnpluggedForegroundTime = 0;
-                mUnpluggedStarts = 0;
+                mUnpluggedStarts = mUnpluggedNumCrashes = mUnpluggedNumAnrs = 0;
                 for (int i = 0; i < mSpeedBins.length; i++) {
                     SamplingCounter c = mSpeedBins[i];
                     if (c != null) {
@@ -5565,14 +5613,20 @@
                 out.writeLong(mSystemTime);
                 out.writeLong(mForegroundTime);
                 out.writeInt(mStarts);
+                out.writeInt(mNumCrashes);
+                out.writeInt(mNumAnrs);
                 out.writeLong(mLoadedUserTime);
                 out.writeLong(mLoadedSystemTime);
                 out.writeLong(mLoadedForegroundTime);
                 out.writeInt(mLoadedStarts);
+                out.writeInt(mLoadedNumCrashes);
+                out.writeInt(mLoadedNumAnrs);
                 out.writeLong(mUnpluggedUserTime);
                 out.writeLong(mUnpluggedSystemTime);
                 out.writeLong(mUnpluggedForegroundTime);
                 out.writeInt(mUnpluggedStarts);
+                out.writeInt(mUnpluggedNumCrashes);
+                out.writeInt(mUnpluggedNumAnrs);
 
                 out.writeInt(mSpeedBins.length);
                 for (int i = 0; i < mSpeedBins.length; i++) {
@@ -5593,18 +5647,20 @@
                 mSystemTime = in.readLong();
                 mForegroundTime = in.readLong();
                 mStarts = in.readInt();
+                mNumCrashes = in.readInt();
+                mNumAnrs = in.readInt();
                 mLoadedUserTime = in.readLong();
                 mLoadedSystemTime = in.readLong();
                 mLoadedForegroundTime = in.readLong();
                 mLoadedStarts = in.readInt();
-                mLastUserTime = 0;
-                mLastSystemTime = 0;
-                mLastForegroundTime = 0;
-                mLastStarts = 0;
+                mLoadedNumCrashes = in.readInt();
+                mLoadedNumAnrs = in.readInt();
                 mUnpluggedUserTime = in.readLong();
                 mUnpluggedSystemTime = in.readLong();
                 mUnpluggedForegroundTime = in.readLong();
                 mUnpluggedStarts = in.readInt();
+                mUnpluggedNumCrashes = in.readInt();
+                mUnpluggedNumAnrs = in.readInt();
 
                 int bins = in.readInt();
                 int steps = getCpuSpeedSteps();
@@ -5635,6 +5691,14 @@
                 mStarts++;
             }
 
+            public void incNumCrashesLocked() {
+                mNumCrashes++;
+            }
+
+            public void incNumAnrsLocked() {
+                mNumAnrs++;
+            }
+
             @Override
             public boolean isActive() {
                 return mActive;
@@ -5684,6 +5748,28 @@
                 return val;
             }
 
+            @Override
+            public int getNumCrashes(int which) {
+                int val = mNumCrashes;
+                if (which == STATS_CURRENT) {
+                    val -= mLoadedNumCrashes;
+                } else if (which == STATS_SINCE_UNPLUGGED) {
+                    val -= mUnpluggedNumCrashes;
+                }
+                return val;
+            }
+
+            @Override
+            public int getNumAnrs(int which) {
+                int val = mNumAnrs;
+                if (which == STATS_CURRENT) {
+                    val -= mLoadedNumAnrs;
+                } else if (which == STATS_SINCE_UNPLUGGED) {
+                    val -= mUnpluggedNumAnrs;
+                }
+                return val;
+            }
+
             /* Called by ActivityManagerService when CPU times are updated. */
             public void addSpeedStepTimes(long[] values) {
                 for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
@@ -6647,6 +6733,7 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].reset(false);
         }
+        mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
 
         for (int i=0; i<mUidStats.size(); i++) {
             if (mUidStats.valueAt(i).reset()) {
@@ -7861,6 +7948,7 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].readSummaryFromParcelLocked(in);
         }
+        mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
         mFlashlightOn = false;
         mFlashlightOnTimer.readSummaryFromParcelLocked(in);
 
@@ -8022,6 +8110,8 @@
                 p.mSystemTime = p.mLoadedSystemTime = in.readLong();
                 p.mForegroundTime = p.mLoadedForegroundTime = in.readLong();
                 p.mStarts = p.mLoadedStarts = in.readInt();
+                p.mNumCrashes = p.mLoadedNumCrashes = in.readInt();
+                p.mNumAnrs = p.mLoadedNumAnrs = in.readInt();
                 int NSB = in.readInt();
                 if (NSB > 100) {
                     Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
@@ -8143,6 +8233,7 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
+        out.writeInt(mNumConnectivityChange);
         mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
 
         out.writeInt(mKernelWakelockStats.size());
@@ -8326,6 +8417,8 @@
                 out.writeLong(ps.mSystemTime);
                 out.writeLong(ps.mForegroundTime);
                 out.writeInt(ps.mStarts);
+                out.writeInt(ps.mNumCrashes);
+                out.writeInt(ps.mNumAnrs);
                 final int N = ps.mSpeedBins.length;
                 out.writeInt(N);
                 for (int i=0; i<N; i++) {
@@ -8444,6 +8537,9 @@
             mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
                     null, mOnBatteryTimeBase, in);
         }
+        mNumConnectivityChange = in.readInt();
+        mLoadedNumConnectivityChange = in.readInt();
+        mUnpluggedNumConnectivityChange = in.readInt();
         mAudioOnNesting = 0;
         mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
         mVideoOnNesting = 0;
@@ -8588,6 +8684,9 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
         }
+        out.writeInt(mNumConnectivityChange);
+        out.writeInt(mLoadedNumConnectivityChange);
+        out.writeInt(mUnpluggedNumConnectivityChange);
         mFlashlightOnTimer.writeToParcel(out, uSecRealtime);
         out.writeInt(mDischargeUnplugLevel);
         out.writeInt(mDischargePlugLevel);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0f1ed0a..d5e4d23 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1524,6 +1524,17 @@
             }
 
             final long ident = Binder.clearCallingIdentity();
+            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+                final IBatteryStats bs = BatteryStatsService.getService();
+                try {
+                    NetworkInfo ni = intent.getParcelableExtra(
+                            ConnectivityManager.EXTRA_NETWORK_INFO);
+                    bs.noteConnectivityChanged(intent.getIntExtra(
+                            ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
+                            ni != null ? ni.getState().toString() : "?");
+                } catch (RemoteException e) {
+                }
+            }
             try {
                 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
             } finally {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5b1d212..bb9ac8f 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5024,6 +5024,8 @@
                 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
 
         synchronized (this) {
+            mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
+
             if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
                 app.kill("bg anr", true);
                 return;
@@ -10927,6 +10929,18 @@
                             && proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
                         if (doKilling && proc.initialIdlePss != 0
                                 && proc.lastPss > ((proc.initialIdlePss*3)/2)) {
+                            sb = new StringBuilder(128);
+                            sb.append("Kill");
+                            sb.append(proc.processName);
+                            sb.append(" in idle maint: pss=");
+                            sb.append(proc.lastPss);
+                            sb.append(", initialPss=");
+                            sb.append(proc.initialIdlePss);
+                            sb.append(", period=");
+                            TimeUtils.formatDuration(timeSinceLastIdle, sb);
+                            sb.append(", lowRamPeriod=");
+                            TimeUtils.formatDuration(lowRamSinceLastIdle, sb);
+                            Slog.wtfQuiet(TAG, sb.toString());
                             proc.kill("idle maint (pss " + proc.lastPss
                                     + " from " + proc.initialIdlePss + ")", true);
                         }
@@ -12035,6 +12049,11 @@
                 return;
             }
 
+            // Log crash in battery stats.
+            if (r != null) {
+                mBatteryStatsService.noteProcessCrash(r.processName, r.uid);
+            }
+
             // If we can't identify the process or it's already exceeded its crash quota,
             // quit right away without showing a crash dialog.
             if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 6983ec4..c0928c7 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -143,6 +143,18 @@
         }
     }
 
+    void noteProcessCrash(String name, int uid) {
+        synchronized (mStats) {
+            mStats.noteProcessCrashLocked(name, uid);
+        }
+    }
+
+    void noteProcessAnr(String name, int uid) {
+        synchronized (mStats) {
+            mStats.noteProcessAnrLocked(name, uid);
+        }
+    }
+
     void noteProcessState(String name, int uid, int state) {
         synchronized (mStats) {
             mStats.noteProcessStateLocked(name, uid, state);
@@ -349,6 +361,13 @@
         }
     }
 
+    public void noteConnectivityChanged(int type, String extra) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteConnectivityChangedLocked(type, extra);
+        }
+    }
+
     public void noteMobileRadioPowerState(int powerState, long timestampNs) {
         enforceCallingPermission();
         synchronized (mStats) {