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