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