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/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 7b81713..b40008e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -101,9 +101,9 @@
         }
     }
 
-    static public void noteWakeupAlarm(PendingIntent ps) {
+    static public void noteWakeupAlarm(PendingIntent ps, int sourceUid, String sourcePkg) {
         try {
-            getDefault().noteWakeupAlarm(ps.getTarget());
+            getDefault().noteWakeupAlarm(ps.getTarget(), sourceUid, sourcePkg);
         } catch (RemoteException ex) {
         }
     }
@@ -1258,7 +1258,9 @@
             data.enforceInterface(IActivityManager.descriptor);
             IIntentSender is = IIntentSender.Stub.asInterface(
                     data.readStrongBinder());
-            noteWakeupAlarm(is);
+            int sourceUid = data.readInt();
+            String sourcePkg = data.readString();
+            noteWakeupAlarm(is, sourceUid, sourcePkg);
             reply.writeNoException();
             return true;
         }
@@ -3651,10 +3653,13 @@
         mRemote.transact(ENTER_SAFE_MODE_TRANSACTION, data, null, 0);
         data.recycle();
     }
-    public void noteWakeupAlarm(IIntentSender sender) throws RemoteException {
+    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
-        data.writeStrongBinder(sender.asBinder());
         data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(sender.asBinder());
+        data.writeInt(sourceUid);
+        data.writeString(sourcePkg);
         mRemote.transact(NOTE_WAKEUP_ALARM_TRANSACTION, data, null, 0);
         data.recycle();
     }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3ed3f7b..8c7fe10 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -243,7 +243,8 @@
 
     public void enterSafeMode() throws RemoteException;
     
-    public void noteWakeupAlarm(IIntentSender sender) throws RemoteException;
+    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg)
+            throws RemoteException;
 
     public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException;
     public boolean killProcessesBelowForeground(String reason) throws RemoteException;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 935ec9a..1ce958b 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -162,6 +162,7 @@
     private static final String WIFI_DATA = "wfl";
     private static final String MISC_DATA = "m";
     private static final String GLOBAL_NETWORK_DATA = "gn";
+    private static final String HISTORY_STRING_POOL = "hsp";
     private static final String HISTORY_DATA = "h";
     private static final String SCREEN_BRIGHTNESS_DATA = "br";
     private static final String SIGNAL_STRENGTH_TIME_DATA = "sgt";
@@ -355,6 +356,11 @@
             }
 
             /**
+             * Returns true if this process is still active in the battery stats.
+             */
+            public abstract boolean isActive();
+
+            /**
              * Returns the total time (in 1/100 sec) spent executing in user code.
              *
              * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
@@ -446,9 +452,6 @@
     }
 
     public final static class HistoryItem implements Parcelable {
-        static final String TAG = "HistoryItem";
-        static final boolean DEBUG = false;
-        
         public HistoryItem next;
         
         public long time;
@@ -526,12 +529,14 @@
         public int states;
 
         public static final int EVENT_NONE = 0;
-        public static final int EVENT_APP_FOREGROUND = 1;
+        public static final int EVENT_PROC_STARTED = 1;
+        public static final int EVENT_PROC_FINISHED = 2;
 
         // For CMD_EVENT.
         public int eventCode;
-        public int eventUid;
         public String eventName;
+        public int eventNameIdx;    // only filled in when iterating.
+        public int eventUid;
 
         public HistoryItem() {
         }
@@ -579,6 +584,7 @@
                 eventCode = src.readInt();
                 eventUid = src.readInt();
                 eventName = src.readString();
+                eventNameIdx = 0;
             } else {
                 eventCode = EVENT_NONE;
             }
@@ -612,6 +618,7 @@
             eventCode = o.eventCode;
             eventUid = o.eventUid;
             eventName = o.eventName;
+            eventNameIdx = o.eventNameIdx;
         }
 
         public void setTo(long time, byte cmd, int eventCode, int eventUid, String eventName,
@@ -621,6 +628,7 @@
             this.eventCode = eventCode;
             this.eventUid = eventUid;
             this.eventName = eventName;
+            this.eventNameIdx = 0;
             batteryLevel = o.batteryLevel;
             batteryStatus = o.batteryStatus;
             batteryHealth = o.batteryHealth;
@@ -681,6 +689,10 @@
     
     public abstract boolean startIteratingHistoryLocked();
 
+    public abstract int getHistoryStringPoolSize();
+
+    public abstract String getHistoryStringPoolItem(int index);
+
     public abstract boolean getNextHistoryLocked(HistoryItem out);
 
     public abstract void finishIteratingHistoryLocked();
@@ -1316,7 +1328,7 @@
         if (sippers != null && sippers.size() > 0) {
             dumpLine(pw, 0 /* uid */, category, POWER_USE_SUMMARY_DATA,
                     BatteryStatsHelper.makemAh(helper.getPowerProfile().getBatteryCapacity()),
