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 35 using namespace android; 36 using namespace aaudio; 37 38 ANDROID_SINGLETON_STATIC_INSTANCE(AAudioClientTracker); 39 40 AAudioClientTracker::AAudioClientTracker() 41 : Singleton<AAudioClientTracker>() { 42 } 43 44 std::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. 66 aaudio_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 if (client.get() == nullptr) { 71 ALOGE("AAudioClientTracker::%s() client is NULL!", __func__); 72 android_errorWriteLog(0x534e4554, "116230453"); 73 return AAUDIO_ERROR_NULL; 74 } 75 76 std::lock_guard<std::mutex> lock(mLock); 77 if (mNotificationClients.count(pid) == 0) { 78 sp<NotificationClient> notificationClient = new NotificationClient(pid); 79 mNotificationClients[pid] = notificationClient; 80 81 sp<IBinder> binder = IInterface::asBinder(client); 82 status_t status = binder->linkToDeath(notificationClient); 83 ALOGW_IF(status != NO_ERROR, "registerClient() linkToDeath = %d\n", status); 84 return AAudioConvert_androidToAAudioResult(status); 85 } else { 86 ALOGW("registerClient(%d) already registered!", pid); 87 return AAUDIO_OK; // TODO should this be considered an error 88 } 89 } 90 91 void AAudioClientTracker::unregisterClient(pid_t pid) { 92 ALOGV("unregisterClient(), calling pid = %d, getpid() = %d\n", pid, getpid()); 93 std::lock_guard<std::mutex> lock(mLock); 94 mNotificationClients.erase(pid); 95 } 96 97 int32_t AAudioClientTracker::getStreamCount(pid_t pid) { 98 std::lock_guard<std::mutex> lock(mLock); 99 auto it = mNotificationClients.find(pid); 100 if (it != mNotificationClients.end()) { 101 return it->second->getStreamCount(); 102 } else { 103 return 0; // no existing client 104 } 105 } 106 107 aaudio_result_t 108 AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) { 109 aaudio_result_t result = AAUDIO_OK; 110 ALOGV("registerClientStream(%d,)\n", pid); 111 std::lock_guard<std::mutex> lock(mLock); 112 sp<NotificationClient> notificationClient = mNotificationClients[pid]; 113 if (notificationClient == 0) { 114 // This will get called the first time the audio server registers an internal stream. 115 ALOGV("registerClientStream(%d,) unrecognized pid\n", pid); 116 notificationClient = new NotificationClient(pid); 117 mNotificationClients[pid] = notificationClient; 118 } 119 notificationClient->registerClientStream(serviceStream); 120 return result; 121 } 122 123 // Find the tracker for this process and remove it. 124 aaudio_result_t 125 AAudioClientTracker::unregisterClientStream(pid_t pid, 126 sp<AAudioServiceStreamBase> serviceStream) { 127 ALOGV("unregisterClientStream(%d,)\n", pid); 128 std::lock_guard<std::mutex> lock(mLock); 129 auto it = mNotificationClients.find(pid); 130 if (it != mNotificationClients.end()) { 131 ALOGV("unregisterClientStream(%d,) found NotificationClient\n", pid); 132 it->second->unregisterClientStream(serviceStream); 133 } else { 134 ALOGE("unregisterClientStream(%d,) missing NotificationClient\n", pid); 135 } 136 return AAUDIO_OK; 137 } 138 139 AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid) 140 : mProcessId(pid) { 141 } 142 143 AAudioClientTracker::NotificationClient::~NotificationClient() { 144 } 145 146 int32_t AAudioClientTracker::NotificationClient::getStreamCount() { 147 std::lock_guard<std::mutex> lock(mLock); 148 return mStreams.size(); 149 } 150 151 aaudio_result_t AAudioClientTracker::NotificationClient::registerClientStream( 152 sp<AAudioServiceStreamBase> serviceStream) { 153 std::lock_guard<std::mutex> lock(mLock); 154 mStreams.insert(serviceStream); 155 return AAUDIO_OK; 156 } 157 158 aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream( 159 sp<AAudioServiceStreamBase> serviceStream) { 160 std::lock_guard<std::mutex> lock(mLock); 161 mStreams.erase(serviceStream); 162 return AAUDIO_OK; 163 } 164 165 // Close any open streams for the client. 166 void AAudioClientTracker::NotificationClient::binderDied(const wp<IBinder>& who __unused) { 167 AAudioService *aaudioService = AAudioClientTracker::getInstance().getAAudioService(); 168 if (aaudioService != nullptr) { 169 // Copy the current list of streams to another vector because closing them below 170 // will cause unregisterClientStream() calls back to this object. 171 std::set<sp<AAudioServiceStreamBase>> streamsToClose; 172 173 { 174 std::lock_guard<std::mutex> lock(mLock); 175 for (const auto& serviceStream : mStreams) { 176 streamsToClose.insert(serviceStream); 177 } 178 } 179 180 for (const auto& serviceStream : streamsToClose) { 181 aaudio_handle_t handle = serviceStream->getHandle(); 182 ALOGW("binderDied() close abandoned stream 0x%08X\n", handle); 183 aaudioService->closeStream(handle); 184 } 185 // mStreams should be empty now 186 } 187 sp<NotificationClient> keep(this); 188 AAudioClientTracker::getInstance().unregisterClient(mProcessId); 189 } 190 191 192 std::string AAudioClientTracker::NotificationClient::dump() const { 193 std::stringstream result; 194 const bool isLocked = AAudio_tryUntilTrue( 195 [this]()->bool { return mLock.try_lock(); } /* f */, 196 50 /* times */, 197 20 /* sleepMs */); 198 if (!isLocked) { 199 result << "AAudioClientTracker::NotificationClient may be deadlocked\n"; 200 } 201 202 result << " client: pid = " << mProcessId << " has " << mStreams.size() << " streams\n"; 203 for (const auto& serviceStream : mStreams) { 204 result << " stream: 0x" << std::setfill('0') << std::setw(8) << std::hex 205 << serviceStream->getHandle() 206 << std::dec << std::setfill(' ') << "\n"; 207 } 208 209 if (isLocked) { 210 mLock.unlock(); 211 } 212 return result.str(); 213 } 214