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