-                    BatteryStatsHelper.makemAh(helper.getTotalPower()),
+                    BatteryStatsHelper.makemAh(helper.getComputedPower()),
                     BatteryStatsHelper.makemAh(helper.getMinDrainedPower()),
                     BatteryStatsHelper.makemAh(helper.getMaxDrainedPower()));
             for (int i=0; i<sippers.size(); i++) {
@@ -1835,7 +1847,7 @@
             pw.print(prefix); pw.println("  Estimated power use (mAh):");
             pw.print(prefix); pw.print("    Capacity: ");
                     printmAh(pw, helper.getPowerProfile().getBatteryCapacity());
-                    pw.print(", Computed drain: "); printmAh(pw, helper.getTotalPower());
+                    pw.print(", Computed drain: "); printmAh(pw, helper.getComputedPower());
                     pw.print(", Min drain: "); printmAh(pw, helper.getMinDrainedPower());
                     pw.print(", Max drain: "); printmAh(pw, helper.getMaxDrainedPower());
                     pw.println();
@@ -2244,10 +2256,14 @@
         if (diff == 0) return;
         for (int i=0; i<descriptions.length; i++) {
             BitDescription bd = descriptions[i];
-            if ((diff&bd.mask) != 0) {
+            int mask = bd.mask;
+            if (bd.shift > 0) {
+                mask <<= bd.shift;
+            }
+            if ((diff&mask) != 0) {
                 pw.print(longNames ? " " : ",");
                 if (bd.shift < 0) {
-                    pw.print((newval&bd.mask) != 0 ? "+" : "-");
+                    pw.print((newval&mask) != 0 ? "+" : "-");
                     pw.print(longNames ? bd.name : bd.shortName);
                 } else {
                     pw.print(longNames ? bd.name : bd.shortName);
@@ -2404,6 +2420,38 @@
                 }
                 printBitDescriptions(pw, oldState, rec.states,
                         HISTORY_STATE_DESCRIPTIONS, !checkin);
+                if (rec.eventCode != HistoryItem.EVENT_NONE) {
+                    switch (rec.eventCode) {
+                        case HistoryItem.EVENT_PROC_STARTED:
+                            pw.print(checkin ? ",PrSt=" : " procstart=");
+                            break;
+                        case HistoryItem.EVENT_PROC_FINISHED:
+                            pw.print(checkin ? ",PrFn=" : " procfin=");
+                            break;
+                        default:
+                            if (checkin) {
+                                pw.print(",?cmd_");
+                                pw.print(rec.eventCode);
+                                pw.print("=");
+                            } else {
+                                pw.print(" cmd_");
+                                pw.print(rec.eventCode);
+                                pw.print("=");
+                            }
+                            break;
+                    }
+                    if (checkin) {
+                        pw.print(rec.eventUid);
+                    } else {
+                        UserHandle.formatUid(pw, rec.eventUid);
+                    }
+                    pw.print(":");
+                    if (checkin) {
+                        pw.print(rec.eventNameIdx);
+                    } else {
+                        pw.print(rec.eventName);
+                    }
+                }
                 pw.println();
             }
             oldState = rec.states;
@@ -2416,7 +2464,8 @@
      * @param pw a Printer to receive the dump output.
      */
     @SuppressWarnings("unused")
-    public void dumpLocked(Context context, PrintWriter pw, boolean isUnpluggedOnly, int reqUid) {
+    public void dumpLocked(Context context, PrintWriter pw, boolean isUnpluggedOnly, int reqUid,
+            boolean historyOnly) {
         prepareForDumpLocked();
 
         long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
@@ -2441,7 +2490,11 @@
             finishIteratingOldHistoryLocked();
             pw.println("");
         }
-        
+
+        if (historyOnly) {
+            return;
+        }
+
         SparseArray<? extends Uid> uidStats = getUidStats();
         final int NU = uidStats.size();
         boolean didPid = false;
@@ -2483,14 +2536,22 @@
     @SuppressWarnings("unused")
     public void dumpCheckinLocked(Context context,
             PrintWriter pw, List<ApplicationInfo> apps, boolean isUnpluggedOnly,
-            boolean includeHistory) {
+            boolean includeHistory, boolean historyOnly) {
         prepareForDumpLocked();
         
         long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
 
-        if (includeHistory) {
+        if (includeHistory || historyOnly) {
             final HistoryItem rec = new HistoryItem();
             if (startIteratingHistoryLocked()) {
+                for (int i=0; i<getHistoryStringPoolSize(); i++) {
+                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                    pw.print(HISTORY_STRING_POOL); pw.print(',');
+                    pw.print(i);
+                    pw.print(',');
+                    pw.print(getHistoryStringPoolItem(i));
+                    pw.println();
+                }
                 HistoryPrinter hprinter = new HistoryPrinter();
                 while (getNextHistoryLocked(rec)) {
                     pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
@@ -2501,6 +2562,10 @@
             }
         }
 
+        if (historyOnly) {
+            return;
+        }
+
         if (apps != null) {
             SparseArray<ArrayList<String>> uids = new SparseArray<ArrayList<String>>();
             for (int i=0; i<apps.size(); i++) {
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 0771329..1946d86 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -29,6 +29,12 @@
 
     // Remaining methods are only used in Java.
     byte[] getStatistics();
+
+    void addIsolatedUid(int isolatedUid, int appUid);
+    void removeIsolatedUid(int isolatedUid, int appUid);
+
+    void noteEvent(int code, String name, int uid);
+
     void noteStartWakelock(int uid, int pid, String name, int type);
     void noteStopWakelock(int uid, int pid, String name, int type);
 
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 0131f68..e7e8006f 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -41,7 +41,6 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BatterySipper.DrainType;
 
-import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -84,6 +83,7 @@
 
     private long mStatsPeriod = 0;
     private double mMaxPower = 1;
+    private double mComputedPower;
     private double mTotalPower;
     private double mWifiPower;
     private double mBluetoothPower;
@@ -156,6 +156,7 @@
         getStats();
 
         mMaxPower = 0;
+        mComputedPower = 0;
         mTotalPower = 0;
         mWifiPower = 0;
         mBluetoothPower = 0;
@@ -195,21 +196,17 @@
         processMiscUsage();
 
         if (DEBUG) {
-            Log.d(TAG, "Accuracy: total computed=" + makemAh(mTotalPower) + ", min discharge="
+            Log.d(TAG, "Accuracy: total computed=" + makemAh(mComputedPower) + ", min discharge="
                     + makemAh(mMinDrainedPower) + ", max discharge=" + makemAh(mMaxDrainedPower));
         }
-        if (true || mStats.getLowDischargeAmountSinceCharge() > 10) {
-            if (mMinDrainedPower > mTotalPower) {
-                double amount = mMinDrainedPower - mTotalPower;
-                if (mMaxPower < amount) {
-                    mMaxPower = amount;
-                }
+        mTotalPower = mComputedPower;
+        if (mStats.getLowDischargeAmountSinceCharge() > 1) {
+            if (mMinDrainedPower > mComputedPower) {
+                double amount = mMinDrainedPower - mComputedPower;
+                mTotalPower = mMinDrainedPower;
                 addEntryNoTotal(BatterySipper.DrainType.UNACCOUNTED, 0, amount);
-            } else if (mMaxDrainedPower < mTotalPower) {
-                double amount = mTotalPower - mMaxDrainedPower;
-                if (mMaxPower < amount) {
-                    mMaxPower = amount;
-                }
+            } else if (mMaxDrainedPower < mComputedPower) {
+                double amount = mComputedPower - mMaxDrainedPower;
                 addEntryNoTotal(BatterySipper.DrainType.OVERCOUNTED, 0, amount);
             }
         }
@@ -442,7 +439,7 @@
                 } else {
                     mUsageList.add(app);
                     if (power > mMaxPower) mMaxPower = power;
-                    mTotalPower += power;
+                    mComputedPower += power;
                 }
                 if (u.getUid() == 0) {
                     osApp = app;
@@ -467,7 +464,7 @@
                 osApp.value += power;
                 osApp.values[0] += power;
                 if (osApp.value > mMaxPower) mMaxPower = osApp.value;
-                mTotalPower += power;
+                mComputedPower += power;
             }
         }
     }
@@ -476,7 +473,9 @@
         long phoneOnTimeMs = mStats.getPhoneOnTime(mBatteryRealtime, mStatsType) / 1000;
         double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
                 * phoneOnTimeMs / (60*60*1000);
-        addEntry(BatterySipper.DrainType.PHONE, phoneOnTimeMs, phoneOnPower);
+        if (phoneOnPower != 0) {
+            addEntry(BatterySipper.DrainType.PHONE, phoneOnTimeMs, phoneOnPower);
+        }
     }
 
     private void addScreenUsage() {
@@ -493,12 +492,14 @@
             double p = screenBinPower*brightnessTime;
             if (DEBUG && p != 0) {
                 Log.d(TAG, "Screen bin #" + i + ": time=" + brightnessTime
-                        + " power=" + makemAh(p/(60*60*1000)));
+                        + " power=" + makemAh(p / (60 * 60 * 1000)));
             }
             power += p;
         }
         power /= (60*60*1000); // To hours
-        addEntry(BatterySipper.DrainType.SCREEN, screenOnTimeMs, power);
+        if (power != 0) {
+            addEntry(BatterySipper.DrainType.SCREEN, screenOnTimeMs, power);
+        }
     }
 
     private void addRadioUsage() {
@@ -530,10 +531,12 @@
             Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + makemAh(p));
         }
         power += p;
-        BatterySipper bs =
-                addEntry(BatterySipper.DrainType.CELL, signalTimeMs, power);
-        if (signalTimeMs != 0) {
-            bs.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs;
+        if (power != 0) {
+            BatterySipper bs =
+                    addEntry(BatterySipper.DrainType.CELL, signalTimeMs, power);
+            if (signalTimeMs != 0) {
+                bs.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs;
+            }
         }
     }
 
@@ -571,9 +574,11 @@
         if (DEBUG && wifiPower != 0) {
             Log.d(TAG, "Wifi: time=" + runningTimeMs + " power=" + makemAh(wifiPower));
         }
-        BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, runningTimeMs,
-                wifiPower + mWifiPower);
-        aggregateSippers(bs, mWifiSippers, "WIFI");
+        if ((wifiPower+mWifiPower) != 0) {
+            BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, runningTimeMs,
+                    wifiPower + mWifiPower);
+            aggregateSippers(bs, mWifiSippers, "WIFI");
+        }
     }
 
     private void addIdleUsage() {
@@ -584,7 +589,9 @@
         if (DEBUG && idlePower != 0) {
             Log.d(TAG, "Idle: time=" + idleTimeMs + " power=" + makemAh(idlePower));
         }
-        addEntry(BatterySipper.DrainType.IDLE, idleTimeMs, idlePower);
+        if (idlePower != 0) {
+            addEntry(BatterySipper.DrainType.IDLE, idleTimeMs, idlePower);
+        }
     }
 
     private void addBluetoothUsage() {
@@ -602,9 +609,11 @@
             Log.d(TAG, "Bluetooth ping: count=" + btPingCount + " power=" + makemAh(pingPower));
         }
         btPower += pingPower;
-        BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, btOnTimeMs,
-                btPower + mBluetoothPower);
-        aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
+        if ((btPower+mBluetoothPower) != 0) {
+            BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, btOnTimeMs,
+                    btPower + mBluetoothPower);
+            aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
+        }
     }
 
     private void addUserUsage() {
@@ -665,7 +674,7 @@
     }
 
     private BatterySipper addEntry(DrainType drainType, long time, double power) {
-        mTotalPower += power;
+        mComputedPower += power;
         return addEntryNoTotal(drainType, time, power);
     }
 
