Home | History | Annotate | Download | only in oboeservice
      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 
     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 
     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.
     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")))
     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 
     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 
    112 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