Battery stats improvements.

- Adjust total power use when there is unaccounted power so that our
  percentages don't end up > 100%.
- Fix accounting of isolated uids to be against the owning real app
  uids.
- Rework how we put cpu use into the battery stats to no longer need
  this uid name cache that can confuse the uid it is associated with.
- Finish implementing events in the history, adding a string pool and
  reading/writing/dumping them.
- Add first two events: processes starting and finishing.
- Fix alarm manager reporting of wakeup alarms to be adjusted by the
  WorkSource associated with the alarm, so they are blamed on the
  correct app.
- New "--history" dump option allows you to perform a checkin of
  only the history data.
- Fixed BitDescription bug that would cause incorrect printing of
  changes in some states.

Change-Id: Ifbdd0740132ed178033851c58f165adc0d50f716
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 3cdf170..cb5ae96 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1258,8 +1258,16 @@
                                     || alarm.type == RTC_WAKEUP) {
                                 bs.numWakeup++;
                                 fs.numWakeup++;
-                                ActivityManagerNative.noteWakeupAlarm(
-                                        alarm.operation);
+                                if (alarm.workSource != null && alarm.workSource.size() > 0) {
+                                    for (int wi=0; wi<alarm.workSource.size(); wi++) {
+                                        ActivityManagerNative.noteWakeupAlarm(
+                                                alarm.operation, alarm.workSource.get(wi),
+                                                alarm.workSource.getName(wi));
+                                    }
+                                } else {
+                                    ActivityManagerNative.noteWakeupAlarm(
+                                            alarm.operation, -1, null);
+                                }
                             }
                         } catch (PendingIntent.CanceledException e) {
                             if (alarm.repeatInterval > 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 77ffeca..19efa9c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -32,6 +32,7 @@
 import android.app.IActivityContainerCallback;
 import android.appwidget.AppWidgetManager;
 import android.graphics.Rect;
+import android.os.BatteryStats;
 import android.util.ArrayMap;
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -2107,29 +2108,24 @@
                                 totalUTime += otherUTime;
                                 totalSTime += otherSTime;
                                 if (pr != null) {
-                                    BatteryStatsImpl.Uid.Proc ps = bstats.getProcessStatsLocked(
-                                            st.name, st.pid);
+                                    BatteryStatsImpl.Uid.Proc ps = pr.curProcBatteryStats;
+                                    if (ps == null || !ps.isActive()) {
+                                        pr.curProcBatteryStats = ps = bstats.getProcessStatsLocked(
+                                                pr.info.uid, pr.processName);
+                                    }
                                     ps.addCpuTimeLocked(st.rel_utime-otherUTime,
                                             st.rel_stime-otherSTime);
                                     ps.addSpeedStepTimes(cpuSpeedTimes);
                                     pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10;
-                                } else if (st.uid >= Process.FIRST_APPLICATION_UID) {
+                                } else {
                                     BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
-                                    if (ps == null) {
-                                        st.batteryStats = ps = bstats.getProcessStatsLocked(st.uid,
-                                                "(Unknown)");
+                                    if (ps == null || !ps.isActive()) {
+                                        st.batteryStats = ps = bstats.getProcessStatsLocked(
+                                                bstats.mapUid(st.uid), st.name);
                                     }
                                     ps.addCpuTimeLocked(st.rel_utime-otherUTime,
                                             st.rel_stime-otherSTime);
                                     ps.addSpeedStepTimes(cpuSpeedTimes);
-                                } else {
-                                    BatteryStatsImpl.Uid.Proc ps =
-                                            bstats.getProcessStatsLocked(st.name, st.pid);
-                                    if (ps != null) {
-                                        ps.addCpuTimeLocked(st.rel_utime-otherUTime,
-                                                st.rel_stime-otherSTime);
-                                        ps.addSpeedStepTimes(cpuSpeedTimes);
-                                    }
                                 }
                             }
                             bstats.finishAddingCpuLocked(perc, totalUTime,
@@ -2778,6 +2774,11 @@
                 mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                         ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
             }
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_STARTED,
+                    app.processName, app.info.uid);
+            if (app.isolated) {
+                mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);
+            }
         } catch (RuntimeException e) {
             // XXX do better error recovery.
             app.setPid(0);
@@ -4732,6 +4733,11 @@
                 mPidsSelfLocked.remove(pid);
                 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             }
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+                    app.processName, app.info.uid);
+            if (app.isolated) {
+                mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
+            }
             killUnneededProcessLocked(app, reason);
             handleAppDiedLocked(app, true, allowRestart);
             removeLruProcessLocked(app);
