Merge "BatteryStats: Update external stats individually." into mnc-dev
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 94737c7..229079f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -95,8 +95,8 @@
 public final class BatteryStatsImpl extends BatteryStats {
     private static final String TAG = "BatteryStatsImpl";
     private static final boolean DEBUG = false;
-    private static final boolean DEBUG_ENERGY = false;
-    public static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY || false;
+    public static final boolean DEBUG_ENERGY = false;
+    private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY || false;
     private static final boolean DEBUG_HISTORY = false;
     private static final boolean USE_OLD_HISTORY = false;   // for debugging.
 
@@ -182,6 +182,7 @@
 
     public interface ExternalStatsSync {
         void scheduleSync(String reason);
+        void scheduleWifiSync(String reason);
     }
 
     public final MyHandler mHandler;
@@ -3490,7 +3491,7 @@
             addHistoryRecordLocked(elapsedRealtime, uptime);
             mWifiOn = true;
             mWifiOnTimer.startRunningLocked(elapsedRealtime);
-            scheduleSyncExternalStatsLocked("wifi-off");
+            scheduleSyncExternalWifiStatsLocked("wifi-off");
         }
     }
 
@@ -3504,7 +3505,7 @@
             addHistoryRecordLocked(elapsedRealtime, uptime);
             mWifiOn = false;
             mWifiOnTimer.stopRunningLocked(elapsedRealtime);
-            scheduleSyncExternalStatsLocked("wifi-on");
+            scheduleSyncExternalWifiStatsLocked("wifi-on");
         }
     }
 
@@ -3756,7 +3757,7 @@
                 int uid = mapUid(ws.get(i));
                 getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
             }
-            scheduleSyncExternalStatsLocked("wifi-running");
+            scheduleSyncExternalWifiStatsLocked("wifi-running");
         } else {
             Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
         }
@@ -3795,7 +3796,7 @@
                 int uid = mapUid(ws.get(i));
                 getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
             }
-            scheduleSyncExternalStatsLocked("wifi-stopped");
+            scheduleSyncExternalWifiStatsLocked("wifi-stopped");
         } else {
             Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
         }
@@ -3810,7 +3811,7 @@
             }
             mWifiState = wifiState;
             mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime);
-            scheduleSyncExternalStatsLocked("wifi-state");
+            scheduleSyncExternalWifiStatsLocked("wifi-state");
         }
     }
 
