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