AudioPolicyService: Properly handle service restarts in UidPolicy
Add logic in UidPolicy for handling audioserver restarts as well
as ActivityManager (system server) restarts.
Also, refactor the UidPolicy logic to simplify reasoning about
active state lookup. As a result, 4 layers are considered:
1. Service UIDs--always active.
2. Overrides--controlled via 'adb shell cmd'.
3. Cached UIDs from ActivityManager--also updated via IUidObserver.
4. ActivityManager ground truth.
Bug: 73405145
Bug: 77300296
Test: android.media.cts.AudioRecordTest#testRecordNoDataForIdleUids
manual tests with SoloTester
Change-Id: I426dd5d4d9c9c2570c0e03dde390e18f672c1b1d
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 81ef2ac..4049cab 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -332,19 +332,16 @@
void AudioPolicyService::setRecordSilenced(uid_t uid, bool silenced)
{
-// FIXME: temporarily disable while investigating issue b/77300296
-// {
-// Mutex::Autolock _l(mLock);
-// if (mAudioPolicyManager) {
-// mAudioPolicyManager->setRecordSilenced(uid, silenced);
-// }
-// }
-// sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-// if (af) {
-// af->setRecordSilenced(uid, silenced);
-// }
- (void)uid;
- (void)silenced;
+ {
+ Mutex::Autolock _l(mLock);
+ if (mAudioPolicyManager) {
+ mAudioPolicyManager->setRecordSilenced(uid, silenced);
+ }
+ }
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af) {
+ af->setRecordSilenced(uid, silenced);
+ }
}
status_t AudioPolicyService::dump(int fd, const Vector<String16>& args __unused)
@@ -508,94 +505,129 @@
| ActivityManager::UID_OBSERVER_ACTIVE,
ActivityManager::PROCESS_STATE_UNKNOWN,
String16("audioserver"));
+ status_t res = am.linkToDeath(this);
+ if (!res) {
+ Mutex::Autolock _l(mLock);
+ mObserverRegistered = true;
+ } else {
+ ALOGE("UidPolicy::registerSelf linkToDeath failed: %d", res);
+ am.unregisterUidObserver(this);
+ }
}
void AudioPolicyService::UidPolicy::unregisterSelf() {
ActivityManager am;
+ am.unlinkToDeath(this);
am.unregisterUidObserver(this);
+ Mutex::Autolock _l(mLock);
+ mObserverRegistered = false;
}
-void AudioPolicyService::UidPolicy::onUidGone(uid_t uid, __unused bool disabled) {
- onUidIdle(uid, disabled);
-}
-
-void AudioPolicyService::UidPolicy::onUidActive(uid_t uid) {
- {
- Mutex::Autolock _l(mUidLock);
- mActiveUids.insert(uid);
- }
- sp<AudioPolicyService> service = mService.promote();
- if (service != nullptr) {
- service->setRecordSilenced(uid, false);
- }
-}
-
-void AudioPolicyService::UidPolicy::onUidIdle(uid_t uid, __unused bool disabled) {
- bool deleted = false;
- {
- Mutex::Autolock _l(mUidLock);
- if (mActiveUids.erase(uid) > 0) {
- deleted = true;
- }
- }
- if (deleted) {
- sp<AudioPolicyService> service = mService.promote();
- if (service != nullptr) {
- service->setRecordSilenced(uid, true);
- }
- }
-}
-
-void AudioPolicyService::UidPolicy::addOverrideUid(uid_t uid, bool active) {
- updateOverrideUid(uid, active, true);
-}
-
-void AudioPolicyService::UidPolicy::removeOverrideUid(uid_t uid) {
- updateOverrideUid(uid, false, false);
-}
-
-void AudioPolicyService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
- bool wasActive = false;
- bool isActive = false;
- {
- Mutex::Autolock _l(mUidLock);
- wasActive = isUidActiveLocked(uid);
- mOverrideUids.erase(uid);
- if (insert) {
- mOverrideUids.insert(std::pair<uid_t, bool>(uid, active));
- }
- isActive = isUidActiveLocked(uid);
- }
- if (wasActive != isActive) {
- sp<AudioPolicyService> service = mService.promote();
- if (service != nullptr) {
- service->setRecordSilenced(uid, !isActive);
- }
- }
+void AudioPolicyService::UidPolicy::binderDied(__unused const wp<IBinder> &who) {
+ Mutex::Autolock _l(mLock);
+ mCachedUids.clear();
+ mObserverRegistered = false;
}
bool AudioPolicyService::UidPolicy::isUidActive(uid_t uid) {
- // Non-app UIDs are considered always active
- if (uid < FIRST_APPLICATION_UID) {
- return true;
+ if (isServiceUid(uid)) return true;
+ bool needToReregister = false;
+ {
+ Mutex::Autolock _l(mLock);
+ needToReregister = !mObserverRegistered;
}
- Mutex::Autolock _l(mUidLock);
- return isUidActiveLocked(uid);
+ if (needToReregister) {
+ // Looks like ActivityManager has died previously, attempt to re-register.
+ registerSelf();
+ }
+ {
+ Mutex::Autolock _l(mLock);
+ auto overrideIter = mOverrideUids.find(uid);
+ if (overrideIter != mOverrideUids.end()) {
+ return overrideIter->second;
+ }
+ // In an absense of the ActivityManager, assume everything to be active.
+ if (!mObserverRegistered) return true;
+ auto cacheIter = mCachedUids.find(uid);
+ if (cacheIter != mOverrideUids.end()) {
+ return cacheIter->second;
+ }
+ }
+ ActivityManager am;
+ bool active = am.isUidActive(uid, String16("audioserver"));
+ {
+ Mutex::Autolock _l(mLock);
+ mCachedUids.insert(std::pair<uid_t, bool>(uid, active));
+ }
+ return active;
}
-bool AudioPolicyService::UidPolicy::isUidActiveLocked(uid_t uid) {
- // Non-app UIDs are considered always active
-// FIXME: temporarily disable while investigating issue b/77300296
-// if (uid < FIRST_APPLICATION_UID) {
-// return true;
-// }
-// auto it = mOverrideUids.find(uid);
-// if (it != mOverrideUids.end()) {
-// return it->second;
-// }
-// return mActiveUids.find(uid) != mActiveUids.end();
- (void)uid;
- return true;
+void AudioPolicyService::UidPolicy::onUidActive(uid_t uid) {
+ updateUidCache(uid, true, true);
+}
+
+void AudioPolicyService::UidPolicy::onUidGone(uid_t uid, __unused bool disabled) {
+ updateUidCache(uid, false, false);
+}
+
+void AudioPolicyService::UidPolicy::onUidIdle(uid_t uid, __unused bool disabled) {
+ updateUidCache(uid, false, true);
+}
+
+bool AudioPolicyService::UidPolicy::isServiceUid(uid_t uid) const {
+ return uid % AID_USER_OFFSET < AID_APP_START;
+}
+
+void AudioPolicyService::UidPolicy::notifyService(uid_t uid, bool active) {
+ sp<AudioPolicyService> service = mService.promote();
+ if (service != nullptr) {
+ service->setRecordSilenced(uid, !active);
+ }
+}
+
+void AudioPolicyService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
+ if (isServiceUid(uid)) return;
+ bool wasOverridden = false, wasActive = false;
+ {
+ Mutex::Autolock _l(mLock);
+ updateUidLocked(&mOverrideUids, uid, active, insert, &wasOverridden, &wasActive);
+ }
+ if (!wasOverridden && insert) {
+ notifyService(uid, active); // Started to override.
+ } else if (wasOverridden && !insert) {
+ notifyService(uid, isUidActive(uid)); // Override ceased, notify with ground truth.
+ } else if (wasActive != active) {
+ notifyService(uid, active); // Override updated.
+ }
+}
+
+void AudioPolicyService::UidPolicy::updateUidCache(uid_t uid, bool active, bool insert) {
+ if (isServiceUid(uid)) return;
+ bool wasActive = false;
+ {
+ Mutex::Autolock _l(mLock);
+ updateUidLocked(&mCachedUids, uid, active, insert, nullptr, &wasActive);
+ // Do not notify service if currently overridden.
+ if (mOverrideUids.find(uid) != mOverrideUids.end()) return;
+ }
+ bool nowActive = active && insert;
+ if (wasActive != nowActive) notifyService(uid, nowActive);
+}
+
+void AudioPolicyService::UidPolicy::updateUidLocked(std::unordered_map<uid_t, bool> *uids,
+ uid_t uid, bool active, bool insert, bool *wasThere, bool *wasActive) {
+ auto it = uids->find(uid);
+ if (it != uids->end()) {
+ if (wasThere != nullptr) *wasThere = true;
+ if (wasActive != nullptr) *wasActive = it->second;
+ if (insert) {
+ it->second = active;
+ } else {
+ uids->erase(it);
+ }
+ } else if (insert) {
+ uids->insert(std::pair<uid_t, bool>(uid, active));
+ }
}
// ----------- AudioPolicyService::AudioCommandThread implementation ----------
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index bfa3ef4..b3bc12b 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -35,7 +35,6 @@
#include "managerdefault/AudioPolicyManager.h"
#include <unordered_map>
-#include <unordered_set>
namespace android {
@@ -264,31 +263,40 @@
// transparently handles recording while the UID transitions between idle/active state
// avoiding to get stuck in a state receiving non-empty buffers while idle or in a state
// receiving empty buffers while active.
- class UidPolicy : public BnUidObserver {
+ class UidPolicy : public BnUidObserver, public virtual IBinder::DeathRecipient {
public:
explicit UidPolicy(wp<AudioPolicyService> service)
- : mService(service) {}
+ : mService(service), mObserverRegistered(false) {}
void registerSelf();
void unregisterSelf();
+ // IBinder::DeathRecipient implementation
+ void binderDied(const wp<IBinder> &who) override;
+
bool isUidActive(uid_t uid);
- void onUidGone(uid_t uid, bool disabled);
- void onUidActive(uid_t uid);
- void onUidIdle(uid_t uid, bool disabled);
+ // BnUidObserver implementation
+ void onUidActive(uid_t uid) override;
+ void onUidGone(uid_t uid, bool disabled) override;
+ void onUidIdle(uid_t uid, bool disabled) override;
- void addOverrideUid(uid_t uid, bool active);
- void removeOverrideUid(uid_t uid);
+ void addOverrideUid(uid_t uid, bool active) { updateOverrideUid(uid, active, true); }
+ void removeOverrideUid(uid_t uid) { updateOverrideUid(uid, false, false); }
private:
- bool isUidActiveLocked(uid_t uid);
+ bool isServiceUid(uid_t uid) const;
+ void notifyService(uid_t uid, bool active);
void updateOverrideUid(uid_t uid, bool active, bool insert);
+ void updateUidCache(uid_t uid, bool active, bool insert);
+ void updateUidLocked(std::unordered_map<uid_t, bool> *uids,
+ uid_t uid, bool active, bool insert, bool *wasThere, bool *wasActive);
- Mutex mUidLock;
wp<AudioPolicyService> mService;
- std::unordered_set<uid_t> mActiveUids;
+ Mutex mLock;
+ bool mObserverRegistered;
std::unordered_map<uid_t, bool> mOverrideUids;
+ std::unordered_map<uid_t, bool> mCachedUids;
};
// Thread used for tone playback and to send audio config commands to audio flinger