Add Multicast wakelock stats in battery-stats dump

This commit adds the statistics for multicast wakelocks (count/time)
in dump of battery-stats.
This enables debugging of power issues due to extensive wakeup of host
processor due to arrival of multicast packets, and help identify the
blamed application

Bug: 33649966
Test: Manual Test
Change-Id: I882f945dd36fa2881c59776b4954017bf3c76cd7
Signed-off-by: Ahmed ElArabawy <arabawy@google.com>
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index af91e81..811091e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -224,6 +224,7 @@
      *   - Always On Display (screen doze mode) time and power
      * New in version 28:
      *   - Light/Deep Doze power
+     *   - WiFi Multicast Wakelock statistics (count & duration)
      */
     static final int CHECKIN_VERSION = 28;
 
@@ -313,6 +314,8 @@
     private static final String CAMERA_DATA = "cam";
     private static final String VIDEO_DATA = "vid";
     private static final String AUDIO_DATA = "aud";
+    private static final String WIFI_MULTICAST_TOTAL_DATA = "wmct";
+    private static final String WIFI_MULTICAST_DATA = "wmc";
 
     public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity";
 
@@ -516,6 +519,13 @@
         public abstract ArrayMap<String, ? extends Wakelock> getWakelockStats();
 
         /**
+         * Returns the WiFi Multicast Wakelock statistics.
+         *
+         * @return a Timer Object for the per uid Multicast statistics.
+         */
+        public abstract Timer getMulticastWakelockStats();
+
+        /**
          * Returns a mapping containing sync statistics.
          *
          * @return a Map from Strings to Timer objects.
@@ -3363,13 +3373,16 @@
                 screenDozeTime / 1000);
 
 
-        // Calculate wakelock times across all uids.
+        // Calculate both wakelock and wifi multicast wakelock times across all uids.
         long fullWakeLockTimeTotal = 0;
         long partialWakeLockTimeTotal = 0;
+        long multicastWakeLockTimeTotalMicros = 0;
+        int multicastWakeLockCountTotal = 0;
 
         for (int iu = 0; iu < NU; iu++) {
             final Uid u = uidStats.valueAt(iu);
 
+            // First calculating the wakelock stats
             final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
                     = u.getWakelockStats();
             for (int iw=wakelocks.size()-1; iw>=0; iw--) {
@@ -3387,6 +3400,13 @@
                         rawRealtime, which);
                 }
             }
+
+            // Now calculating the wifi multicast wakelock stats
+            final Timer mcTimer = u.getMulticastWakelockStats();
+            if (mcTimer != null) {
+                multicastWakeLockTimeTotalMicros += mcTimer.getTotalTimeLocked(rawRealtime, which);
+                multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
+            }
         }
 
         // Dump network stats
@@ -3502,6 +3522,11 @@
         }
         dumpLine(pw, 0 /* uid */, category, WIFI_SIGNAL_STRENGTH_COUNT_DATA, args);
 
+        // Dump Multicast total stats
+        dumpLine(pw, 0 /* uid */, category, WIFI_MULTICAST_TOTAL_DATA,
+                multicastWakeLockTimeTotalMicros / 1000,
+                multicastWakeLockCountTotal);
+
         if (which == STATS_SINCE_UNPLUGGED) {
             dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(),
                     getDischargeCurrentLevel());
@@ -3828,6 +3853,18 @@
                 }
             }
 
+            // WiFi Multicast Wakelock Statistics
+            final Timer mcTimer = u.getMulticastWakelockStats();
+            if (mcTimer != null) {
+                final long totalMcWakelockTimeMs =
+                        mcTimer.getTotalTimeLocked(rawRealtime, which) / 1000 ;
+                final int countMcWakelock = mcTimer.getCountLocked(which);
+                if(totalMcWakelockTimeMs > 0) {
+                    dumpLine(pw, uid, category, WIFI_MULTICAST_DATA,
+                            totalMcWakelockTimeMs, countMcWakelock);
+                }
+            }
+
             final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
             for (int isy=syncs.size()-1; isy>=0; isy--) {
                 final Timer timer = syncs.valueAt(isy);
@@ -4327,15 +4364,18 @@
             pw.print("  Connectivity changes: "); pw.println(connChanges);
         }
 
-        // Calculate wakelock times across all uids.
+        // Calculate both wakelock and wifi multicast wakelock times across all uids.
         long fullWakeLockTimeTotalMicros = 0;
         long partialWakeLockTimeTotalMicros = 0;
