AudioFlinger: Use atomic pointer for AudioFlinger singleton.
Set when AudioFlinger is assigned to sp<> (i.e. onFirstRef())
by the main audioserver thread.
Test: basic audio works
Test: AudioEffectTest AudioPreProcessingTest BassBoostTest
Test: EnvReverbTest EqualizerTest LoudnessEnhancerTest
Test: PresetReverbTest VirtualizerTest VisualizerTest
Bug: 161341295
Change-Id: I21b8c88f35fbeaae6214b2f894cfcea22b965f6f
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index a6f0953..b8257d3 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -128,9 +128,6 @@
// we define a minimum time during which a global effect is considered enabled.
static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
-Mutex gLock;
-wp<AudioFlinger> gAudioFlinger;
-
// Keep a strong reference to media.log service around forever.
// The service is within our parent process so it can never die in a way that we could observe.
// These two variables are const after initialization.
@@ -268,7 +265,7 @@
mMode = AUDIO_MODE_NORMAL;
- gAudioFlinger = this;
+ gAudioFlinger = this; // we are already refcounted, store into atomic pointer.
mDevicesFactoryHalCallback = new DevicesFactoryHalCallbackImpl;
mDevicesFactoryHal->setCallbackOnce(mDevicesFactoryHalCallback);
@@ -325,11 +322,9 @@
sp<MmapStreamInterface>& interface,
audio_port_handle_t *handle)
{
- sp<AudioFlinger> af;
- {
- Mutex::Autolock _l(gLock);
- af = gAudioFlinger.promote();
- }
+ // TODO: Use ServiceManager to get IAudioFlinger instead of by atomic pointer.
+ // This allows moving oboeservice (AAudio) to a separate process in the future.
+ sp<AudioFlinger> af = AudioFlinger::gAudioFlinger.load(); // either nullptr or singleton AF.
status_t ret = NO_INIT;
if (af != 0) {
ret = af->openMmapStream(
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 8b96355..1d530a4 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -306,6 +306,24 @@
Mutex mUnregisteredWritersLock;
public:
+ // Life cycle of gAudioFlinger and AudioFlinger:
+ //
+ // AudioFlinger is created once and survives until audioserver crashes
+ // irrespective of sp<> and wp<> as it is refcounted by ServiceManager and we
+ // don't issue a ServiceManager::tryUnregisterService().
+ //
+ // gAudioFlinger is an atomic pointer set on AudioFlinger::onFirstRef().
+ // After this is set, it is safe to obtain a wp<> or sp<> from it as the
+ // underlying object does not go away.
+ //
+ // Note: For most inner classes, it is acceptable to hold a reference to the outer
+ // AudioFlinger instance as creation requires AudioFlinger to exist in the first place.
+ //
+ // An atomic here ensures underlying writes have completed before setting
+ // the pointer. Access by memory_order_seq_cst.
+ //
+
+ static inline std::atomic<AudioFlinger *> gAudioFlinger = nullptr;
class SyncEvent;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index f5a8552..56d32a6 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -2785,11 +2785,7 @@
const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
sp<EffectHalInterface> *effect) {
status_t status = NO_INIT;
- sp<AudioFlinger> af = mAudioFlinger.promote();
- if (af == nullptr) {
- return status;
- }
- sp<EffectsFactoryHalInterface> effectsFactory = af->getEffectsFactory();
+ sp<EffectsFactoryHalInterface> effectsFactory = mAudioFlinger.getEffectsFactory();
if (effectsFactory != 0) {
status = effectsFactory->createEffect(pEffectUuid, sessionId, io(), deviceId, effect);
}
@@ -2798,19 +2794,13 @@
bool AudioFlinger::EffectChain::EffectCallback::updateOrphanEffectChains(
const sp<AudioFlinger::EffectBase>& effect) {
- sp<AudioFlinger> af = mAudioFlinger.promote();
- if (af == nullptr) {
- return false;
- }
// in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
- return af->updateOrphanEffectChains(effect->asEffectModule());
+ return mAudioFlinger.updateOrphanEffectChains(effect->asEffectModule());
}
status_t AudioFlinger::EffectChain::EffectCallback::allocateHalBuffer(
size_t size, sp<EffectBufferHalInterface>* buffer) {
- sp<AudioFlinger> af = mAudioFlinger.promote();
- LOG_ALWAYS_FATAL_IF(af == nullptr, "allocateHalBuffer() could not retrieved audio flinger");
- return af->mEffectsFactoryHal->allocateBuffer(size, buffer);
+ return mAudioFlinger.mEffectsFactoryHal->allocateBuffer(size, buffer);
}
status_t AudioFlinger::EffectChain::EffectCallback::addEffectToHal(
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 476330c..139c049 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -524,8 +524,9 @@
// during construction (but may keep a reference for later promotion).
EffectCallback(const wp<EffectChain>& owner,
const wp<ThreadBase>& thread)
- : mChain(owner) {
- setThread(thread);
+ : mChain(owner)
+ , mThread(thread)
+ , mAudioFlinger(*gAudioFlinger) {
}
status_t createEffectHal(const effect_uuid_t *pEffectUuid,
@@ -566,14 +567,12 @@
void setThread(const wp<ThreadBase>& thread) {
mThread = thread;
- sp<ThreadBase> p = thread.promote();
- mAudioFlinger = p ? p->mAudioFlinger : nullptr;
}
private:
const wp<EffectChain> mChain;
mediautils::atomic_wp<ThreadBase> mThread;
- wp<AudioFlinger> mAudioFlinger; // this could be const with some rearrangement.
+ AudioFlinger &mAudioFlinger; // implementation detail: outer instance always exists.
};
friend class AudioFlinger; // for mThread, mEffects