Home | History | Annotate | Download | only in oboeservice
      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 
     18 #define LOG_TAG "AAudioClientTracker"
     19 //#define LOG_NDEBUG 0
     20 #include <utils/Log.h>
     21 
     22 #include <assert.h>
     23 #include <binder/IPCThreadState.h>
     24 #include <iomanip>
     25 #include <iostream>
     26 #include <map>
     27 #include <mutex>
     28 #include <utils/Singleton.h>
     29 
     30 #include "utility/AAudioUtilities.h"
     31 #include "AAudioEndpointManager.h"
     32 #include "AAudioServiceEndpoint.h"
     33 #include "AAudioClientTracker.h"
     34 
     35 using namespace android;
     36 using namespace aaudio;
     37 
     38 ANDROID_SINGLETON_STATIC_INSTANCE(AAudioClientTracker);
     39 
     40 AAudioClientTracker::AAudioClientTracker()
     41         : Singleton<AAudioClientTracker>() {
     42 }
     43 
     44 std::string AAudioClientTracker::dump() const {
     45     std::stringstream result;
     46     const bool isLocked = AAudio_tryUntilTrue(
     47             [this]()->bool { return mLock.try_lock(); } /* f */,
     48             50 /* times */,
     49             20 /* sleepMs */);
     50     if (!isLocked) {
     51         result << "AAudioClientTracker may be deadlocked\n";
     52     }
     53 
     54     result << "AAudioClientTracker:\n";
     55     for (const auto&  it : mNotificationClients) {
     56         result << it.second->dump();
     57     }
     58 
     59     if (isLocked) {
     60         mLock.unlock();
     61     }
     62     return result.str();
     63 }
     64 
     65 // Create a tracker for the client.
     66 aaudio_result_t AAudioClientTracker::registerClient(pid_t pid,
     67                                          const sp<IAAudioClient>& client) {
     68     ALOGV("registerClient(), calling pid = %d, getpid() = %d\n", pid, getpid());
     69 
     70     std::lock_guard<std::mutex> lock(mLock);
     71     if (mNotificationClients.count(pid) == 0) {
     72         sp<NotificationClient> notificationClient = new NotificationClient(pid);
     73         mNotificationClients[pid] = notificationClient;
     74 
     75         sp<IBinder> binder = IInterface::asBinder(client);
     76         status_t status = binder->linkToDeath(notificationClient);
     77         ALOGW_IF(status != NO_ERROR, "registerClient() linkToDeath = %d\n", status);
     78         return AAudioConvert_androidToAAudioResult(status);
     79     } else {
     80         ALOGW("registerClient(%d) already registered!", pid);
     81         return AAUDIO_OK; // TODO should this be considered an error
     82     }
     83 }
     84 
     85 void AAudioClientTracker::unregisterClient(pid_t pid) {
     86     ALOGV("unregisterClient(), calling pid = %d, getpid() = %d\n", pid, getpid());
     87     std::lock_guard<std::mutex> lock(mLock);
     88     mNotificationClients.erase(pid);
     89 }
     90 
     91 int32_t AAudioClientTracker::getStreamCount(pid_t pid) {
     92     std::lock_guard<std::mutex> lock(mLock);
     93     auto it = mNotificationClients.find(pid);
     94     if (it != mNotificationClients.end()) {
     95         return it->second->getStreamCount();
     96     } else {
     97         return 0; // no existing client
     98     }
     99 }
    100 
    101 aaudio_result_t
    102 AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
    103     aaudio_result_t result = AAUDIO_OK;
    104     ALOGV("registerClientStream(%d, %p)\n", pid, serviceStream.get());
    105     std::lock_guard<std::mutex> lock(mLock);
    106     sp<NotificationClient> notificationClient = mNotificationClients[pid];
    107     if (notificationClient == 0) {
    108         // This will get called the first time the audio server registers an internal stream.
    109         ALOGV("registerClientStream(%d,) unrecognized pid\n", pid);
    110         notificationClient = new NotificationClient(pid);
    111         mNotificationClients[pid] = notificationClient;
    112     }
    113     notificationClient->registerClientStream(serviceStream);
    114     return result;
    115 }
    116 
    117 // Find the tracker for this process and remove it.
    118 aaudio_result_t
    119 AAudioClientTracker::unregisterClientStream(pid_t pid,
    120                                             sp<AAudioServiceStreamBase> serviceStream) {
    121     ALOGV("unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
    122     std::lock_guard<std::mutex> lock(mLock);
    123     auto it = mNotificationClients.find(pid);
    124     if (it != mNotificationClients.end()) {
    125         ALOGV("unregisterClientStream(%d, %p) found NotificationClient\n",
    126               pid, serviceStream.get());
    127         it->second->unregisterClientStream(serviceStream);
    128     } else {
    129         ALOGE("unregisterClientStream(%d, %p) missing NotificationClient\n",
    130               pid, serviceStream.get());
    131     }
    132     return AAUDIO_OK;
    133 }
    134 
    135 AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
    136         : mProcessId(pid) {
    137     //ALOGD("NotificationClient(%d) created %p\n", pid, this);
    138 }
    139 
    140 AAudioClientTracker::NotificationClient::~NotificationClient() {
    141     //ALOGD("~NotificationClient() destroyed %p\n", this);
    142 }
    143 
    144 int32_t AAudioClientTracker::NotificationClient::getStreamCount() {
    145     std::lock_guard<std::mutex> lock(mLock);
    146     return mStreams.size();
    147 }
    148 
    149 aaudio_result_t AAudioClientTracker::NotificationClient::registerClientStream(
    150         sp<AAudioServiceStreamBase> serviceStream) {
    151     std::lock_guard<std::mutex> lock(mLock);
    152     mStreams.insert(serviceStream);
    153     return AAUDIO_OK;
    154 }
    155 
    156 aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream(
    157         sp<AAudioServiceStreamBase> serviceStream) {
    158     std::lock_guard<std::mutex> lock(mLock);
    159     mStreams.erase(serviceStream);
    160     return AAUDIO_OK;
    161 }
    162 
    163 // Close any open streams for the client.
    164 void AAudioClientTracker::NotificationClient::binderDied(const wp<IBinder>& who __unused) {
    165     AAudioService *aaudioService = AAudioClientTracker::getInstance().getAAudioService();
    166     if (aaudioService != nullptr) {
    167         // Copy the current list of streams to another vector because closing them below
    168         // will cause unregisterClientStream() calls back to this object.
    169         std::set<sp<AAudioServiceStreamBase>>  streamsToClose;
    170 
    171         {
    172             std::lock_guard<std::mutex> lock(mLock);
    173             for (const auto& serviceStream : mStreams) {
    174                 streamsToClose.insert(serviceStream);
    175             }
    176         }
    177 
    178         for (const auto& serviceStream : streamsToClose) {
    179             aaudio_handle_t handle = serviceStream->getHandle();
    180             ALOGW("binderDied() close abandoned stream 0x%08X\n", handle);
    181             aaudioService->closeStream(handle);
    182         }
    183         // mStreams should be empty now
    184     }
    185     sp<NotificationClient> keep(this);
    186     AAudioClientTracker::getInstance().unregisterClient(mProcessId);
    187 }
    188 
    189 
    190 std::string AAudioClientTracker::NotificationClient::dump() const {
    191     std::stringstream result;
    192     const bool isLocked = AAudio_tryUntilTrue(
    193             [this]()->bool { return mLock.try_lock(); } /* f */,
    194             50 /* times */,
    195             20 /* sleepMs */);
    196     if (!isLocked) {
    197         result << "AAudioClientTracker::NotificationClient may be deadlocked\n";
    198     }
    199 
    200     result << "  client: pid = " << mProcessId << " has " << mStreams.size() << " streams\n";
    201     for (const auto& serviceStream : mStreams) {
    202         result << "     stream: 0x" << std::setfill('0') << std::setw(8) << std::hex
    203                << serviceStream->getHandle()
    204                << std::dec << std::setfill(' ') << "\n";
    205     }
    206 
    207     if (isLocked) {
    208         mLock.unlock();
    209     }
    210     return result.str();
    211 }
    212