@@ -689,6 +698,8 @@
 
     public double getTotalPower() { return mTotalPower; }
 
+    public double getComputedPower() { return mComputedPower; }
+
     public double getMinDrainedPower() {
         return mMinDrainedPower;
     }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f692948..70ba4e3 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -45,6 +45,7 @@
 import android.util.Printer;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
@@ -86,7 +87,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 69 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 70 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -142,6 +143,11 @@
     private BatteryCallback mCallback;
 
     /**
+     * Mapping isolated uids to the actual owning app uid.
+     */
+    final SparseIntArray mIsolatedUids = new SparseIntArray();
+
+    /**
      * The statistics we have collected organized by uids.
      */
     final SparseArray<BatteryStatsImpl.Uid> mUidStats =
@@ -183,6 +189,9 @@
     final HistoryItem mHistoryLastWritten = new HistoryItem();
     final HistoryItem mHistoryLastLastWritten = new HistoryItem();
     final HistoryItem mHistoryReadTmp = new HistoryItem();
+    final HashMap<String, Integer> mHistoryStringPool = new HashMap<String, Integer>();
+    String[] mReadHistoryStrings;
+    int mNextHistoryStringIdx = 0;
     int mHistoryBufferLastPos = -1;
     boolean mHistoryOverflow = false;
     long mLastHistoryTime = 0;