@@ -7542,6 +7543,10 @@
      * @param info The energy information from the WiFi controller.
      */
     public void updateWifiStateLocked(@Nullable final WifiActivityEnergyInfo info) {
+        if (DEBUG_ENERGY) {
+            Slog.d(TAG, "Updating wifi stats");
+        }
+
         final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
         NetworkStats delta = null;
         try {
@@ -7739,6 +7744,10 @@
      * Distribute Cell radio energy info and network traffic to apps.
      */
     public void updateMobileRadioStateLocked(final long elapsedRealtimeMs) {
+        if (DEBUG_ENERGY) {
+            Slog.d(TAG, "Updating mobile radio stats");
+        }
+
         NetworkStats delta = null;
         try {
             if (!ArrayUtils.isEmpty(mMobileIfaces)) {
@@ -7811,6 +7820,10 @@
      * @param info The energy information from the bluetooth controller.
      */
     public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
+        if (DEBUG_ENERGY) {
+            Slog.d(TAG, "Updating bluetooth stats");
+        }
+
         if (info != null && mOnBatteryInternal) {
             mHasBluetoothEnergyReporting = true;
             mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
@@ -8233,6 +8246,12 @@
         }
     }
 
+    private void scheduleSyncExternalWifiStatsLocked(String reason) {
+        if (mExternalSync != null) {
+            mExternalSync.scheduleWifiSync(reason);
+        }
+    }
+
     // This should probably be exposed in the API, though it's not critical
     public static final int BATTERY_PLUGGED_NONE = 0;
 
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ee1ee1c..3854e51 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -71,9 +71,16 @@
     Context mContext;
     PowerManagerInternal mPowerManagerInternal;
 
+    final int UPDATE_CPU = 0x01;
+    final int UPDATE_WIFI = 0x02;
+    final int UPDATE_RADIO = 0x04;
+    final int UPDATE_BT = 0x08;
+    final int UPDATE_ALL = UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT;
+
     class BatteryStatsHandler extends Handler implements BatteryStatsImpl.ExternalStatsSync {
         public static final int MSG_SYNC_EXTERNAL_STATS = 1;
         public static final int MSG_WRITE_TO_DISK = 2;
+        private int mUpdateFlags = 0;
 
         public BatteryStatsHandler(Looper looper) {
             super(looper);
@@ -83,11 +90,17 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_SYNC_EXTERNAL_STATS:
-                    updateExternalStats((String)msg.obj, false);
+                    final int updateFlags;
+                    synchronized (this) {
+                        removeMessages(MSG_SYNC_EXTERNAL_STATS);
+                        updateFlags = mUpdateFlags;
+                        mUpdateFlags = 0;
+                    }
+                    updateExternalStats((String)msg.obj, updateFlags);
                     break;
 
                 case MSG_WRITE_TO_DISK:
-                    updateExternalStats("write", true);
+                    updateExternalStats("write", UPDATE_ALL);
                     synchronized (mStats) {
                         mStats.writeAsyncLocked();
                     }
@@ -97,9 +110,20 @@
 
         @Override
         public void scheduleSync(String reason) {
-            if (!hasMessages(MSG_SYNC_EXTERNAL_STATS)) {
-                Message msg = Message.obtain(this, MSG_SYNC_EXTERNAL_STATS, reason);
-                sendMessage(msg);
+            scheduleSyncImpl(reason, UPDATE_ALL);
+        }
+
+        @Override
+        public void scheduleWifiSync(String reason) {
+            scheduleSyncImpl(reason, UPDATE_WIFI);
+        }
+
+        private void scheduleSyncImpl(String reason, int updateFlags) {
+            synchronized (this) {
+                if (mUpdateFlags == 0) {
+                    sendMessage(Message.obtain(this, MSG_SYNC_EXTERNAL_STATS, reason));
+                }
+                mUpdateFlags |= updateFlags;
             }
         }
     }
@@ -137,7 +161,7 @@
     public void shutdown() {
         Slog.w("BatteryStats", "Writing battery stats before shutdown...");
 
-        updateExternalStats("shutdown", true);
+        updateExternalStats("shutdown", UPDATE_ALL);
         synchronized (mStats) {
             mStats.shutdownLocked();
         }
@@ -237,7 +261,7 @@
         //Slog.i("foo", "SENDING BATTERY INFO:");
         //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
         Parcel out = Parcel.obtain();
-        updateExternalStats("get-stats", true);
+        updateExternalStats("get-stats", UPDATE_ALL);
         synchronized (mStats) {
             mStats.writeToParcel(out, 0);
         }
@@ -252,7 +276,7 @@
         //Slog.i("foo", "SENDING BATTERY INFO:");
         //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
         Parcel out = Parcel.obtain();
-        updateExternalStats("get-stats", true);
+        updateExternalStats("get-stats", UPDATE_ALL);
         synchronized (mStats) {
             mStats.writeToParcel(out, 0);
         }
@@ -603,8 +627,10 @@
 
         // There was a change in WiFi power state.
         // Collect data now for the past activity.
-        mHandler.scheduleSync("wifi-data");
         synchronized (mStats) {
+            if (mStats.isOnBattery()) {
+                mHandler.scheduleWifiSync("wifi-data");
+            }
             mStats.noteWifiRadioPowerState(powerState, tsNanos);
         }
     }
@@ -807,7 +833,7 @@
 
         // Sync external stats first as the battery has changed states. If we don't sync
         // immediately here, we may not collect the relevant data later.
-        updateExternalStats("battery-state", true);
+        updateExternalStats("battery-state", UPDATE_ALL);
         synchronized (mStats) {
             mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
         }
@@ -961,9 +987,9 @@
                         pw.println("Battery stats reset.");
                         noOutput = true;
                     }
-                    updateExternalStats("dump", true);
+                    updateExternalStats("dump", UPDATE_ALL);
                 } else if ("--write".equals(arg)) {
-                    updateExternalStats("dump", true);
+                    updateExternalStats("dump", UPDATE_ALL);
                     synchronized (mStats) {
                         mStats.writeSyncLocked();
                         pw.println("Battery stats written.");
@@ -1027,7 +1053,7 @@
                 flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
             }
             // Fetch data from external sources and update the BatteryStatsImpl object with them.
-            updateExternalStats("dump", true);
+            updateExternalStats("dump", UPDATE_ALL);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -1215,15 +1241,12 @@
      * We first grab a lock specific to this method, then once all the data has been collected,
      * we grab the mStats lock and update the data.
      *
-     * TODO(adamlesinski): When we start distributing bluetooth data to apps, we'll want to
-     * separate these external stats so that they can be collected individually and on different
-     * intervals.
-     *
      * @param reason The reason why this collection was requested. Useful for debugging.
-     * @param force If false, some stats may decide not to be collected for efficiency as their
-     *              results aren't needed immediately. When true, collect all stats unconditionally.
+     * @param updateFlags Which external stats to update. Can be a combination of
+     *                    {@link #UPDATE_CPU}, {@link #UPDATE_RADIO}, {@link #UPDATE_WIFI},
+     *                    and {@link #UPDATE_BT}.
      */
-    void updateExternalStats(String reason, boolean force) {
+    void updateExternalStats(final String reason, final int updateFlags) {
         synchronized (mExternalStatsLock) {
             if (mContext == null) {
                 // We haven't started yet (which means the BatteryStatsImpl object has
@@ -1231,32 +1254,46 @@
                 return;
             }
 
-            final WifiActivityEnergyInfo wifiEnergyInfo = pullWifiEnergyInfoLocked();
-            final BluetoothActivityEnergyInfo bluetoothEnergyInfo;
-            if (force) {
+            if (BatteryStatsImpl.DEBUG_ENERGY) {
+                Slog.d(TAG, "Updating external stats: reason=" + reason);
+            }
+
+            WifiActivityEnergyInfo wifiEnergyInfo = null;
+            if ((updateFlags & UPDATE_WIFI) != 0) {
+                wifiEnergyInfo = pullWifiEnergyInfoLocked();
+            }
+
+            BluetoothActivityEnergyInfo bluetoothEnergyInfo = null;
+            if ((updateFlags & UPDATE_BT) != 0) {
                 // We only pull bluetooth stats when we have to, as we are not distributing its
                 // use amongst apps and the sampling frequency does not matter.
                 bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked();
-            } else {
-                bluetoothEnergyInfo = null;
             }
 
             synchronized (mStats) {
+                final long elapsedRealtime = SystemClock.elapsedRealtime();
+                final long uptime = SystemClock.uptimeMillis();
                 if (mStats.mRecordAllHistory) {
-                    final long elapsedRealtime = SystemClock.elapsedRealtime();
-                    final long uptime = SystemClock.uptimeMillis();
                     mStats.addHistoryEventLocked(elapsedRealtime, uptime,
                             BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS, reason, 0);
                 }
 
-                if (BatteryStatsImpl.DEBUG_ENERGY_CPU) {
-                    Slog.d(TAG, "Updating cpu time from external: " + reason);
+                if ((updateFlags & UPDATE_CPU) != 0) {
+                    mStats.updateCpuTimeLocked();
+                    mStats.updateKernelWakelocksLocked();
                 }
-                mStats.updateCpuTimeLocked();
-                mStats.updateKernelWakelocksLocked();
-                mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime());
-                mStats.updateWifiStateLocked(wifiEnergyInfo);
-                mStats.updateBluetoothStateLocked(bluetoothEnergyInfo);
+
+                if ((updateFlags & UPDATE_RADIO) != 0) {
+                    mStats.updateMobileRadioStateLocked(elapsedRealtime);
+                }
+
+                if ((updateFlags & UPDATE_WIFI) != 0) {
+                    mStats.updateWifiStateLocked(wifiEnergyInfo);
+                }
+
+                if ((updateFlags & UPDATE_BT) != 0) {
+                    mStats.updateBluetoothStateLocked(bluetoothEnergyInfo);
+                }
             }
         }
     }