aaudio: cleanup thread handling
Fix problem when an attempt is made to join the callback from the
callback. It used to leave mHasThread in the wrong state.
This was fixed in AAudioThread and in AudioStream.
Add "_l" suffix to functions that need to be locked.
Simplify the way that reference counted objects are passed to threads
using incStrong() and decStrong().
Bug: 171296283
Test: atest AAudioTestCases
Change-Id: I034049c4cb9021c6073fff441e49214ee898b804
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 9f34153..483a264 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -306,6 +306,7 @@
mSharedStreams.end());
serviceEndpoint->close();
+
mSharedCloseCount++;
ALOGV("%s(%p) closed for device %d",
__func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index f5de59f..caf6139 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -88,23 +88,30 @@
}
void AAudioServiceEndpointShared::close() {
- getStreamInternal()->releaseCloseFinal();
+ stopSharingThread();
+ getStreamInternal()->safeReleaseClose();
}
// Glue between C and C++ callbacks.
static void *aaudio_endpoint_thread_proc(void *arg) {
assert(arg != nullptr);
+ ALOGD("%s() called", __func__);
- // The caller passed in a smart pointer to prevent the endpoint from getting deleted
- // while the thread was launching.
- sp<AAudioServiceEndpointShared> *endpointForThread =
- static_cast<sp<AAudioServiceEndpointShared> *>(arg);
- sp<AAudioServiceEndpointShared> endpoint = *endpointForThread;
- delete endpointForThread; // Just use scoped smart pointer. Don't need this anymore.
+ // Prevent the stream from being deleted while being used.
+ // This is just for extra safety. It is probably not needed because
+ // this callback should be joined before the stream is closed.
+ AAudioServiceEndpointShared *endpointPtr =
+ static_cast<AAudioServiceEndpointShared *>(arg);
+ android::sp<AAudioServiceEndpointShared> endpoint(endpointPtr);
+ // Balance the incStrong() in startSharingThread_l().
+ endpoint->decStrong(nullptr);
+
void *result = endpoint->callbackLoop();
// Close now so that the HW resource is freed and we can open a new device.
if (!endpoint->isConnected()) {
- endpoint->close();
+ ALOGD("%s() call safeReleaseCloseFromCallback()", __func__);
+ // Release and close under a lock with no check for callback collisions.
+ endpoint->getStreamInternal()->safeReleaseCloseFromCallback();
}
return result;
@@ -116,14 +123,14 @@
* AAUDIO_NANOS_PER_SECOND
/ getSampleRate();
mCallbackEnabled.store(true);
- // Pass a smart pointer so the thread can hold a reference.
- sp<AAudioServiceEndpointShared> *endpointForThread = new sp<AAudioServiceEndpointShared>(this);
- aaudio_result_t result = getStreamInternal()->createThread(periodNanos,
- aaudio_endpoint_thread_proc,
- endpointForThread);
+ // Prevent this object from getting deleted before the thread has a chance to create
+ // its strong pointer. Assume the thread will call decStrong().
+ this->incStrong(nullptr);
+ aaudio_result_t result = getStreamInternal()->createThread_l(periodNanos,
+ aaudio_endpoint_thread_proc,
+ this);
if (result != AAUDIO_OK) {
- // The thread can't delete it so we have to do it here.
- delete endpointForThread;
+ this->decStrong(nullptr); // Because the thread won't do it.
}
return result;
}
@@ -141,13 +148,13 @@
{
std::lock_guard<std::mutex> lock(mLockStreams);
if (++mRunningStreamCount == 1) { // atomic
- result = getStreamInternal()->requestStart();
+ result = getStreamInternal()->requestStart_l();
if (result != AAUDIO_OK) {
--mRunningStreamCount;
} else {
result = startSharingThread_l();
if (result != AAUDIO_OK) {
- getStreamInternal()->requestStop();
+ getStreamInternal()->requestStop_l();
--mRunningStreamCount;
}
}
@@ -161,7 +168,7 @@
if (result != AAUDIO_OK) {
if (--mRunningStreamCount == 0) { // atomic
stopSharingThread();
- getStreamInternal()->requestStop();
+ getStreamInternal()->requestStop_l();
}
}
}
@@ -176,7 +183,7 @@
if (--mRunningStreamCount == 0) { // atomic
stopSharingThread(); // the sharing thread locks mLockStreams
- getStreamInternal()->requestStop();
+ getStreamInternal()->requestStop_l();
}
return AAUDIO_OK;
}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index 020b926..91a86c1 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -37,6 +37,8 @@
public:
explicit AAudioServiceEndpointShared(AudioStreamInternal *streamInternal);
+ virtual ~AAudioServiceEndpointShared() = default;
+
std::string dump() const override;
aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
@@ -55,12 +57,12 @@
virtual void *callbackLoop() = 0;
-protected:
-
AudioStreamInternal *getStreamInternal() const {
return mStreamInternal.get();
};
+protected:
+
aaudio_result_t startSharingThread_l();
aaudio_result_t stopSharingThread();
diff --git a/services/oboeservice/AAudioThread.cpp b/services/oboeservice/AAudioThread.cpp
index ed7895b..68496ac 100644
--- a/services/oboeservice/AAudioThread.cpp
+++ b/services/oboeservice/AAudioThread.cpp
@@ -37,10 +37,13 @@
setup("AAudio");
}
-void AAudioThread::setup(const char *prefix) {
- // mThread is a pthread_t of unknown size so we need memset().
- memset(&mThread, 0, sizeof(mThread));
+AAudioThread::~AAudioThread() {
+ ALOGE_IF(pthread_equal(pthread_self(), mThread),
+ "%s() destructor running in thread", __func__);
+ ALOGE_IF(mHasThread, "%s() thread never joined", __func__);
+}
+void AAudioThread::setup(const char *prefix) {
// Name the thread with an increasing index, "prefix_#", for debugging.
uint32_t index = mNextThreadIndex++;
// Wrap the index so that we do not hit the 16 char limit
@@ -57,7 +60,7 @@
}
}
-// This is the entry point for the new thread created by createThread().
+// This is the entry point for the new thread created by createThread_l().
// It converts the 'C' function call to a C++ method call.
static void * AAudioThread_internalThreadProc(void *arg) {
AAudioThread *aaudioThread = (AAudioThread *) arg;
@@ -90,13 +93,18 @@
ALOGE("stop() but no thread running");
return AAUDIO_ERROR_INVALID_STATE;
}
+ // Check to see if the thread is trying to stop itself.
+ if (pthread_equal(pthread_self(), mThread)) {
+ ALOGE("%s() attempt to pthread_join() from launched thread!", __func__);
+ return AAUDIO_ERROR_INTERNAL;
+ }
+
int err = pthread_join(mThread, nullptr);
- mHasThread = false;
if (err != 0) {
ALOGE("stop() - pthread_join() returned %d %s", err, strerror(err));
return AAudioConvert_androidToAAudioResult(-err);
} else {
+ mHasThread = false;
return AAUDIO_OK;
}
}
-
diff --git a/services/oboeservice/AAudioThread.h b/services/oboeservice/AAudioThread.h
index dcce68a..08a8a98 100644
--- a/services/oboeservice/AAudioThread.h
+++ b/services/oboeservice/AAudioThread.h
@@ -46,7 +46,7 @@
explicit AAudioThread(const char *prefix);
- virtual ~AAudioThread() = default;
+ virtual ~AAudioThread();
/**
* Start the thread running.
@@ -73,7 +73,7 @@
Runnable *mRunnable = nullptr;
bool mHasThread = false;
- pthread_t mThread; // initialized in constructor
+ pthread_t mThread = {};
static std::atomic<uint32_t> mNextThreadIndex;
char mName[16]; // max length for a pthread_name