@@ -343,8 +352,6 @@
     private final Map<String, KernelWakelockStats> mProcWakelockFileStats =
             new HashMap<String, KernelWakelockStats>();
 
-    private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>();
-
     private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
     private NetworkStats mLastSnapshot;
 
@@ -1554,9 +1561,19 @@
                     + " states=0x" + Integer.toHexString(cur.states));
         }
         if (cur.cmd == HistoryItem.CMD_EVENT) {
-            dest.writeInt(cur.eventCode);
+            Integer idxObj = mHistoryStringPool.get(cur.eventName);
+            int codeAndIndex = (cur.eventCode&0xffff);
+            int idx;
+            if (idxObj != null) {
+                idx = idxObj;
+            } else {
+                idx = mNextHistoryStringIdx;
+                mHistoryStringPool.put(cur.eventName, mNextHistoryStringIdx);
+                mNextHistoryStringIdx++;
+            }
+            codeAndIndex |= (idx<<16);
+            dest.writeInt(codeAndIndex);
             dest.writeInt(cur.eventUid);
-            dest.writeString(cur.eventName);
         }
     }
 
@@ -1625,9 +1642,12 @@
         }
 
         if (cur.cmd == HistoryItem.CMD_EVENT) {
-            cur.eventCode = src.readInt();
+            int codeAndIndex = src.readInt();
+            cur.eventCode = (codeAndIndex&0xffff);
+            int index = ((codeAndIndex>>16)&0xffff);
+            cur.eventName = mReadHistoryStrings[index];
+            cur.eventNameIdx = index;
             cur.eventUid = src.readInt();
-            cur.eventName = src.readString();
         } else {
             cur.eventCode = HistoryItem.EVENT_NONE;
         }
