1 /*
2  * Copyright (C) 2019 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 #pragma once
18 
19 #include <unistd.h>
20 
21 #include <map>
22 
23 #include <android-base/logging.h>
24 #include <hwbinder/IPCThreadState.h>
25 
26 // clang-format off
27 #include PATH(android/hardware/audio/FILE_VERSION/IDevice.h)
28 #include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h)
29 #include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h)
30 #include PATH(android/hardware/audio/FILE_VERSION/types.h)
31 #include PATH(android/hardware/audio/common/FILE_VERSION/types.h)
32 // clang-format on
33 
34 #include "utility/ReturnIn.h"
35 
36 using ::android::sp;
37 using namespace ::android::hardware::audio::common::CPP_VERSION;
38 using namespace ::android::hardware::audio::common::test::utility;
39 using namespace ::android::hardware::audio::CPP_VERSION;
40 
41 template <class Derived, class Key, class Interface>
42 class InterfaceManager {
43   public:
getExisting(const Key & name)44     sp<Interface> getExisting(const Key& name) {
45         auto existing = instances.find(name);
46         return existing != instances.end() ? existing->second : sp<Interface>();
47     }
48 
get(const Key & name)49     sp<Interface> get(const Key& name) {
50         auto existing = instances.find(name);
51         if (existing != instances.end()) return existing->second;
52         auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name));
53         return inserted->second;
54     }
55 
56     // The test must check that reset was successful. Reset failure means that the test code
57     // is holding a strong reference to the device.
reset(const Key & name,bool waitForDestruction)58     bool reset(const Key& name, bool waitForDestruction) __attribute__((warn_unused_result)) {
59         auto iter = instances.find(name);
60         if (iter == instances.end()) return true;
61         ::android::wp<Interface> weak = iter->second;
62         instances.erase(iter);
63         if (weak.promote() != nullptr) return false;
64         if (waitForDestruction) {
65             waitForInstanceDestruction();
66         }
67         return true;
68     }
69 
waitForInstanceDestruction()70     static void waitForInstanceDestruction() {
71         // FIXME: there is no way to know when the remote IDevice is being destroyed
72         //        Binder does not support testing if an object is alive, thus
73         //        wait for 100ms to let the binder destruction propagates and
74         //        the remote device has the time to be destroyed.
75         //        flushCommand makes sure all local command are sent, thus should reduce
76         //        the latency between local and remote destruction.
77         ::android::hardware::IPCThreadState::self()->flushCommands();
78         usleep(100 * 1000);
79     }
80 
81   protected:
82     std::map<Key, sp<Interface>> instances;
83 };
84 
85 class DevicesFactoryManager
86     : public InterfaceManager<DevicesFactoryManager, std::string, IDevicesFactory> {
87   public:
getInstance()88     static DevicesFactoryManager& getInstance() {
89         static DevicesFactoryManager instance;
90         return instance;
91     }
createInterfaceInstance(const std::string & name)92     static sp<IDevicesFactory> createInterfaceInstance(const std::string& name) {
93         return IDevicesFactory::getService(name);
94     }
95 };
96 
97 using FactoryAndDevice = std::tuple<std::string, std::string>;
98 class DeviceManager : public InterfaceManager<DeviceManager, FactoryAndDevice, IDevice> {
99   public:
getInstance()100     static DeviceManager& getInstance() {
101         static DeviceManager instance;
102         return instance;
103     }
createInterfaceInstance(const FactoryAndDevice & factoryAndDevice)104     static sp<IDevice> createInterfaceInstance(const FactoryAndDevice& factoryAndDevice) {
105         auto [factoryName, name] = factoryAndDevice;
106         sp<IDevicesFactory> factory = DevicesFactoryManager::getInstance().get(factoryName);
107         return name == kPrimaryDevice ? openPrimaryDevice(factory) : openDevice(factory, name);
108     }
109     using InterfaceManager::reset;
110 
111     static constexpr const char* kPrimaryDevice = "primary";
112 
get(const std::string & factoryName,const std::string & name)113     sp<IDevice> get(const std::string& factoryName, const std::string& name) {
114         return InterfaceManager::get(std::make_tuple(factoryName, name));
115     }
getPrimary(const std::string & factoryName)116     sp<IPrimaryDevice> getPrimary(const std::string& factoryName) {
117         sp<IDevice> device = get(factoryName, kPrimaryDevice);
118         return device != nullptr ? IPrimaryDevice::castFrom(device) : nullptr;
119     }
reset(const std::string & factoryName,const std::string & name)120     bool reset(const std::string& factoryName, const std::string& name)
121             __attribute__((warn_unused_result)) {
122 #if MAJOR_VERSION <= 5
123         return InterfaceManager::reset(std::make_tuple(factoryName, name), true);
124 #elif MAJOR_VERSION >= 6
125         {
126             sp<IDevice> device = getExisting(std::make_tuple(factoryName, name));
127             if (device != nullptr) {
128                 auto ret = device->close();
129                 ALOGE_IF(!ret.isOk(), "Device %s::%s close failed: %s", factoryName.c_str(),
130                          name.c_str(), ret.description().c_str());
131             }
132         }
133         return InterfaceManager::reset(std::make_tuple(factoryName, name), false);
134 #endif
135     }
resetPrimary(const std::string & factoryName)136     bool resetPrimary(const std::string& factoryName) __attribute__((warn_unused_result)) {
137         return reset(factoryName, kPrimaryDevice);
138     }
139 
140   private:
openDevice(const sp<IDevicesFactory> & factory,const std::string & name)141     static sp<IDevice> openDevice(const sp<IDevicesFactory>& factory, const std::string& name) {
142         if (factory == nullptr) return nullptr;
143         sp<IDevice> device;
144 #if MAJOR_VERSION >= 4
145         Result result;
146         auto ret = factory->openDevice(name, returnIn(result, device));
147         if (!ret.isOk() || result != Result::OK || device == nullptr) {
148             ALOGW("Device %s can not be opened, transaction: %s, result %d, device %p",
149                   name.c_str(), ret.description().c_str(), result, device.get());
150             return nullptr;
151         }
152 #else
153         (void)name;
154 #endif
155         return device;
156     }
157 
openPrimaryDevice(const sp<IDevicesFactory> & factory)158     static sp<IDevice> openPrimaryDevice(const sp<IDevicesFactory>& factory) {
159         if (factory == nullptr) return nullptr;
160         Result result;
161         sp<IDevice> device;
162 #if MAJOR_VERSION == 2
163         auto ret = factory->openDevice(IDevicesFactory::Device::PRIMARY, returnIn(result, device));
164 #elif MAJOR_VERSION >= 4
165         auto ret = factory->openPrimaryDevice(returnIn(result, device));
166 #endif
167         if (!ret.isOk() || result != Result::OK || device == nullptr) {
168             ALOGW("Primary device can not be opened, transaction: %s, result %d, device %p",
169                   ret.description().c_str(), result, device.get());
170             return nullptr;
171         }
172         return device;
173     }
174 };
175