Implement issue #3326435: Battery stats improvements

Keep track of discharge while screen is on vs. off.

Checkin looks like:

5,0,u,dc,1,1,1,0

The last four numbers are, from left:

- Maximum battery drain over time period.
- Minimum battery drain over time period.
- Battery drain while screen was on.
- Battery drain while screen was off.

Change-Id: Ie4026a7cc8aabb2a6d47d03d2e278aa51c2d5ddf
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 7dd5e31..6e6731e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -132,6 +132,7 @@
     private static final String NETWORK_DATA = "nt";
     private static final String USER_ACTIVITY_DATA = "ua";
     private static final String BATTERY_DATA = "bt";
+    private static final String BATTERY_DISCHARGE_DATA = "dc";
     private static final String BATTERY_LEVEL_DATA = "lv";
     private static final String WIFI_LOCK_DATA = "wfl";
     private static final String MISC_DATA = "m";
@@ -804,6 +805,30 @@
     public abstract int getHighDischargeAmountSinceCharge();
 
     /**
+     * Get the amount the battery has discharged while the screen was on,
+     * since the last time power was unplugged.
+     */
+    public abstract int getDischargeAmountScreenOn();
+
+    /**
+     * Get the amount the battery has discharged while the screen was on,
+     * since the last time the device was charged.
+     */
+    public abstract int getDischargeAmountScreenOnSinceCharge();
+
+    /**
+     * Get the amount the battery has discharged while the screen was off,
+     * since the last time power was unplugged.
+     */
+    public abstract int getDischargeAmountScreenOff();
+
+    /**
+     * Get the amount the battery has discharged while the screen was off,
+     * since the last time the device was charged.
+     */
+    public abstract int getDischargeAmountScreenOffSinceCharge();
+
+    /**
      * Returns the total, last, or current battery uptime in microseconds.
      *
      * @param curTime the elapsed realtime in microseconds.
@@ -1098,6 +1123,17 @@
                     getDischargeCurrentLevel());
         }
         
+        if (which == STATS_SINCE_UNPLUGGED) {
+            dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
+                    getDischargeStartLevel()-getDischargeCurrentLevel(),
+                    getDischargeStartLevel()-getDischargeCurrentLevel(),
+                    getDischargeAmountScreenOn(), getDischargeAmountScreenOff());
+        } else {
+            dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
+                    getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
+                    getDischargeAmountScreenOn(), getDischargeAmountScreenOff());
+        }
+        
         if (reqUid < 0) {
             Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
             if (kernelWakelocks.size() > 0) {
@@ -1454,6 +1490,10 @@
                 pw.print(prefix); pw.print("    Last discharge cycle end level: "); 
                         pw.println(getDischargeCurrentLevel());
             }
+            pw.print(prefix); pw.print("    Amount discharged while screen on: ");
+                    pw.println(getDischargeAmountScreenOn());
+            pw.print(prefix); pw.print("    Amount discharged while screen off: ");
+                    pw.println(getDischargeAmountScreenOff());
             pw.println(" ");
         } else {
             pw.print(prefix); pw.println("  Device battery use since last full charge");
@@ -1461,6 +1501,10 @@
                     pw.println(getLowDischargeAmountSinceCharge());
             pw.print(prefix); pw.print("    Amount discharged (upper bound): ");
                     pw.println(getHighDischargeAmountSinceCharge());
+            pw.print(prefix); pw.print("    Amount discharged while screen on: ");
+                    pw.println(getDischargeAmountScreenOnSinceCharge());
+            pw.print(prefix); pw.print("    Amount discharged while screen off: ");
+                    pw.println(getDischargeAmountScreenOffSinceCharge());
             pw.println(" ");
         }
         
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 284df1e..b682947 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -70,7 +70,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 52;
+    private static final int VERSION = 54;
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -237,6 +237,12 @@
     int mDischargeCurrentLevel;
     int mLowDischargeAmountSinceCharge;
     int mHighDischargeAmountSinceCharge;
+    int mDischargeScreenOnUnplugLevel;
+    int mDischargeScreenOffUnplugLevel;
+    int mDischargeAmountScreenOn;
+    int mDischargeAmountScreenOnSinceCharge;
+    int mDischargeAmountScreenOff;
+    int mDischargeAmountScreenOffSinceCharge;
 
     long mLastWriteTime = 0; // Milliseconds
 
@@ -1572,6 +1578,11 @@
             // Fake a wake lock, so we consider the device waked as long
             // as the screen is on.
             noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
+            
+            // Update discharge amounts.
+            if (mOnBatteryInternal) {
+                updateDischargeScreenLevels(false, true);
+            }
         }
     }
 
@@ -1588,6 +1599,11 @@
             }
 
             noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
+            
+            // Update discharge amounts.
+            if (mOnBatteryInternal) {
+                updateDischargeScreenLevels(true, false);
+            }
         }
     }
 
@@ -3910,8 +3926,7 @@
         mDischargeStartLevel = 0;
         mDischargeUnplugLevel = 0;
         mDischargeCurrentLevel = 0;
-        mLowDischargeAmountSinceCharge = 0;
-        mHighDischargeAmountSinceCharge = 0;
+        initDischarge();
     }
 
     public BatteryStatsImpl(Parcel p) {
@@ -3982,6 +3997,15 @@
         mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
     }
 
+    void initDischarge() {
+        mLowDischargeAmountSinceCharge = 0;
+        mHighDischargeAmountSinceCharge = 0;
+        mDischargeAmountScreenOn = 0;
+        mDischargeAmountScreenOnSinceCharge = 0;
+        mDischargeAmountScreenOff = 0;
+        mDischargeAmountScreenOffSinceCharge = 0;
+    }
+    
     public void resetAllStatsLocked() {
         mStartCount = 0;
         initTimes();
@@ -4018,12 +4042,34 @@
             mKernelWakelockStats.clear();
         }
         
-        mLowDischargeAmountSinceCharge = 0;
-        mHighDischargeAmountSinceCharge = 0;
+        initDischarge();
 
         clearHistoryLocked();
     }
 
+    void updateDischargeScreenLevels(boolean oldScreenOn, boolean newScreenOn) {
+        if (oldScreenOn) {
+            int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
+            if (diff > 0) {
+                mDischargeAmountScreenOn += diff;
+                mDischargeAmountScreenOnSinceCharge += diff;
+            }
+        } else {
+            int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
+            if (diff > 0) {
+                mDischargeAmountScreenOff += diff;
+                mDischargeAmountScreenOffSinceCharge += diff;
+            }
+        }
+        if (newScreenOn) {
+            mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
+            mDischargeScreenOffUnplugLevel = 0;
+        } else {
+            mDischargeScreenOnUnplugLevel = 0;
+            mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
+        }
+    }
+    
     void setOnBattery(boolean onBattery, int oldStatus, int level) {
         synchronized(this) {
             boolean doWrite = false;
@@ -4058,6 +4104,15 @@
                 mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
                 mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
                 mDischargeCurrentLevel = mDischargeUnplugLevel = level;
+                if (mScreenOn) {
+                    mDischargeScreenOnUnplugLevel = level;
+                    mDischargeScreenOffUnplugLevel = 0;
+                } else {
+                    mDischargeScreenOnUnplugLevel = 0;
+                    mDischargeScreenOffUnplugLevel = level;
+                }
+                mDischargeAmountScreenOn = 0;
+                mDischargeAmountScreenOff = 0;
                 doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
             } else {
                 updateKernelWakelocksLocked();
@@ -4073,6 +4128,7 @@
                     mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
                     mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
                 }
+                updateDischargeScreenLevels(mScreenOn, mScreenOn);
                 doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
             }
             if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
@@ -4361,6 +4417,50 @@
             return val;
         }
     }
+    
+    public int getDischargeAmountScreenOn() {
+        synchronized(this) {
+            int val = mDischargeAmountScreenOn;
+            if (mOnBattery && mScreenOn
+                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
+                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
+            }
+            return val;
+        }
+    }
+
+    public int getDischargeAmountScreenOnSinceCharge() {
+        synchronized(this) {
+            int val = mDischargeAmountScreenOnSinceCharge;
+            if (mOnBattery && mScreenOn
+                    && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
+                val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
+            }
+            return val;
+        }
+    }
+
+    public int getDischargeAmountScreenOff() {
+        synchronized(this) {
+            int val = mDischargeAmountScreenOff;
+            if (mOnBattery && !mScreenOn
+                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
+                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
+            }
+            return val;
+        }
+    }
+
+    public int getDischargeAmountScreenOffSinceCharge() {
+        synchronized(this) {
+            int val = mDischargeAmountScreenOffSinceCharge;
+            if (mOnBattery && !mScreenOn
+                    && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
+                val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
+            }
+            return val;
+        }
+    }
 
     @Override
     public int getCpuSpeedSteps() {
@@ -4667,6 +4767,8 @@
         mDischargeCurrentLevel = in.readInt();
         mLowDischargeAmountSinceCharge = in.readInt();
         mHighDischargeAmountSinceCharge = in.readInt();
+        mDischargeAmountScreenOnSinceCharge = in.readInt();
+        mDischargeAmountScreenOffSinceCharge = in.readInt();
 
         mStartCount++;
 
@@ -4862,6 +4964,8 @@
         out.writeInt(mDischargeCurrentLevel);
         out.writeInt(getLowDischargeAmountSinceCharge());
         out.writeInt(getHighDischargeAmountSinceCharge());
+        out.writeInt(getDischargeAmountScreenOnSinceCharge());
+        out.writeInt(getDischargeAmountScreenOffSinceCharge());
         
         mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -5101,6 +5205,10 @@
         mDischargeCurrentLevel = in.readInt();
         mLowDischargeAmountSinceCharge = in.readInt();
         mHighDischargeAmountSinceCharge = in.readInt();
+        mDischargeAmountScreenOn = in.readInt();
+        mDischargeAmountScreenOnSinceCharge = in.readInt();
+        mDischargeAmountScreenOff = in.readInt();
+        mDischargeAmountScreenOffSinceCharge = in.readInt();
         mLastWriteTime = in.readLong();
 
         mMobileDataRx[STATS_LAST] = in.readLong();
@@ -5202,6 +5310,10 @@
         out.writeInt(mDischargeCurrentLevel);
         out.writeInt(mLowDischargeAmountSinceCharge);
         out.writeInt(mHighDischargeAmountSinceCharge);
+        out.writeInt(mDischargeAmountScreenOn);
+        out.writeInt(mDischargeAmountScreenOnSinceCharge);
+        out.writeInt(mDischargeAmountScreenOff);
+        out.writeInt(mDischargeAmountScreenOffSinceCharge);
         out.writeLong(mLastWriteTime);
 
         out.writeLong(getMobileTcpBytesReceived(STATS_SINCE_UNPLUGGED));