@@ -1688,15 +1708,15 @@
     }
 
     void addHistoryBufferLocked(long curTime, byte cmd) {
-        addHistoryBufferLocked(curTime, cmd, HistoryItem.EVENT_NONE, 0, null);
+        addHistoryBufferLocked(curTime, cmd, HistoryItem.EVENT_NONE, null, 0);
     }
 
-    void addHistoryBufferEventLocked(long curTime, int eventCode, int eventUid, String eventName) {
-        addHistoryBufferLocked(curTime, HistoryItem.CMD_EVENT, eventCode, eventUid, eventName);
+    void addHistoryBufferEventLocked(long curTime, int eventCode, String eventName, int eventUid) {
+        addHistoryBufferLocked(curTime, HistoryItem.CMD_EVENT, eventCode, eventName, eventUid);
     }
 
     private void addHistoryBufferLocked(long curTime, byte cmd,
-            int eventCode, int eventUid, String eventName) {
+            int eventCode, String eventName, int eventUid) {
         int origPos = 0;
         if (mIteratingHistory) {
             origPos = mHistoryBuffer.dataPosition();
@@ -1778,6 +1798,10 @@
         addHistoryRecordLocked(curTime, HistoryItem.CMD_UPDATE);
     }
 
+    void addHistoryEventLocked(long curTime, int code, String name, int uid) {
+        addHistoryBufferEventLocked(curTime, code, name, uid);
+    }
+
     void addHistoryRecordLocked(long curTime, byte cmd) {
         HistoryItem rec = mHistoryCache;
         if (rec != null) {
@@ -1822,6 +1846,8 @@
         mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER/2);
         mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
         mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+        mHistoryStringPool.clear();
+        mNextHistoryStringIdx = 0;
         mHistoryBufferLastPos = -1;
         mHistoryOverflow = false;
     }
@@ -1856,7 +1882,29 @@
 
     int mWakeLockNesting;
 
+    public void addIsolatedUidLocked(int isolatedUid, int appUid) {
+        mIsolatedUids.put(isolatedUid, appUid);
+    }
+
+    public void removeIsolatedUidLocked(int isolatedUid, int appUid) {
+        int curUid = mIsolatedUids.get(isolatedUid, -1);
+        if (curUid == appUid) {
+            mIsolatedUids.delete(isolatedUid);
+        }
+    }
+
+    public int mapUid(int uid) {
+        int isolated = mIsolatedUids.get(uid, -1);
+        return isolated > 0 ? isolated : uid;
+    }
+
+    public void noteEventLocked(int code, String name, int uid) {
+        uid = mapUid(uid);
+        addHistoryEventLocked(SystemClock.elapsedRealtime(), code, name, uid);
+    }
+
     public void noteStartWakeLocked(int uid, int pid, String name, int type) {
+        uid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             // Only care about partial wake locks, since full wake locks
             // will be canceled when the user puts the screen to sleep.
@@ -1878,6 +1926,7 @@
     }
 
     public void noteStopWakeLocked(int uid, int pid, String name, int type) {
+        uid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             mWakeLockNesting--;
             if (mWakeLockNesting == 0) {
@@ -2009,6 +2058,7 @@
     }
 
     public void noteProcessDiedLocked(int uid, int pid) {
+        uid = mapUid(uid);
         Uid u = mUidStats.get(uid);
         if (u != null) {
             u.mPids.remove(pid);
@@ -2016,6 +2066,7 @@
     }
 
     public long getProcessWakeTime(int uid, int pid, long realtime) {
+        uid = mapUid(uid);
         Uid u = mUidStats.get(uid);
         if (u != null) {
             Uid.Pid p = u.mPids.get(pid);
@@ -2027,6 +2078,7 @@
     }
 
     public void reportExcessiveWakeLocked(int uid, String proc, long overTime, long usedTime) {
+        uid = mapUid(uid);
         Uid u = mUidStats.get(uid);
         if (u != null) {
             u.reportExcessiveWakeLocked(proc, overTime, usedTime);
@@ -2034,6 +2086,7 @@
     }
 
     public void reportExcessiveCpuLocked(int uid, String proc, long overTime, long usedTime) {
+        uid = mapUid(uid);
         Uid u = mUidStats.get(uid);
         if (u != null) {
             u.reportExcessiveCpuLocked(proc, overTime, usedTime);
@@ -2043,6 +2096,7 @@
     int mSensorNesting;
 
     public void noteStartSensorLocked(int uid, int sensor) {
+        uid = mapUid(uid);
         if (mSensorNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
@@ -2054,6 +2108,7 @@
     }
 
     public void noteStopSensorLocked(int uid, int sensor) {
+        uid = mapUid(uid);
         mSensorNesting--;
         if (mSensorNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
@@ -2067,6 +2122,7 @@
     int mGpsNesting;
 
     public void noteStartGpsLocked(int uid) {
+        uid = mapUid(uid);
         if (mGpsNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
@@ -2078,6 +2134,7 @@
     }
 
     public void noteStopGpsLocked(int uid) {
+        uid = mapUid(uid);
         mGpsNesting--;
         if (mGpsNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
@@ -2158,6 +2215,7 @@
     }
 
     public void noteUserActivityLocked(int uid, int event) {
+        uid = mapUid(uid);
         getUidStatsLocked(uid).noteUserActivityLocked(event);
     }
 
@@ -2400,6 +2458,7 @@
     }
 
     public void noteAudioOnLocked(int uid) {
+        uid = mapUid(uid);
         if (!mAudioOn) {
             mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
@@ -2412,6 +2471,7 @@
     }
 
     public void noteAudioOffLocked(int uid) {
+        uid = mapUid(uid);
         if (mAudioOn) {
             mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
@@ -2424,6 +2484,7 @@
     }
 
     public void noteVideoOnLocked(int uid) {
+        uid = mapUid(uid);
         if (!mVideoOn) {
             mHistoryCur.states |= HistoryItem.STATE_VIDEO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
@@ -2436,6 +2497,7 @@
     }
 
     public void noteVideoOffLocked(int uid) {
+        uid = mapUid(uid);
         if (mVideoOn) {
             mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
@@ -2448,18 +2510,22 @@
     }
 
     public void noteActivityResumedLocked(int uid) {
+        uid = mapUid(uid);
         getUidStatsLocked(uid).noteActivityResumedLocked();
     }
 
     public void noteActivityPausedLocked(int uid) {
+        uid = mapUid(uid);
         getUidStatsLocked(uid).noteActivityPausedLocked();
     }
 
     public void noteVibratorOnLocked(int uid, long durationMillis) {
+        uid = mapUid(uid);
         getUidStatsLocked(uid).noteVibratorOnLocked(durationMillis);
     }
 
     public void noteVibratorOffLocked(int uid) {
+        uid = mapUid(uid);
         getUidStatsLocked(uid).noteVibratorOffLocked();
     }
 
@@ -2473,7 +2539,8 @@
             mGlobalWifiRunningTimer.startRunningLocked(this);
             int N = ws.size();
             for (int i=0; i<N; i++) {
-                getUidStatsLocked(ws.get(i)).noteWifiRunningLocked();
+                int uid = mapUid(ws.get(i));
+                getUidStatsLocked(uid).noteWifiRunningLocked();
             }
         } else {
             Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
@@ -2484,11 +2551,13 @@
         if (mGlobalWifiRunning) {
             int N = oldWs.size();
             for (int i=0; i<N; i++) {
-                getUidStatsLocked(oldWs.get(i)).noteWifiStoppedLocked();
+                int uid = mapUid(oldWs.get(i));
+                getUidStatsLocked(uid).noteWifiStoppedLocked();
             }
             N = newWs.size();
             for (int i=0; i<N; i++) {
-                getUidStatsLocked(newWs.get(i)).noteWifiRunningLocked();
+                int uid = mapUid(newWs.get(i));
+                getUidStatsLocked(uid).noteWifiRunningLocked();
             }
         } else {
             Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
@@ -2505,7 +2574,8 @@
             mGlobalWifiRunningTimer.stopRunningLocked(this);
             int N = ws.size();
             for (int i=0; i<N; i++) {
-                getUidStatsLocked(ws.get(i)).noteWifiStoppedLocked();
+                int uid = mapUid(ws.get(i));
+                getUidStatsLocked(uid).noteWifiStoppedLocked();
             }
         } else {
             Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
@@ -2537,6 +2607,7 @@
     int mWifiFullLockNesting = 0;
 
     public void noteFullWifiLockAcquiredLocked(int uid) {
+        uid = mapUid(uid);
         if (mWifiFullLockNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
@@ -2548,6 +2619,7 @@
     }
 
     public void noteFullWifiLockReleasedLocked(int uid) {
+        uid = mapUid(uid);
         mWifiFullLockNesting--;
         if (mWifiFullLockNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
@@ -2561,6 +2633,7 @@
     int mWifiScanNesting = 0;
 
     public void noteWifiScanStartedLocked(int uid) {
+        uid = mapUid(uid);
         if (mWifiScanNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
@@ -2572,6 +2645,7 @@
     }
 
     public void noteWifiScanStoppedLocked(int uid) {
+        uid = mapUid(uid);
         mWifiScanNesting--;
         if (mWifiScanNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
@@ -2583,16 +2657,19 @@
     }
 
     public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
+        uid = mapUid(uid);
         getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph);
     }
 
     public void noteWifiBatchedScanStoppedLocked(int uid) {
+        uid = mapUid(uid);
         getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked();
     }
 
     int mWifiMulticastNesting = 0;
 
     public void noteWifiMulticastEnabledLocked(int uid) {
+        uid = mapUid(uid);
         if (mWifiMulticastNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
@@ -2604,6 +2681,7 @@
     }
 
     public void noteWifiMulticastDisabledLocked(int uid) {
+        uid = mapUid(uid);
         mWifiMulticastNesting--;
         if (mWifiMulticastNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
@@ -3781,6 +3859,11 @@
          */
         public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
             /**
+             * Remains true until removed from the stats.
+             */
+            boolean mActive = true;
+
+            /**
              * Total time (in 1/100 sec) spent executing in user code.
              */
             long mUserTime;
@@ -3880,6 +3963,7 @@
             }
 
             void detach() {
+                mActive = false;
                 mUnpluggables.remove(this);
                 for (int i = 0; i < mSpeedBins.length; i++) {
                     SamplingCounter c = mSpeedBins[i];
@@ -4038,6 +4122,11 @@
             }
 
             @Override
+            public boolean isActive() {
+                return mActive;
+            }
+
+            @Override
             public long getUserTime(int which) {
                 long val;
                 if (which == STATS_LAST) {
@@ -4812,10 +4901,24 @@
         mHistoryBuffer.setDataPosition(0);
         mReadOverflow = false;
         mIteratingHistory = true;
+        mReadHistoryStrings = new String[mHistoryStringPool.size()];
+        for (HashMap.Entry<String, Integer> ent : mHistoryStringPool.entrySet()) {
+            mReadHistoryStrings[ent.getValue()] = ent.getKey();
+        }
         return mHistoryBuffer.dataSize() > 0;
     }
 
     @Override
+    public int getHistoryStringPoolSize() {
+        return mReadHistoryStrings.length;
+    }
+
+    @Override
+    public String getHistoryStringPoolItem(int index) {
+        return mReadHistoryStrings[index];
+    }
+
+    @Override
     public boolean getNextHistoryLocked(HistoryItem out) {
         final int pos = mHistoryBuffer.dataPosition();
         if (pos == 0) {
@@ -4834,6 +4937,7 @@
     public void finishIteratingHistoryLocked() {
         mIteratingHistory = false;
         mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
+        mReadHistoryStrings = null;
     }
 
     @Override
@@ -5396,24 +5500,6 @@
     }
 
     /**
-     * Retrieve the statistics object for a particular process, given
-     * the name of the process.
-     * @param name process name
-     * @return the statistics object for the process
-     */
-    public Uid.Proc getProcessStatsLocked(String name, int pid) {
-        int uid;
-        if (mUidCache.containsKey(name)) {
-            uid = mUidCache.get(name);
-        } else {
-            uid = Process.getUidForPid(pid);
-            mUidCache.put(name, uid);
-        }
-        Uid u = getUidStatsLocked(uid);
-        return u.getProcessStatsLocked(name);
-    }
-
-    /**
      * Retrieve the statistics object for a particular process, creating
      * if needed.
      */
@@ -5624,6 +5710,18 @@
 
         mHistoryBuffer.setDataSize(0);
         mHistoryBuffer.setDataPosition(0);
+        mHistoryStringPool.clear();
+        mNextHistoryStringIdx = 0;
+
+        int numStrings = in.readInt();
+        for (int i=0; i<numStrings; i++) {
+            String str = in.readString();
+            int idx = in.readInt();
+            mHistoryStringPool.put(str, idx);
+            if (idx >= mNextHistoryStringIdx) {
+                mNextHistoryStringIdx = idx+1;
+            }
+        }
 
         int bufSize = in.readInt();
         int curPos = in.dataPosition();
@@ -5692,6 +5790,11 @@
             Slog.i(TAG, sb.toString());
         }
         out.writeLong(mHistoryBaseTime + mLastHistoryTime);
+        out.writeInt(mHistoryStringPool.size());
+        for (HashMap.Entry<String, Integer> ent : mHistoryStringPool.entrySet()) {
+            out.writeString(ent.getKey());
+            out.writeInt(ent.getValue());
+        }
         out.writeInt(mHistoryBuffer.dataSize());
         if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
                 + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
@@ -6399,7 +6502,8 @@
         pullPendingStateUpdatesLocked();
     }
 
-    public void dumpLocked(Context context, PrintWriter pw, boolean isUnpluggedOnly, int reqUid) {
+    public void dumpLocked(Context context, PrintWriter pw, boolean isUnpluggedOnly, int reqUid,
+            boolean historyOnly) {
         if (DEBUG) {
             Printer pr = new PrintWriterPrinter(pw);
             pr.println("*** Screen timer:");
@@ -6429,6 +6533,6 @@
             pr.println("*** Bluetooth timer:");
             mBluetoothOnTimer.logState(pr, "  ");
         }
-        super.dumpLocked(context, pw, isUnpluggedOnly, reqUid);
+        super.dumpLocked(context, pw, isUnpluggedOnly, reqUid, historyOnly);
     }
 }