xref: /aosp_15_r20/frameworks/av/services/oboeservice/AAudioEndpointManager.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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 devices = %s, sessionId = %d",
123           endpoint.get(), toString(configuration.getDeviceIds()).c_str(),
124           configuration.getSessionId());
125     return endpoint;
126 }
127 
128 // Try to find an existing endpoint.
findSharedEndpoint_l(const AAudioStreamConfiguration & configuration)129 sp<AAudioServiceEndpointShared> AAudioEndpointManager::findSharedEndpoint_l(
130         const AAudioStreamConfiguration &configuration) {
131     sp<AAudioServiceEndpointShared> endpoint;
132     mSharedSearchCount++;
133     for (const auto& ep  : mSharedStreams) {
134         if (ep->matches(configuration)) {
135             mSharedFoundCount++;
136             endpoint = ep;
137             break;
138         }
139     }
140 
141     ALOGV("findSharedEndpoint_l(), found %p for devices = %s, sessionId = %d",
142           endpoint.get(), toString(configuration.getDeviceIds()).c_str(),
143           configuration.getSessionId());
144     return endpoint;
145 }
146 
openEndpoint(AAudioService & audioService,const aaudio::AAudioStreamRequest & request)147 sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &audioService,
148                                         const aaudio::AAudioStreamRequest &request) {
149     if (request.getConstantConfiguration().getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
150         sp<AAudioServiceEndpoint> endpointToSteal;
151         sp<AAudioServiceEndpoint> foundEndpoint =
152                 openExclusiveEndpoint(audioService, request, endpointToSteal);
153         if (endpointToSteal.get()) {
154             endpointToSteal->releaseRegisteredStreams(); // free the MMAP resource
155         }
156         return foundEndpoint;
157     } else {
158         return openSharedEndpoint(audioService, request);
159     }
160 }
161 
openExclusiveEndpoint(AAudioService & aaudioService,const aaudio::AAudioStreamRequest & request,sp<AAudioServiceEndpoint> & endpointToSteal)162 sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint(
163         AAudioService &aaudioService,
164         const aaudio::AAudioStreamRequest &request,
165         sp<AAudioServiceEndpoint> &endpointToSteal) {
166 
167     const std::lock_guard<std::mutex> lock(mExclusiveLock);
168 
169     const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
170 
171     // Try to find an existing endpoint.
172     sp<AAudioServiceEndpoint> endpoint = findExclusiveEndpoint_l(configuration);
173 
174     // If we find an existing one then this one cannot be exclusive.
175     if (endpoint.get() != nullptr) {
176         if (kStealingEnabled
177                 && !endpoint->isForSharing() // not currently SHARED
178                 && !request.isSharingModeMatchRequired()) { // app did not request a shared stream
179             ALOGD("%s() endpoint in EXCLUSIVE use. Steal it!", __func__);
180             mExclusiveStolenCount++;
181             // Prevent this process from getting another EXCLUSIVE stream.
182             // This will prevent two clients from colliding after a DISCONNECTION
183             // when they both try to open an exclusive stream at the same time.
184             // That can result in a stream getting disconnected between the OPEN
185             // and START calls. This will help preserve app compatibility.
186             // An app can avoid having this happen by closing their streams when
187             // the app is paused.
188             const pid_t pid = VALUE_OR_FATAL(
189                 aidl2legacy_int32_t_pid_t(request.getAttributionSource().pid));
190             AAudioClientTracker::getInstance().setExclusiveEnabled(pid, false);
191             endpointToSteal = endpoint; // return it to caller
192         }
193         return nullptr;
194     } else {
195         const sp<AAudioServiceEndpointMMAP> endpointMMap =
196                 new AAudioServiceEndpointMMAP(aaudioService);
197         ALOGV("%s(), no match so try to open MMAP %p for devices %s",
198               __func__, endpointMMap.get(), toString(configuration.getDeviceIds()).c_str());
199         endpoint = endpointMMap;
200 
201         const aaudio_result_t result = endpoint->open(request);
202         if (result != AAUDIO_OK) {
203             endpoint.clear();
204         } else {
205             mExclusiveStreams.push_back(endpointMMap);
206             mExclusiveOpenCount++;
207         }
208     }
209 
210     if (endpoint.get() != nullptr) {
211         // Increment the reference count under this lock.
212         endpoint->setOpenCount(endpoint->getOpenCount() + 1);
213         endpoint->setForSharing(request.isSharingModeMatchRequired());
214     }
215 
216     return endpoint;
217 }
218 
openSharedEndpoint(AAudioService & aaudioService,const aaudio::AAudioStreamRequest & request)219 sp<AAudioServiceEndpoint> AAudioEndpointManager::openSharedEndpoint(
220         AAudioService &aaudioService,
221         const aaudio::AAudioStreamRequest &request) {
222 
223     const std::lock_guard<std::mutex> lock(mSharedLock);
224 
225     const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
226     const aaudio_direction_t direction = configuration.getDirection();
227 
228     // Try to find an existing endpoint.
229     sp<AAudioServiceEndpointShared> endpoint = findSharedEndpoint_l(configuration);
230 
231     // If we can't find an existing one then open a new one.
232     if (endpoint.get() == nullptr) {
233         // we must call openStream with audioserver identity
234         const int64_t token = IPCThreadState::self()->clearCallingIdentity();
235         switch (direction) {
236             case AAUDIO_DIRECTION_INPUT:
237                 endpoint = new AAudioServiceEndpointCapture(aaudioService);
238                 break;
239             case AAUDIO_DIRECTION_OUTPUT:
240                 endpoint = new AAudioServiceEndpointPlay(aaudioService);
241                 break;
242             default:
243                 break;
244         }
245 
246         if (endpoint.get() != nullptr) {
247             const aaudio_result_t result = endpoint->open(request);
248             if (result != AAUDIO_OK) {
249                 endpoint.clear();
250             } else {
251                 mSharedStreams.push_back(endpoint);
252                 mSharedOpenCount++;
253             }
254         }
255         ALOGV("%s(), created endpoint %p, requested device = %s, dir = %d",
256               __func__, endpoint.get(), android::toString(configuration.getDeviceIds()).c_str(),
257               (int)direction);
258         IPCThreadState::self()->restoreCallingIdentity(token);
259     }
260 
261     if (endpoint.get() != nullptr) {
262         // Increment the reference count under this lock.
263         endpoint->setOpenCount(endpoint->getOpenCount() + 1);
264     }
265     return endpoint;
266 }
267 
closeEndpoint(const sp<AAudioServiceEndpoint> & serviceEndpoint)268 void AAudioEndpointManager::closeEndpoint(const sp<AAudioServiceEndpoint>& serviceEndpoint) {
269     if (serviceEndpoint->getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
270         return closeExclusiveEndpoint(serviceEndpoint);
271     } else {
272         return closeSharedEndpoint(serviceEndpoint);
273     }
274 }
275 
closeExclusiveEndpoint(const sp<AAudioServiceEndpoint> & serviceEndpoint)276 void AAudioEndpointManager::closeExclusiveEndpoint(
277         const sp<AAudioServiceEndpoint>& serviceEndpoint) {
278     if (serviceEndpoint.get() == nullptr) {
279         return;
280     }
281 
282     // Decrement the reference count under this lock.
283     const std::lock_guard<std::mutex> lock(mExclusiveLock);
284     const int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
285     serviceEndpoint->setOpenCount(newRefCount);
286 
287     // If no longer in use then actually close it.
288     if (newRefCount <= 0) {
289         mExclusiveStreams.erase(
290                 std::remove(mExclusiveStreams.begin(), mExclusiveStreams.end(), serviceEndpoint),
291                 mExclusiveStreams.end());
292 
293         serviceEndpoint->close();
294         mExclusiveCloseCount++;
295         ALOGV("%s() %p for devices %s",
296               __func__, serviceEndpoint.get(),
297               android::toString(serviceEndpoint->getDeviceIds()).c_str());
298     }
299 }
300 
closeSharedEndpoint(const sp<AAudioServiceEndpoint> & serviceEndpoint)301 void AAudioEndpointManager::closeSharedEndpoint(const sp<AAudioServiceEndpoint>& serviceEndpoint) {
302     if (serviceEndpoint.get() == nullptr) {
303         return;
304     }
305 
306     // Decrement the reference count under this lock.
307     const std::lock_guard<std::mutex> lock(mSharedLock);
308     const int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
309     serviceEndpoint->setOpenCount(newRefCount);
310 
311     // If no longer in use then actually close it.
312     if (newRefCount <= 0) {
313         mSharedStreams.erase(
314                 std::remove(mSharedStreams.begin(), mSharedStreams.end(), serviceEndpoint),
315                 mSharedStreams.end());
316 
317         serviceEndpoint->close();
318 
319         mSharedCloseCount++;
320         ALOGV("%s(%p) closed for device %s",
321               __func__, serviceEndpoint.get(),
322               android::toString(serviceEndpoint->getDeviceIds()).c_str());
323     }
324 }
325