Merge "Re-enable Bluetooth stats reporting in dumpsys" into main
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index c26eeed..fe14f6b 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -11447,7 +11447,7 @@
         mWifiPowerStatsCollector.addConsumer(this::recordPowerStats);
 
         mBluetoothPowerStatsCollector = new BluetoothPowerStatsCollector(
-                mPowerStatsCollectorInjector);
+                mPowerStatsCollectorInjector, this::onBluetoothPowerStatsRetrieved);
         mBluetoothPowerStatsCollector.addConsumer(this::recordPowerStats);
 
         mCameraPowerStatsCollector = new CameraPowerStatsCollector(mPowerStatsCollectorInjector);
@@ -13417,6 +13417,13 @@
     private final BluetoothActivityInfoCache mLastBluetoothActivityInfo
             = new BluetoothActivityInfoCache();
 
+    private void onBluetoothPowerStatsRetrieved(BluetoothActivityEnergyInfo info,
+            long elapsedRealtimeMs, long uptimeMs) {
+        // Do not populate consumed energy, because energy attribution is done by
+        // BluetoothPowerStatsProcessor.
+        updateBluetoothStateLocked(info, POWER_DATA_UNAVAILABLE, elapsedRealtimeMs, uptimeMs);
+    }
+
     /**
      * Distribute Bluetooth energy info and network traffic to apps.
      *
@@ -13425,10 +13432,6 @@
     @GuardedBy("this")
     public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info,
             final long consumedChargeUC, long elapsedRealtimeMs, long uptimeMs) {
-        if (mBluetoothPowerStatsCollector.isEnabled()) {
-            return;
-        }
-
         if (DEBUG_ENERGY) {
             Slog.d(TAG, "Updating bluetooth stats: " + info);
         }
diff --git a/services/core/java/com/android/server/power/stats/BluetoothPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/BluetoothPowerStatsCollector.java
index d7aa987..c12ae63 100644
--- a/services/core/java/com/android/server/power/stats/BluetoothPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/BluetoothPowerStatsCollector.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.power.stats;
 
+import android.annotation.Nullable;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.UidTraffic;
@@ -41,7 +42,10 @@
 
     private static final long BLUETOOTH_ACTIVITY_REQUEST_TIMEOUT = 20000;
 
-    private static final long ENERGY_UNSPECIFIED = -1;
+    interface Observer {
+        void onBluetoothPowerStatsRetrieved(@Nullable BluetoothActivityEnergyInfo info,
+                long elapsedRealtimeMs, long uptimeMs);
+    }
 
     public interface BluetoothStatsRetriever {
         interface Callback {
@@ -65,6 +69,7 @@
     }
 
     private final Injector mInjector;
+    private final Observer mObserver;
 
     private com.android.server.power.stats.format.BluetoothPowerStatsLayout mLayout;
     private boolean mIsInitialized;
@@ -89,13 +94,14 @@
 
     private final SparseArray<UidStats> mUidStats = new SparseArray<>();
 
-    public BluetoothPowerStatsCollector(Injector injector) {
+    public BluetoothPowerStatsCollector(Injector injector, @Nullable Observer observer) {
         super(injector.getHandler(),  injector.getPowerStatsCollectionThrottlePeriod(
                         BatteryConsumer.powerComponentIdToString(
                                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH)),
                 injector.getUidResolver(),
                 injector.getClock());
         mInjector = injector;
+        mObserver = observer;
     }
 
     @Override
@@ -146,15 +152,20 @@
         Arrays.fill(mDeviceStats, 0);
         mPowerStats.uidStats.clear();
 
-        collectBluetoothActivityInfo();
+        BluetoothActivityEnergyInfo activityInfo = collectBluetoothActivityInfo();
         collectBluetoothScanStats();
 
         mConsumedEnergyHelper.collectConsumedEnergy(mPowerStats, mLayout);
 
+        if (mObserver != null) {
+            mObserver.onBluetoothPowerStatsRetrieved(activityInfo, mClock.elapsedRealtime(),
+                    mClock.uptimeMillis());
+        }
+
         return mPowerStats;
     }
 
-    private void collectBluetoothActivityInfo() {
+    private BluetoothActivityEnergyInfo collectBluetoothActivityInfo() {
         CompletableFuture<BluetoothActivityEnergyInfo> immediateFuture = new CompletableFuture<>();
         boolean success = mBluetoothStatsRetriever.requestControllerActivityEnergyInfo(
                 Runnable::run,
@@ -173,7 +184,7 @@
                 });
 
         if (!success) {
-            return;
+            return null;
         }
 
         BluetoothActivityEnergyInfo activityInfo;
@@ -186,7 +197,7 @@
         }
 
         if (activityInfo == null) {
-            return;
+            return null;
         }
 
         long rxTime = activityInfo.getControllerRxTimeMillis();
@@ -241,6 +252,8 @@
                 mLayout.setUidTxBytes(stats, txDelta);
             }
         }
+
+        return activityInfo;
     }
 
     private void collectBluetoothScanStats() {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerStatsCollectorTest.java
index e392c5d..3895cb4 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerStatsCollectorTest.java
@@ -225,7 +225,10 @@
     }
 
     private PowerStats collectPowerStats() {
-        BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector);
+        List<BluetoothActivityEnergyInfo> expected = new ArrayList<>();
+        List<BluetoothActivityEnergyInfo> observed = new ArrayList<>();
+        BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector,
+                (info, elapsedRealtimeMs, uptimeMs) -> observed.add(info));
         collector.setEnabled(true);
 
         when(mConsumedEnergyRetriever.getVoltageMv()).thenReturn(3500);
@@ -236,6 +239,7 @@
                 mockUidTraffic(APP_UID1, 100, 200),
                 mockUidTraffic(APP_UID2, 300, 400),
                 mockUidTraffic(ISOLATED_UID, 500, 600));
+        expected.add(mBluetoothActivityEnergyInfo);
 
         mUidScanTimes.put(APP_UID1, 100);
 
@@ -248,6 +252,7 @@
                 mockUidTraffic(APP_UID1, 1100, 2200),
                 mockUidTraffic(APP_UID2, 3300, 4400),
                 mockUidTraffic(ISOLATED_UID, 5500, 6600));
+        expected.add(mBluetoothActivityEnergyInfo);
 
         mUidScanTimes.clear();
         mUidScanTimes.put(APP_UID1, 200);
@@ -257,7 +262,10 @@
         mockConsumedEnergy(777, 64321);
 
         mStatsRule.setTime(20000, 20000);
-        return collector.collectStats();
+        PowerStats powerStats = collector.collectStats();
+
+        assertThat(observed).isEqualTo(expected);
+        return powerStats;
     }
 
     private void mockConsumedEnergy(int consumerId, long energyUWs) {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/BluetoothPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/BluetoothPowerStatsProcessorTest.java
index 2c580e5..6013186 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/BluetoothPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/BluetoothPowerStatsProcessorTest.java
@@ -170,7 +170,7 @@
         PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(
                 () -> new BluetoothPowerStatsProcessor(mStatsRule.getPowerProfile()));
 
-        BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector);
+        BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector, null);
         collector.setEnabled(true);
         mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1000, 600, 100, 200,
                 mockUidTraffic(APP_UID1, 100, 200),
@@ -271,7 +271,7 @@
         PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(
                 () -> new BluetoothPowerStatsProcessor(mStatsRule.getPowerProfile()));
 
-        BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector);
+        BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector, null);
         collector.setEnabled(true);
         mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1000, 600, 100, 200,
                 mockUidTraffic(APP_UID1, 100, 200),
@@ -371,7 +371,7 @@
         PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(
                 () -> new BluetoothPowerStatsProcessor(mStatsRule.getPowerProfile()));
 
-        BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector);
+        BluetoothPowerStatsCollector collector = new BluetoothPowerStatsCollector(mInjector, null);
         collector.setEnabled(true);
         mBluetoothActivityEnergyInfo = mockBluetoothActivityEnergyInfo(1000, 600, 100, 200,
                 mockUidTraffic(APP_UID1, 100, 200),