Merge "Prevent audioflinger battery notes leak" into udc-qpr-dev am: 39d8386ec1 am: d1a5674f62

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/av/+/23839324

Change-Id: Ic24686cb6defbfa69a5898e7a2787d96c815a107
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/media/utils/BatteryNotifier.cpp b/media/utils/BatteryNotifier.cpp
index 09bc042..7762c24 100644
--- a/media/utils/BatteryNotifier.cpp
+++ b/media/utils/BatteryNotifier.cpp
@@ -85,8 +85,8 @@
 
 void BatteryNotifier::noteStopAudio(uid_t uid) {
     Mutex::Autolock _l(mLock);
-    if (mAudioRefCounts.find(uid) == mAudioRefCounts.end()) {
-        ALOGW("%s: audio refcount is broken for uid(%d).", __FUNCTION__, (int)uid);
+    if (mAudioRefCounts.find(uid) == mAudioRefCounts.end() || (mAudioRefCounts[uid] == 0)) {
+        ALOGE("%s: audio refcount is broken for uid(%d).", __FUNCTION__, (int)uid);
         return;
     }
 
diff --git a/media/utils/include/mediautils/BatteryNotifier.h b/media/utils/include/mediautils/BatteryNotifier.h
index 3812d7a..73bed4a 100644
--- a/media/utils/include/mediautils/BatteryNotifier.h
+++ b/media/utils/include/mediautils/BatteryNotifier.h
@@ -68,6 +68,38 @@
     sp<IBatteryStats> getBatteryService_l();
 };
 
+namespace mediautils {
+class BatteryStatsAudioHandle {
+  public:
+    static constexpr uid_t INVALID_UID = static_cast<uid_t>(-1);
+
+    explicit BatteryStatsAudioHandle(uid_t uid) : mUid(uid) {
+        if (uid != INVALID_UID) {
+            BatteryNotifier::getInstance().noteStartAudio(mUid);
+        }
+    }
+
+    BatteryStatsAudioHandle(BatteryStatsAudioHandle&& other) : mUid(other.mUid) {
+        other.mUid = INVALID_UID;
+    }
+
+    BatteryStatsAudioHandle(const BatteryStatsAudioHandle& other) = delete;
+
+    BatteryStatsAudioHandle& operator=(const BatteryStatsAudioHandle& other) = delete;
+
+    BatteryStatsAudioHandle& operator=(BatteryStatsAudioHandle&& other) = delete;
+
+    ~BatteryStatsAudioHandle() {
+        if (mUid != INVALID_UID) {
+            BatteryNotifier::getInstance().noteStopAudio(mUid);
+        }
+    }
+
+  private:
+    // Logically const
+    uid_t mUid = INVALID_UID;
+};
+}  // namespace mediautils
 }  // namespace android
 
 #endif // MEDIA_BATTERY_NOTIFIER_H
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 6a43d1e..56285bf 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -74,6 +74,7 @@
 #include <media/DeviceDescriptorBase.h>
 #include <media/ExtendedAudioBufferProvider.h>
 #include <media/VolumeShaper.h>
+#include <mediautils/BatteryNotifier.h>
 #include <mediautils/ServiceUtilities.h>
 #include <mediautils/SharedMemoryAllocator.h>
 #include <mediautils/Synchronization.h>
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 397f5bd..af15cfc 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1858,7 +1858,7 @@
     logTrack("add", track);
     mActiveTracksGeneration++;
     mLatestActiveTrack = track;
-    ++mBatteryCounter[track->uid()].second;
+    track->beginBatteryAttribution();
     mHasChanged = true;
     return mActiveTracks.add(track);
 }
@@ -1872,7 +1872,7 @@
     }
     logTrack("remove", track);
     mActiveTracksGeneration++;
-    --mBatteryCounter[track->uid()].second;
+    track->endBatteryAttribution();
     // mLatestActiveTrack is not cleared even if is the same as track.
     mHasChanged = true;
 #ifdef TEE_SINK
@@ -1885,14 +1885,13 @@
 template <typename T>
 void AudioFlinger::ThreadBase::ActiveTracks<T>::clear() {
     for (const sp<T> &track : mActiveTracks) {
-        BatteryNotifier::getInstance().noteStopAudio(track->uid());
+        track->endBatteryAttribution();
         logTrack("clear", track);
     }
     mLastActiveTracksGeneration = mActiveTracksGeneration;
     if (!mActiveTracks.empty()) { mHasChanged = true; }
     mActiveTracks.clear();
     mLatestActiveTrack.clear();
-    mBatteryCounter.clear();
 }
 
 template <typename T>
@@ -1903,27 +1902,6 @@
         thread->updateWakeLockUids_l(getWakeLockUids());
         mLastActiveTracksGeneration = mActiveTracksGeneration;
     }
-
-    // Updates BatteryNotifier uids
-    for (auto it = mBatteryCounter.begin(); it != mBatteryCounter.end();) {
-        const uid_t uid = it->first;
-        ssize_t &previous = it->second.first;
-        ssize_t &current = it->second.second;
-        if (current > 0) {
-            if (previous == 0) {
-                BatteryNotifier::getInstance().noteStartAudio(uid);
-            }
-            previous = current;
-            ++it;
-        } else if (current == 0) {
-            if (previous > 0) {
-                BatteryNotifier::getInstance().noteStopAudio(uid);
-            }
-            it = mBatteryCounter.erase(it); // std::map<> is stable on iterator erase.
-        } else /* (current < 0) */ {
-            LOG_ALWAYS_FATAL("negative battery count %zd", current);
-        }
-    }
 }
 
 template <typename T>
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 3d41f45..482c66e 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -829,8 +829,6 @@
                         return wakeLockUids; // moved by underlying SharedBuffer
                     }
 
-                    std::map<uid_t, std::pair<ssize_t /* previous */, ssize_t /* current */>>
-                                        mBatteryCounter;
                     SortedVector<sp<T>> mActiveTracks;
                     int                 mActiveTracksGeneration;
                     int                 mLastActiveTracksGeneration;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index d5b6a98..dec49ba 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -270,6 +270,23 @@
     /** Set that a metadata has changed and needs to be notified to backend. Thread safe. */
     void setMetadataHasChanged() { mChangeNotified.clear(); }
 
+    /**
+     * Called when a track moves to active state to record its contribution to battery usage.
+     * Track state transitions should eventually be handled within the track class.
+     */
+    void beginBatteryAttribution() {
+        mBatteryStatsHolder.emplace(uid());
+    }
+
+    /**
+     * Called when a track moves out of the active state to record its contribution
+     * to battery usage.
+     */
+    void endBatteryAttribution() {
+        mBatteryStatsHolder.reset();
+    }
+
+
 protected:
     DISALLOW_COPY_AND_ASSIGN(TrackBase);
 
@@ -413,6 +430,8 @@
 
     // If the last track change was notified to the client with readAndClearHasChanged
     std::atomic_flag    mChangeNotified = ATOMIC_FLAG_INIT;
+    // RAII object for battery stats book-keeping
+    std::optional<mediautils::BatteryStatsAudioHandle> mBatteryStatsHolder;
 };
 
 // PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.