Prevent audioflinger battery notes leak
Ensure battery notes from audioflinger are encapsulated in an RAII
object so noteStart is always properly matched.
Remove uid refcounting in audioserver, since it already exists in
the battery notifier utility class, and is error-prone. As a byproduct,
notes occur during track transitions rather than in the threadloop,
which happens to avoid problematic blocking.
Bump refcount mismatch logging to error.
Bug: 259449389
Test: Manual verification of battery stats notes w/ multiple refs
Change-Id: Ifc931a9ac46f37d662e42dd4696f0a62eec22c25
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 c3ca1b0..7058a25 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 700bdd2..45a5c09 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1877,7 +1877,7 @@
logTrack("add", track);
mActiveTracksGeneration++;
mLatestActiveTrack = track;
- ++mBatteryCounter[track->uid()].second;
+ track->beginBatteryAttribution();
mHasChanged = true;
return mActiveTracks.add(track);
}
@@ -1891,7 +1891,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
@@ -1904,14 +1904,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>
@@ -1922,27 +1921,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 ¤t = 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 e88134b..7d16a0b 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -826,8 +826,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 254fb91..5adeb1f 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);
@@ -412,6 +429,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.