1 /*
2  * Copyright (C) 2016 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 "AAudioStreamTracker"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include <iomanip>
22 #include <iostream>
23 #include <sstream>
24 
25 #include <aaudio/AAudio.h>
26 #include <utils/String16.h>
27 
28 #include "AAudioStreamTracker.h"
29 
30 using namespace android;
31 using namespace aaudio;
32 
decrementAndRemoveStreamByHandle(aaudio_handle_t streamHandle)33 sp<AAudioServiceStreamBase> AAudioStreamTracker::decrementAndRemoveStreamByHandle(
34         aaudio_handle_t streamHandle) {
35     std::lock_guard<std::mutex> lock(mHandleLock);
36     sp<AAudioServiceStreamBase> serviceStream;
37     auto it = mStreamsByHandle.find(streamHandle);
38     if (it != mStreamsByHandle.end()) {
39         sp<AAudioServiceStreamBase> tempStream = it->second;
40         // Does the caller need to close the stream?
41         // The reference count should never be negative.
42         // But it is safer to check for <= 0 than == 0.
43         if ((tempStream->decrementServiceReferenceCount_l() <= 0) && tempStream->isCloseNeeded()) {
44             serviceStream = tempStream; // Only return stream if ready to be closed.
45             mStreamsByHandle.erase(it);
46         }
47     }
48     return serviceStream;
49 }
50 
getStreamByHandleAndIncrement(aaudio_handle_t streamHandle)51 sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandleAndIncrement(
52         aaudio_handle_t streamHandle) {
53     std::lock_guard<std::mutex> lock(mHandleLock);
54     sp<AAudioServiceStreamBase> serviceStream;
55     auto it = mStreamsByHandle.find(streamHandle);
56     if (it != mStreamsByHandle.end()) {
57         serviceStream = it->second;
58         serviceStream->incrementServiceReferenceCount_l();
59     }
60     return serviceStream;
61 }
62 
63 // The port handle is only available when the stream is started.
64 // So we have to iterate over all the streams.
65 // Luckily this rarely happens.
findStreamByPortHandleAndIncrement(audio_port_handle_t portHandle)66 sp<AAudioServiceStreamBase> AAudioStreamTracker::findStreamByPortHandleAndIncrement(
67         audio_port_handle_t portHandle) {
68     std::lock_guard<std::mutex> lock(mHandleLock);
69     sp<AAudioServiceStreamBase> serviceStream;
70     auto it = mStreamsByHandle.begin();
71     while (it != mStreamsByHandle.end()) {
72         auto candidate = it->second;
73         if (candidate->getPortHandle() == portHandle) {
74             serviceStream = candidate;
75             serviceStream->incrementServiceReferenceCount_l();
76             break;
77         }
78         it++;
79     }
80     return serviceStream;
81 }
82 
83 // advance to next legal handle value
84 __attribute__((no_sanitize("integer")))
bumpHandle(aaudio_handle_t handle)85 aaudio_handle_t AAudioStreamTracker::bumpHandle(aaudio_handle_t handle) {
86     handle++;
87     // Only use positive integers.
88     if (handle <= 0) {
89         handle = 1;
90     }
91     return handle;
92 }
93 
addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream)94 aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream) {
95     std::lock_guard<std::mutex> lock(mHandleLock);
96     aaudio_handle_t handle = mPreviousHandle;
97     // Assign a unique handle.
98     while (true) {
99         handle = bumpHandle(handle);
100         sp<AAudioServiceStreamBase> oldServiceStream = mStreamsByHandle[handle];
101         // Is this an unused handle? It would be extremely unlikely to wrap
102         // around and collide with a very old handle. But just in case.
103         if (oldServiceStream.get() == nullptr) {
104             mStreamsByHandle[handle] = serviceStream;
105             break;
106         }
107     }
108     mPreviousHandle = handle;
109     return handle;
110 }
111 
dump() const112 std::string AAudioStreamTracker::dump() const {
113     std::stringstream result;
114     const bool isLocked = AAudio_tryUntilTrue(
115             [this]()->bool { return mHandleLock.try_lock(); } /* f */,
116             50 /* times */,
117             20 /* sleepMs */);
118     if (!isLocked) {
119         result << "AAudioStreamTracker may be deadlocked\n";
120     } else {
121         result << "Stream Handles:\n";
122         for (const auto&  it : mStreamsByHandle) {
123             aaudio_handle_t handle = it.second->getHandle();
124             result << "    0x" << std::setfill('0') << std::setw(8) << std::hex << handle
125                    << std::dec << std::setfill(' ') << "\n";
126         }
127 
128         mHandleLock.unlock();
129     }
130     return result.str();
131 }
132