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