+        long multicastWakeLockTimeTotalMicros = 0;
+        int multicastWakeLockCountTotal = 0;
 
         final ArrayList<TimerEntry> timers = new ArrayList<>();
 
         for (int iu = 0; iu < NU; iu++) {
             final Uid u = uidStats.valueAt(iu);
 
+            // First calculate wakelock statistics
             final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
                     = u.getWakelockStats();
             for (int iw=wakelocks.size()-1; iw>=0; iw--) {
@@ -4363,6 +4403,13 @@
                     }
                 }
             }
+
+            // Next calculate wifi multicast wakelock statistics
+            final Timer mcTimer = u.getMulticastWakelockStats();
+            if (mcTimer != null) {
+                multicastWakeLockTimeTotalMicros += mcTimer.getTotalTimeLocked(rawRealtime, which);
+                multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
+            }
         }
 
         final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
@@ -4392,6 +4439,20 @@
             pw.println(sb.toString());
         }
 
+        if (multicastWakeLockTimeTotalMicros != 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+            sb.append("  Total WiFi Multicast wakelock Count: ");
+            sb.append(multicastWakeLockCountTotal);
+            pw.println(sb.toString());
+
+            sb.setLength(0);
+            sb.append(prefix);
+            sb.append("  Total WiFi Multicast wakelock time: ");
+            formatTimeMsNoSpace(sb, (multicastWakeLockTimeTotalMicros + 500) / 1000);
+            pw.println(sb.toString());
+        }
+
         pw.println("");
         pw.print(prefix);
         sb.setLength(0);
@@ -5309,6 +5370,24 @@
                 }
             }
 
+            // Calculate multicast wakelock stats
+            final Timer mcTimer = u.getMulticastWakelockStats();
+            if (mcTimer != null) {
+                final long multicastWakeLockTimeMicros = mcTimer.getTotalTimeLocked(rawRealtime, which);
+                final int multicastWakeLockCount = mcTimer.getCountLocked(which);
+
+                if (multicastWakeLockTimeMicros > 0) {
+                    sb.setLength(0);
+                    sb.append(prefix);
+                    sb.append("    WiFi Multicast Wakelock");
+                    sb.append(" count = ");
+                    sb.append(multicastWakeLockCount);
+                    sb.append(" time = ");
+                    formatTimeMsNoSpace(sb, (multicastWakeLockTimeMicros + 500) / 1000);
+                    pw.println(sb.toString());
+                }
+            }
+
             final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
             for (int isy=syncs.size()-1; isy>=0; isy--) {
                 final Timer timer = syncs.valueAt(isy);
@@ -7085,6 +7164,10 @@
                 proto.end(wToken);
             }
 
+            // Wifi Multicast Wakelock (WIFI_MULTICAST_WAKELOCK_DATA)
+            dumpTimer(proto, UidProto.WIFI_MULTICAST_WAKELOCK, u.getMulticastWakelockStats(),
+                    rawRealtimeUs, which);
+
             // Wakeup alarms (WAKEUP_ALARM_DATA)
             for (int ipkg = packageStats.size() - 1; ipkg >= 0; --ipkg) {
                 final Uid.Pkg ps = packageStats.valueAt(ipkg);
@@ -7341,6 +7424,30 @@
                 getLongestDeviceIdleModeTime(DEVICE_IDLE_MODE_LIGHT));
         proto.end(mToken);
 
+        // Wifi multicast wakelock total stats (WIFI_MULTICAST_WAKELOCK_TOTAL_DATA)
+        // Calculate multicast wakelock stats across all uids.
+        long multicastWakeLockTimeTotalUs = 0;
+        int multicastWakeLockCountTotal = 0;
+
+        for (int iu = 0; iu < uidStats.size(); iu++) {
+            final Uid u = uidStats.valueAt(iu);
+
+            final Timer mcTimer = u.getMulticastWakelockStats();
+
+            if (mcTimer != null) {
+                multicastWakeLockTimeTotalUs +=
+                        mcTimer.getTotalTimeLocked(rawRealtimeUs, which);
+                multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
+            }
+        }
+
+        final long wmctToken = proto.start(SystemProto.WIFI_MULTICAST_WAKELOCK_TOTAL);
+        proto.write(SystemProto.WifiMulticastWakelockTotal.DURATION_MS,
+                multicastWakeLockTimeTotalUs / 1000);
+        proto.write(SystemProto.WifiMulticastWakelockTotal.COUNT,
+                multicastWakeLockCountTotal);
+        proto.end(wmctToken);
+
         // Power use item (POWER_USE_ITEM_DATA)
         final List<BatterySipper> sippers = helper.getUsageList();
         if (sippers != null) {