aaudio: close MMAP stream if client dies
Notify client when audio service dies. Clear connection.
Notify AAudio service when client dies. Close client streams.
Use sp<> to track ServiceStreams.
Bug: 38267698
Test: test_no_close.cpp
Change-Id: I5f1699ed3b8b7bd960947c0028a89ca8419ce7a0
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
new file mode 100644
index 0000000..da7b80f
--- /dev/null
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#define LOG_TAG "AAudioService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <assert.h>
+#include <binder/IPCThreadState.h>
+#include <map>
+#include <mutex>
+#include <utils/Singleton.h>
+
+#include "utility/AAudioUtilities.h"
+#include "AAudioEndpointManager.h"
+#include "AAudioServiceEndpoint.h"
+#include "AAudioClientTracker.h"
+
+using namespace android;
+using namespace aaudio;
+
+ANDROID_SINGLETON_STATIC_INSTANCE(AAudioClientTracker);
+
+AAudioClientTracker::AAudioClientTracker()
+ : Singleton<AAudioClientTracker>() {
+}
+
+// Create a tracker for the client.
+aaudio_result_t AAudioClientTracker::registerClient(pid_t pid,
+ const sp<IAAudioClient>& client) {
+ ALOGD("AAudioClientTracker::registerClient(), calling pid = %d, getpid() = %d\n",
+ pid, getpid());
+
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mNotificationClients.count(pid) == 0) {
+ sp<NotificationClient> notificationClient = new NotificationClient(pid);
+ mNotificationClients[pid] = notificationClient;
+
+ sp<IBinder> binder = IInterface::asBinder(client);
+ status_t status = binder->linkToDeath(notificationClient);
+ ALOGW_IF(status != NO_ERROR,
+ "AAudioClientTracker::registerClient() linkToDeath = %d\n", status);
+ return AAudioConvert_androidToAAudioResult(status);
+ } else {
+ ALOGW("AAudioClientTracker::registerClient(%d) already registered!", pid);
+ return AAUDIO_OK; // TODO should this be considered an error
+ }
+}
+
+void AAudioClientTracker::unregisterClient(pid_t pid) {
+ ALOGD("AAudioClientTracker::unregisterClient(), calling pid = %d, getpid() = %d\n",
+ pid, getpid());
+ std::lock_guard<std::mutex> lock(mLock);
+ mNotificationClients.erase(pid);
+}
+
+aaudio_result_t
+AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
+ aaudio_result_t result = AAUDIO_OK;
+ ALOGV("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
+ std::lock_guard<std::mutex> lock(mLock);
+ sp<NotificationClient> notificationClient = mNotificationClients[pid];
+ if (notificationClient == 0) {
+ // This will get called the first time the audio server registers an internal stream.
+ ALOGV("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
+ notificationClient = new NotificationClient(pid);
+ mNotificationClients[pid] = notificationClient;
+ }
+ notificationClient->registerClientStream(serviceStream);
+ return result;
+}
+
+// Find the tracker for this process and remove it.
+aaudio_result_t
+AAudioClientTracker::unregisterClientStream(pid_t pid,
+ sp<AAudioServiceStreamBase> serviceStream) {
+ ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+ std::lock_guard<std::mutex> lock(mLock);
+ std::map<pid_t, android::sp<NotificationClient>>::iterator it;
+ it = mNotificationClients.find(pid);
+ if (it != mNotificationClients.end()) {
+ it->second->unregisterClientStream(serviceStream);
+ }
+ return AAUDIO_OK;
+}
+
+AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
+ : mProcessId(pid) {
+ //ALOGD("AAudioClientTracker::NotificationClient(%d) created %p\n", pid, this);
+}
+
+AAudioClientTracker::NotificationClient::~NotificationClient() {
+ //ALOGD("AAudioClientTracker::~NotificationClient() destroyed %p\n", this);
+}
+
+aaudio_result_t AAudioClientTracker::NotificationClient::registerClientStream(
+ sp<AAudioServiceStreamBase> serviceStream) {
+ std::lock_guard<std::mutex> lock(mLock);
+ mStreams.insert(serviceStream);
+ return AAUDIO_OK;
+}
+
+aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream(
+ sp<AAudioServiceStreamBase> serviceStream) {
+ std::lock_guard<std::mutex> lock(mLock);
+ mStreams.erase(serviceStream);
+ return AAUDIO_OK;
+}
+
+// Close any open streams for the client.
+void AAudioClientTracker::NotificationClient::binderDied(const wp<IBinder>& who __unused) {
+ AAudioService *aaudioService = AAudioClientTracker::getInstance().getAAudioService();
+ if (aaudioService != nullptr) {
+ // Copy the current list of streams to another vector because closing them below
+ // will cause unregisterClientStream() calls back to this object.
+ std::set<android::sp<AAudioServiceStreamBase>> streamsToClose;
+
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ ALOGV("AAudioClientTracker::binderDied() pid = %d, # streams = %d\n",
+ mProcessId, (int) mStreams.size());
+ for (auto serviceStream : mStreams) {
+ streamsToClose.insert(serviceStream);
+ }
+ }
+
+ for (auto serviceStream : streamsToClose) {
+ aaudio_handle_t handle = serviceStream->getHandle();
+ ALOGW("AAudioClientTracker::binderDied() close abandoned stream 0x%08X\n", handle);
+ aaudioService->closeStream(handle);
+ }
+ // mStreams should be empty now
+ }
+ sp<NotificationClient> keep(this);
+ AAudioClientTracker::getInstance().unregisterClient(mProcessId);
+}