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 #define LOG_TAG "AAudioEndpointManager"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include <assert.h>
22 #include <functional>
23 #include <map>
24 #include <mutex>
25 #include <sstream>
26 #include <utility/AAudioUtilities.h>
27 #include <media/AidlConversion.h>
28
29 #include "AAudioClientTracker.h"
30 #include "AAudioEndpointManager.h"
31 #include "AAudioServiceEndpointShared.h"
32 #include "AAudioServiceEndpointMMAP.h"
33 #include "AAudioServiceEndpointCapture.h"
34 #include "AAudioServiceEndpointPlay.h"
35
36 using namespace android;
37 using namespace aaudio;
38
39 ANDROID_SINGLETON_STATIC_INSTANCE(AAudioEndpointManager);
40
AAudioEndpointManager()41 AAudioEndpointManager::AAudioEndpointManager()
42 : Singleton<AAudioEndpointManager>()
43 , mSharedStreams()
44 , mExclusiveStreams() {
45 }
46
dump() const47 std::string AAudioEndpointManager::dump() const NO_THREAD_SAFETY_ANALYSIS {
48 std::stringstream result;
49 int index = 0;
50
51 result << "AAudioEndpointManager:" << "\n";
52
53 const bool isSharedLocked = AAudio_tryUntilTrue(
54 [this]()->bool { return mSharedLock.try_lock(); } /* f */,
55 50 /* times */,
56 20 /* sleepMs */);
57 if (!isSharedLocked) {
58 result << "AAudioEndpointManager Shared may be deadlocked\n";
59 }
60
61 {
62 const bool isExclusiveLocked = AAudio_tryUntilTrue(
63 [this]() -> bool { return mExclusiveLock.try_lock(); } /* f */,
64 50 /* times */,
65 20 /* sleepMs */);
66 if (!isExclusiveLocked) {
67 result << "AAudioEndpointManager Exclusive may be deadlocked\n";
68 }
69
70 result << "Exclusive MMAP Endpoints: " << mExclusiveStreams.size() << "\n";
71 index = 0;
72 for (const auto &stream : mExclusiveStreams) {
73 result << " #" << index++ << ":";
74 result << stream->dump() << "\n";
75 }
76
77 result << " ExclusiveSearchCount: " << mExclusiveSearchCount << "\n";
78 result << " ExclusiveFoundCount: " << mExclusiveFoundCount << "\n";
79 result << " ExclusiveOpenCount: " << mExclusiveOpenCount << "\n";
80 result << " ExclusiveCloseCount: " << mExclusiveCloseCount << "\n";
81 result << " ExclusiveStolenCount: " << mExclusiveStolenCount << "\n";
82 result << "\n";
83
84 if (isExclusiveLocked) {
85 mExclusiveLock.unlock();
86 }
87 }
88
89 result << "Shared Endpoints: " << mSharedStreams.size() << "\n";
90 index = 0;
91 for (const auto &stream : mSharedStreams) {
92 result << " #" << index++ << ":";
93 result << stream->dump() << "\n";
94 }
95
96 result << " SharedSearchCount: " << mSharedSearchCount << "\n";
97 result << " SharedFoundCount: " << mSharedFoundCount << "\n";
98 result << " SharedOpenCount: " << mSharedOpenCount << "\n";
99 result << " SharedCloseCount: " << mSharedCloseCount << "\n";
100 result << "\n";
101
102 if (isSharedLocked) {
103 mSharedLock.unlock();
104 }
105 return result.str();
106 }
107
108
109 // Try to find an existing endpoint.
findExclusiveEndpoint_l(const AAudioStreamConfiguration & configuration)110 sp<AAudioServiceEndpoint> AAudioEndpointManager::findExclusiveEndpoint_l(
111 const AAudioStreamConfiguration &configuration) {
112 sp<AAudioServiceEndpoint> endpoint;
113 mExclusiveSearchCount++;
114 for (const auto& ep : mExclusiveStreams) {
115 if (ep->matches(configuration)) {
116 mExclusiveFoundCount++;
117 endpoint = ep;
118 break;
119 }
120 }
121
122 ALOGV("findExclusiveEndpoint_l(), found %p for device = %d, sessionId = %d",
123 endpoint.get(), configuration.getDeviceId(), configuration.getSessionId());
124 return endpoint;
125 }
126
127 // Try to find an existing endpoint.
findSharedEndpoint_l(const AAudioStreamConfiguration & configuration)128 sp<AAudioServiceEndpointShared> AAudioEndpointManager::findSharedEndpoint_l(
129 const AAudioStreamConfiguration &configuration) {
130 sp<AAudioServiceEndpointShared> endpoint;
131 mSharedSearchCount++;
132 for (const auto& ep : mSharedStreams) {
133 if (ep->matches(configuration)) {
134 mSharedFoundCount++;
135 endpoint = ep;
136 break;
137 }
138 }
139
140 ALOGV("findSharedEndpoint_l(), found %p for device = %d, sessionId = %d",
141 endpoint.get(), configuration.getDeviceId(), configuration.getSessionId());
142 return endpoint;
143 }
144
openEndpoint(AAudioService & audioService,const aaudio::AAudioStreamRequest & request)145 sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &audioService,
146 const aaudio::AAudioStreamRequest &request) {
147 if (request.getConstantConfiguration().getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
148 sp<AAudioServiceEndpoint> endpointToSteal;
149 sp<AAudioServiceEndpoint> foundEndpoint =
150 openExclusiveEndpoint(audioService, request, endpointToSteal);
151 if (endpointToSteal.get()) {
152 endpointToSteal->releaseRegisteredStreams(); // free the MMAP resource
153 }
154 return foundEndpoint;
155 } else {
156 return openSharedEndpoint(audioService, request);
157 }
158 }
159
openExclusiveEndpoint(AAudioService & aaudioService,const aaudio::AAudioStreamRequest & request,sp<AAudioServiceEndpoint> & endpointToSteal)160 sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint(
161 AAudioService &aaudioService,
162 const aaudio::AAudioStreamRequest &request,
163 sp<AAudioServiceEndpoint> &endpointToSteal) {
164
165 const std::lock_guard<std::mutex> lock(mExclusiveLock);
166
167 const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
168
169 // Try to find an existing endpoint.
170 sp<AAudioServiceEndpoint> endpoint = findExclusiveEndpoint_l(configuration);
171
172 // If we find an existing one then this one cannot be exclusive.
173 if (endpoint.get() != nullptr) {
174 if (kStealingEnabled
175 && !endpoint->isForSharing() // not currently SHARED
176 && !request.isSharingModeMatchRequired()) { // app did not request a shared stream
177 ALOGD("%s() endpoint in EXCLUSIVE use. Steal it!", __func__);
178 mExclusiveStolenCount++;
179 // Prevent this process from getting another EXCLUSIVE stream.
180 // This will prevent two clients from colliding after a DISCONNECTION
181 // when they both try to open an exclusive stream at the same time.
182 // That can result in a stream getting disconnected between the OPEN
183 // and START calls. This will help preserve app compatibility.
184 // An app can avoid having this happen by closing their streams when
185 // the app is paused.
186 const pid_t pid = VALUE_OR_FATAL(
187 aidl2legacy_int32_t_pid_t(request.getAttributionSource().pid));
188 AAudioClientTracker::getInstance().setExclusiveEnabled(pid, false);
189 endpointToSteal = endpoint; // return it to caller
190 }
191 return nullptr;
192 } else {
193 const sp<AAudioServiceEndpointMMAP> endpointMMap =
194 new AAudioServiceEndpointMMAP(aaudioService);
195 ALOGV("%s(), no match so try to open MMAP %p for dev %d",
196 __func__, endpointMMap.get(), configuration.getDeviceId());
197 endpoint = endpointMMap;
198
199 const aaudio_result_t result = endpoint->open(request);
200 if (result != AAUDIO_OK) {
201 endpoint.clear();
202 } else {
203 mExclusiveStreams.push_back(endpointMMap);
204 mExclusiveOpenCount++;
205 }
206 }
207
208 if (endpoint.get() != nullptr) {
209 // Increment the reference count under this lock.
210 endpoint->setOpenCount(endpoint->getOpenCount() + 1);
211 endpoint->setForSharing(request.isSharingModeMatchRequired());
212 }
213
214 return endpoint;
215 }
216
openSharedEndpoint(AAudioService & aaudioService,const aaudio::AAudioStreamRequest & request)217 sp<AAudioServiceEndpoint> AAudioEndpointManager::openSharedEndpoint(
218 AAudioService &aaudioService,
219 const aaudio::AAudioStreamRequest &request) {
220
221 const std::lock_guard<std::mutex> lock(mSharedLock);
222
223 const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
224 const aaudio_direction_t direction = configuration.getDirection();
225
226 // Try to find an existing endpoint.
227 sp<AAudioServiceEndpointShared> endpoint = findSharedEndpoint_l(configuration);
228
229 // If we can't find an existing one then open a new one.
230 if (endpoint.get() == nullptr) {
231 // we must call openStream with audioserver identity
232 const int64_t token = IPCThreadState::self()->clearCallingIdentity();
233 switch (direction) {
234 case AAUDIO_DIRECTION_INPUT:
235 endpoint = new AAudioServiceEndpointCapture(aaudioService);
236 break;
237 case AAUDIO_DIRECTION_OUTPUT:
238 endpoint = new AAudioServiceEndpointPlay(aaudioService);
239 break;
240 default:
241 break;
242 }
243
244 if (endpoint.get() != nullptr) {
245 const aaudio_result_t result = endpoint->open(request);
246 if (result != AAUDIO_OK) {
247 endpoint.clear();
248 } else {
249 mSharedStreams.push_back(endpoint);
250 mSharedOpenCount++;
251 }
252 }
253 ALOGV("%s(), created endpoint %p, requested device = %d, dir = %d",
254 __func__, endpoint.get(), configuration.getDeviceId(), (int)direction);
255 IPCThreadState::self()->restoreCallingIdentity(token);
256 }
257
258 if (endpoint.get() != nullptr) {
259 // Increment the reference count under this lock.
260 endpoint->setOpenCount(endpoint->getOpenCount() + 1);
261 }
262 return endpoint;
263 }
264
closeEndpoint(const sp<AAudioServiceEndpoint> & serviceEndpoint)265 void AAudioEndpointManager::closeEndpoint(const sp<AAudioServiceEndpoint>& serviceEndpoint) {
266 if (serviceEndpoint->getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
267 return closeExclusiveEndpoint(serviceEndpoint);
268 } else {
269 return closeSharedEndpoint(serviceEndpoint);
270 }
271 }
272
closeExclusiveEndpoint(const sp<AAudioServiceEndpoint> & serviceEndpoint)273 void AAudioEndpointManager::closeExclusiveEndpoint(
274 const sp<AAudioServiceEndpoint>& serviceEndpoint) {
275 if (serviceEndpoint.get() == nullptr) {
276 return;
277 }
278
279 // Decrement the reference count under this lock.
280 const std::lock_guard<std::mutex> lock(mExclusiveLock);
281 const int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
282 serviceEndpoint->setOpenCount(newRefCount);
283
284 // If no longer in use then actually close it.
285 if (newRefCount <= 0) {
286 mExclusiveStreams.erase(
287 std::remove(mExclusiveStreams.begin(), mExclusiveStreams.end(), serviceEndpoint),
288 mExclusiveStreams.end());
289
290 serviceEndpoint->close();
291 mExclusiveCloseCount++;
292 ALOGV("%s() %p for device %d",
293 __func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
294 }
295 }
296
closeSharedEndpoint(const sp<AAudioServiceEndpoint> & serviceEndpoint)297 void AAudioEndpointManager::closeSharedEndpoint(const sp<AAudioServiceEndpoint>& serviceEndpoint) {
298 if (serviceEndpoint.get() == nullptr) {
299 return;
300 }
301
302 // Decrement the reference count under this lock.
303 const std::lock_guard<std::mutex> lock(mSharedLock);
304 const int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
305 serviceEndpoint->setOpenCount(newRefCount);
306
307 // If no longer in use then actually close it.
308 if (newRefCount <= 0) {
309 mSharedStreams.erase(
310 std::remove(mSharedStreams.begin(), mSharedStreams.end(), serviceEndpoint),
311 mSharedStreams.end());
312
313 serviceEndpoint->close();
314
315 mSharedCloseCount++;
316 ALOGV("%s(%p) closed for device %d",
317 __func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
318 }
319 }
320