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