• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "BusDeviceProvider.h"
16 
17 #include <utils/Log.h>
18 
19 #include <algorithm>
20 
21 #include "DummyBusDevice.h"
22 
23 #undef LOG_TAG
24 #define LOG_TAG "BusDeviceProvider"
25 
26 namespace audio_proxy {
27 namespace service {
28 
29 class BusDeviceProvider::DeathRecipient : public hidl_death_recipient {
30  public:
DeathRecipient(BusDeviceProvider & owner)31   explicit DeathRecipient(BusDeviceProvider& owner) : mOwner(owner) {}
32   ~DeathRecipient() override = default;
33 
serviceDied(uint64_t token,const android::wp<::android::hidl::base::V1_0::IBase> & who)34   void serviceDied(
35       uint64_t token,
36       const android::wp<::android::hidl::base::V1_0::IBase>& who) override {
37     sp<BusDeviceProvider::Handle> handle = mOwner.removeByToken(token);
38 
39     // If the stopped client still has opened stream, audioserver may still hold
40     // a dead IStreamOut object. This may prevent the client to create a new
41     // IStreamOut when it's rebooted. Crash the audioserver as a temporary
42     // solution to fix this.
43     if (handle && handle->getStreamCount() > 0) {
44       ALOGW("Device at %s crashed with opened stream. Crash audioserver.",
45             handle->getAddress().c_str());
46       // Avoid calling atexit handlers, as this code runs on a thread from RPC
47       // threadpool.
48       _exit(-3);
49     }
50   }
51 
52  private:
53   BusDeviceProvider& mOwner;
54 };
55 
Handle(sp<IBusDevice> device,const hidl_string & address,uint64_t token)56 BusDeviceProvider::Handle::Handle(sp<IBusDevice> device,
57                                   const hidl_string& address,
58                                   uint64_t token)
59   : mDevice(std::move(device)),
60     mAddress(address),
61     mToken(token) {}
62 
63 BusDeviceProvider::Handle::~Handle() = default;
64 
getDevice() const65 const sp<IBusDevice>& BusDeviceProvider::Handle::getDevice() const {
66   return mDevice;
67 }
68 
getAddress() const69 const hidl_string& BusDeviceProvider::Handle::getAddress() const {
70   return mAddress;
71 }
72 
getToken() const73 uint64_t BusDeviceProvider::Handle::getToken() const {
74   return mToken;
75 }
76 
getStreamCount() const77 int BusDeviceProvider::Handle::getStreamCount() const {
78   return mStreamCount;
79 }
80 
onStreamOpen()81 void BusDeviceProvider::Handle::onStreamOpen() {
82   mStreamCount++;
83 }
84 
onStreamClose()85 void BusDeviceProvider::Handle::onStreamClose() {
86   mStreamCount--;
87 }
88 
BusDeviceProvider()89 BusDeviceProvider::BusDeviceProvider()
90     : mDeathRecipient(new DeathRecipient(*this)) {}
91 BusDeviceProvider::~BusDeviceProvider() = default;
92 
add(const hidl_string & address,sp<IBusDevice> device)93 bool BusDeviceProvider::add(const hidl_string& address, sp<IBusDevice> device) {
94   std::lock_guard<std::mutex> guard(mDevicesLock);
95   auto it = std::find_if(mBusDevices.begin(), mBusDevices.end(),
96                          [&address](const sp<Handle>& handle) {
97                            return handle->getAddress() == address;
98                          });
99 
100   if (it != mBusDevices.end()) {
101     return false;
102   }
103 
104   uint64_t token = mNextToken++;
105 
106   mBusDevices.emplace_back(new Handle(device, address, token));
107 
108   device->linkToDeath(mDeathRecipient, token);
109 
110   return true;
111 }
112 
get(const hidl_string & address)113 sp<BusDeviceProvider::Handle> BusDeviceProvider::get(const hidl_string& address) {
114   std::lock_guard<std::mutex> guard(mDevicesLock);
115   auto it = std::find_if(mBusDevices.begin(), mBusDevices.end(),
116                          [&address](const sp<Handle>& handle) {
117                            return handle->getAddress() == address;
118                          });
119 
120   if (it == mBusDevices.end()) {
121     // When AudioPolicyManager first opens this HAL, it iterates through the
122     // devices and quickly opens and closes the first device (as specified in
123     // the audio configuration .xml). However, it is possible that the first
124     // device has not registered with the audio proxy HAL yet. In this case, we
125     // will return a dummy device, which is going to create a dummy output
126     // stream. Since this HAL only supports direct outputs, the dummy output
127     // will be immediately closed until it is reopened on use -- and by that
128     // time the actual device must have registered itself.
129     return new Handle(new DummyBusDevice(), "placeholder", 1234);
130   }
131 
132   return *it;
133 }
134 
removeAll()135 void BusDeviceProvider::removeAll() {
136   std::lock_guard<std::mutex> guard(mDevicesLock);
137   mBusDevices.clear();
138 }
139 
removeByToken(uint64_t token)140 sp<BusDeviceProvider::Handle> BusDeviceProvider::removeByToken(uint64_t token) {
141   std::lock_guard<std::mutex> guard(mDevicesLock);
142   auto it = std::find_if(mBusDevices.begin(), mBusDevices.end(),
143                          [token](const sp<Handle>& handle) {
144                            return handle->getToken() == token;
145                          });
146 
147   if (it == mBusDevices.end()) {
148     return nullptr;
149   }
150 
151   sp<Handle> handle = std::move(*it);
152   mBusDevices.erase(it);
153   return handle;
154 }
155 
156 }  // namespace service
157 }  // namespace audio_proxy
158