1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18#define LOG_TAG "AAudioClientTracker" 19//#define LOG_NDEBUG 0 20#include <utils/Log.h> 21 22#include <assert.h> 23#include <binder/IPCThreadState.h> 24#include <iomanip> 25#include <iostream> 26#include <map> 27#include <mutex> 28#include <utils/Singleton.h> 29 30#include "utility/AAudioUtilities.h" 31#include "AAudioEndpointManager.h" 32#include "AAudioServiceEndpoint.h" 33#include "AAudioClientTracker.h" 34 35using namespace android; 36using namespace aaudio; 37 38ANDROID_SINGLETON_STATIC_INSTANCE(AAudioClientTracker); 39 40AAudioClientTracker::AAudioClientTracker() 41 : Singleton<AAudioClientTracker>() { 42} 43 44std::string AAudioClientTracker::dump() const { 45 std::stringstream result; 46 const bool isLocked = AAudio_tryUntilTrue( 47 [this]()->bool { return mLock.try_lock(); } /* f */, 48 50 /* times */, 49 20 /* sleepMs */); 50 if (!isLocked) { 51 result << "AAudioClientTracker may be deadlocked\n"; 52 } 53 54 result << "AAudioClientTracker:\n"; 55 for (const auto& it : mNotificationClients) { 56 result << it.second->dump(); 57 } 58 59 if (isLocked) { 60 mLock.unlock(); 61 } 62 return result.str(); 63} 64 65// Create a tracker for the client. 66aaudio_result_t AAudioClientTracker::registerClient(pid_t pid, 67 const sp<IAAudioClient>& client) { 68 ALOGV("registerClient(), calling pid = %d, getpid() = %d\n", pid, getpid()); 69 70 std::lock_guard<std::mutex> lock(mLock); 71 if (mNotificationClients.count(pid) == 0) { 72 sp<NotificationClient> notificationClient = new NotificationClient(pid); 73 mNotificationClients[pid] = notificationClient; 74 75 sp<IBinder> binder = IInterface::asBinder(client); 76 status_t status = binder->linkToDeath(notificationClient); 77 ALOGW_IF(status != NO_ERROR, "registerClient() linkToDeath = %d\n", status); 78 return AAudioConvert_androidToAAudioResult(status); 79 } else { 80 ALOGW("registerClient(%d) already registered!", pid); 81 return AAUDIO_OK; // TODO should this be considered an error 82 } 83} 84 85void AAudioClientTracker::unregisterClient(pid_t pid) { 86 ALOGV("unregisterClient(), calling pid = %d, getpid() = %d\n", pid, getpid()); 87 std::lock_guard<std::mutex> lock(mLock); 88 mNotificationClients.erase(pid); 89} 90 91int32_t AAudioClientTracker::getStreamCount(pid_t pid) { 92 std::lock_guard<std::mutex> lock(mLock); 93 auto it = mNotificationClients.find(pid); 94 if (it != mNotificationClients.end()) { 95 return it->second->getStreamCount(); 96 } else { 97 return 0; // no existing client 98 } 99} 100 101aaudio_result_t 102AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) { 103 aaudio_result_t result = AAUDIO_OK; 104 ALOGV("registerClientStream(%d, %p)\n", pid, serviceStream.get()); 105 std::lock_guard<std::mutex> lock(mLock); 106 sp<NotificationClient> notificationClient = mNotificationClients[pid]; 107 if (notificationClient == 0) { 108 // This will get called the first time the audio server registers an internal stream. 109 ALOGV("registerClientStream(%d,) unrecognized pid\n", pid); 110 notificationClient = new NotificationClient(pid); 111 mNotificationClients[pid] = notificationClient; 112 } 113 notificationClient->registerClientStream(serviceStream); 114 return result; 115} 116 117// Find the tracker for this process and remove it. 118aaudio_result_t 119AAudioClientTracker::unregisterClientStream(pid_t pid, 120 sp<AAudioServiceStreamBase> serviceStream) { 121 ALOGV("unregisterClientStream(%d, %p)\n", pid, serviceStream.get()); 122 std::lock_guard<std::mutex> lock(mLock); 123 auto it = mNotificationClients.find(pid); 124 if (it != mNotificationClients.end()) { 125 ALOGV("unregisterClientStream(%d, %p) found NotificationClient\n", 126 pid, serviceStream.get()); 127 it->second->unregisterClientStream(serviceStream); 128 } else { 129 ALOGE("unregisterClientStream(%d, %p) missing NotificationClient\n", 130 pid, serviceStream.get()); 131 } 132 return AAUDIO_OK; 133} 134 135AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid) 136 : mProcessId(pid) { 137 //ALOGD("NotificationClient(%d) created %p\n", pid, this); 138} 139 140AAudioClientTracker::NotificationClient::~NotificationClient() { 141 //ALOGD("~NotificationClient() destroyed %p\n", this); 142} 143 144int32_t AAudioClientTracker::NotificationClient::getStreamCount() { 145 std::lock_guard<std::mutex> lock(mLock); 146 return mStreams.size(); 147} 148 149aaudio_result_t AAudioClientTracker::NotificationClient::registerClientStream( 150 sp<AAudioServiceStreamBase> serviceStream) { 151 std::lock_guard<std::mutex> lock(mLock); 152 mStreams.insert(serviceStream); 153 return AAUDIO_OK; 154} 155 156aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream( 157 sp<AAudioServiceStreamBase> serviceStream) { 158 std::lock_guard<std::mutex> lock(mLock); 159 mStreams.erase(serviceStream); 160 return AAUDIO_OK; 161} 162 163// Close any open streams for the client. 164void AAudioClientTracker::NotificationClient::binderDied(const wp<IBinder>& who __unused) { 165 AAudioService *aaudioService = AAudioClientTracker::getInstance().getAAudioService(); 166 if (aaudioService != nullptr) { 167 // Copy the current list of streams to another vector because closing them below 168 // will cause unregisterClientStream() calls back to this object. 169 std::set<sp<AAudioServiceStreamBase>> streamsToClose; 170 171 { 172 std::lock_guard<std::mutex> lock(mLock); 173 for (const auto& serviceStream : mStreams) { 174 streamsToClose.insert(serviceStream); 175 } 176 } 177 178 for (const auto& serviceStream : streamsToClose) { 179 aaudio_handle_t handle = serviceStream->getHandle(); 180 ALOGW("binderDied() close abandoned stream 0x%08X\n", handle); 181 aaudioService->closeStream(handle); 182 } 183 // mStreams should be empty now 184 } 185 sp<NotificationClient> keep(this); 186 AAudioClientTracker::getInstance().unregisterClient(mProcessId); 187} 188 189 190std::string AAudioClientTracker::NotificationClient::dump() const { 191 std::stringstream result; 192 const bool isLocked = AAudio_tryUntilTrue( 193 [this]()->bool { return mLock.try_lock(); } /* f */, 194 50 /* times */, 195 20 /* sleepMs */); 196 if (!isLocked) { 197 result << "AAudioClientTracker::NotificationClient may be deadlocked\n"; 198 } 199 200 result << " client: pid = " << mProcessId << " has " << mStreams.size() << " streams\n"; 201 for (const auto& serviceStream : mStreams) { 202 result << " stream: 0x" << std::setfill('0') << std::setw(8) << std::hex 203 << serviceStream->getHandle() 204 << std::dec << std::setfill(' ') << "\n"; 205 } 206 207 if (isLocked) { 208 mLock.unlock(); 209 } 210 return result.str(); 211} 212