Add handling of "hard" I/O errors to AudioFlinger
"Hard" errors are unrecoverable errors reported by the HAL. In
AIDL HAL, "hard" errors are indicated by switching the stream
into the `ERROR` state, which only allows closing it.
The asynchronous error callback in the AIDL stream interface is
also used to indicate that an unrecoverable error has occured
(for example, it can be a DSP firmware crash). In this case the
I/O stream must be re-opened. So far, audioflinger did not have
support for this scenario. What was happening before is that the
offload track was invalidated, causing the output thread to be
closed. Then track recreation by the client caused the thread to
be created again. However, this sequence is a race between the
audioserver and the app, and thus it is possible that the track
gets recreated on still the same thread, which is unusable
because the HAL stream is in the `ERROR` state.
Bug: 339400414
Test: repro steps in the bug
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bf203ce4210f480a6ddf158c6fb0b49b4f80f345)
Merged-In: I100d235506f5e3fdfb781a043bbf64746e918d84
Change-Id: I100d235506f5e3fdfb781a043bbf64746e918d84
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index ddf0669..98e3298 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -946,7 +946,7 @@
// StreamOutHalInterfaceCallback implementation
virtual void onWriteReady();
virtual void onDrainReady();
- virtual void onError();
+ virtual void onError(bool /*isHardError*/);
public: // AsyncCallbackThread
void resetWriteBlocked(uint32_t sequence);
@@ -958,7 +958,7 @@
virtual bool shouldStandby_l() REQUIRES(mutex(), ThreadBase_ThreadLoop);
virtual void onAddNewTrack_l() REQUIRES(mutex());
public: // AsyncCallbackThread
- void onAsyncError(); // error reported by AsyncCallbackThread
+ void onAsyncError(bool isHardError); // error reported by AsyncCallbackThread
protected:
// StreamHalInterfaceCodecFormatCallback implementation
void onCodecFormatChanged(
@@ -1371,6 +1371,8 @@
bool destroyTrack_l(const sp<IAfTrack>& track) final REQUIRES(mutex());
void removeTrack_l(const sp<IAfTrack>& track) REQUIRES(mutex());
+ std::set<audio_port_handle_t> getTrackPortIds_l() REQUIRES(mutex());
+ std::set<audio_port_handle_t> getTrackPortIds();
void readOutputParameters_l() REQUIRES(mutex());
MetadataUpdate updateMetadata_l() final REQUIRES(mutex());
@@ -1834,7 +1836,7 @@
void resetWriteBlocked();
void setDraining(uint32_t sequence);
void resetDraining();
- void setAsyncError();
+ void setAsyncError(bool isHardError);
private:
const wp<PlaybackThread> mPlaybackThread;
@@ -1848,7 +1850,8 @@
uint32_t mDrainSequence;
audio_utils::condition_variable mWaitWorkCV;
mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kAsyncCallbackThread_Mutex};
- bool mAsyncError;
+ enum AsyncError { ASYNC_ERROR_NONE, ASYNC_ERROR_SOFT, ASYNC_ERROR_HARD };
+ AsyncError mAsyncError;
audio_utils::mutex& mutex() const RETURN_CAPABILITY(audio_utils::AsyncCallbackThread_Mutex) {
return mMutex;