@@ -4772,6 +4778,11 @@
                         mHeavyWeightProcess.userId, 0));
                 mHeavyWeightProcess = null;
             }
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+                    app.processName, app.info.uid);
+            if (app.isolated) {
+                mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
+            }
             // Take care of any launching providers waiting for this process.
             checkAppInLaunchingProvidersLocked(app, true);
             // Take care of any services that are waiting for the process.
@@ -8726,7 +8737,7 @@
                 Context.WINDOW_SERVICE)).addView(v, lp);
     }
 
-    public void noteWakeupAlarm(IIntentSender sender) {
+    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg) {
         if (!(sender instanceof PendingIntentRecord)) {
             return;
         }
@@ -8738,7 +8749,8 @@
                 int MY_UID = Binder.getCallingUid();
                 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
                 BatteryStatsImpl.Uid.Pkg pkg =
-                    stats.getPackageStatsLocked(uid, rec.key.packageName);
+                    stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
+                            sourcePkg != null ? sourcePkg : rec.key.packageName);
                 pkg.incWakeupsLocked();
             }
         }
@@ -12453,10 +12465,16 @@
             startProcessLocked(app, "restart", app.processName);
         } else if (app.pid > 0 && app.pid != MY_PID) {
             // Goodbye!
+            boolean removed;
             synchronized (mPidsSelfLocked) {
                 mPidsSelfLocked.remove(app.pid);
                 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             }
+            mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+                    app.processName, app.info.uid);
+            if (app.isolated) {
+                mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
+            }
             app.setPid(0);
         }
     }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index d2dfb0d..eda08a9 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -105,6 +105,27 @@
         return data;
     }
     
+    public void addIsolatedUid(int isolatedUid, int appUid) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.addIsolatedUidLocked(isolatedUid, appUid);
+        }
+    }
+
+    public void removeIsolatedUid(int isolatedUid, int appUid) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.removeIsolatedUidLocked(isolatedUid, appUid);
+        }
+    }
+
+    public void noteEvent(int code, String name, int uid) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteEventLocked(code, name, uid);
+        }
+    }
+
     public void noteStartWakelock(int uid, int pid, String name, int type) {
         enforceCallingPermission();
         synchronized (mStats) {
@@ -496,8 +517,10 @@
     
     private void dumpHelp(PrintWriter pw) {
         pw.println("Battery stats (batterystats) dump options:");
-        pw.println("  [--checkin] [-c] [--unplugged] [--reset] [--write] [-h] [<package.name>]");
+        pw.println("  [--checkin] [--history] [-c] [--unplugged] [--reset] [--write]");
+        pw.println("  [-h] [<package.name>]");
         pw.println("  --checkin: format output for a checkin report.");
+        pw.println("  --history: show only history data.");
         pw.println("  --unplugged: only output data since last unplugged.");
         pw.println("  --reset: reset the stats, clearing all current data.");
         pw.println("  --write: force write current collected stats to disk.");
@@ -517,6 +540,7 @@
 
         boolean isCheckin = false;
         boolean includeHistory = false;
+        boolean historyOnly = false;
         boolean isUnpluggedOnly = false;
         boolean noOutput = false;
         int reqUid = -1;
@@ -524,6 +548,8 @@
             for (String arg : args) {
                 if ("--checkin".equals(arg)) {
                     isCheckin = true;
+                } else if ("--history".equals(arg)) {
+                    historyOnly = true;
                 } else if ("-c".equals(arg)) {
                     isCheckin = true;
                     includeHistory = true;
@@ -569,11 +595,12 @@
         if (isCheckin) {
             List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
             synchronized (mStats) {
-                mStats.dumpCheckinLocked(mContext, pw, apps, isUnpluggedOnly, includeHistory);
+                mStats.dumpCheckinLocked(mContext, pw, apps, isUnpluggedOnly, includeHistory,
+                        historyOnly);
             }
         } else {
             synchronized (mStats) {
-                mStats.dumpLocked(mContext, pw, isUnpluggedOnly, reqUid);
+                mStats.dumpLocked(mContext, pw, isUnpluggedOnly, reqUid, historyOnly);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 217a8d61..1f0fc3a0 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -59,6 +59,7 @@
                                 // 'persistent' is true (in which case we
                                 // are in the process of launching the app)
     ProcessStats.ProcessState baseProcessTracker;
+    BatteryStatsImpl.Uid.Proc curProcBatteryStats;
     int pid;                    // The process of this application; 0 if none
     boolean starting;           // True if the process is being started
     long lastActivityTime;      // For managing the LRU list