/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #define LOG_TAG "FactoryHal" #include #include #include #include #include #include #include #include #include #include #include "include/media/audiohal/AudioHalVersionInfo.h" #include "include/media/audiohal/FactoryHal.h" namespace android::detail { namespace { using ::android::detail::AudioHalVersionInfo; // The pair of the interface's package name and the interface name, // e.g. <"android.hardware.audio", "IDevicesFactory"> for HIDL, <"android.hardware.audio.core", // "IModule"> for AIDL. // Splitting is used for easier construction of versioned names (FQNs). using InterfaceName = std::pair; /** * Supported HAL versions, from most recent to least recent. * This list need to keep sync with AudioHalVersionInfo.VERSIONS in * media/java/android/media/AudioHalVersionInfo.java. */ static const std::array sAudioHALVersions = { // TODO: remove this comment to get AIDL // AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, 1, 0), AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 7, 1), AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 7, 0), AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 6, 0), AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 5, 0), AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 4, 0), }; static const std::map sDevicesHALInterfaces = { {AudioHalVersionInfo::Type::AIDL, std::make_pair("android.hardware.audio.core", "IModule")}, {AudioHalVersionInfo::Type::HIDL, std::make_pair("android.hardware.audio", "IDevicesFactory")}, }; static const std::map sEffectsHALInterfaces = { {AudioHalVersionInfo::Type::AIDL, std::make_pair("android.hardware.audio.effect", "IFactory")}, {AudioHalVersionInfo::Type::HIDL, std::make_pair("android.hardware.audio.effect", "IEffectsFactory")}, }; bool createHalService(const AudioHalVersionInfo& version, bool isDevice, void** rawInterface) { const std::string libName = "libaudiohal@" + version.toVersionString() + ".so"; const std::string factoryFunctionName = isDevice ? "createIDevicesFactory" : "createIEffectsFactory"; constexpr int dlMode = RTLD_LAZY; void* handle = nullptr; dlerror(); // clear handle = dlopen(libName.c_str(), dlMode); if (handle == nullptr) { const char* error = dlerror(); ALOGE("Failed to dlopen %s: %s", libName.c_str(), error != nullptr ? error : "unknown error"); return false; } void* (*factoryFunction)(); *(void **)(&factoryFunction) = dlsym(handle, factoryFunctionName.c_str()); if (!factoryFunction) { const char* error = dlerror(); ALOGE("Factory function %s not found in library %s: %s", factoryFunctionName.c_str(), libName.c_str(), error != nullptr ? error : "unknown error"); dlclose(handle); return false; } *rawInterface = (*factoryFunction)(); ALOGW_IF(!*rawInterface, "Factory function %s from %s returned nullptr", factoryFunctionName.c_str(), libName.c_str()); return true; } bool hasAidlHalService(const InterfaceName& interface, const AudioHalVersionInfo& version) { const std::string name = interface.first + "." + interface.second + "/default"; const bool isDeclared = AServiceManager_isDeclared(name.c_str()); if (!isDeclared) { ALOGW("%s %s: false", __func__, name.c_str()); return false; } ALOGI("%s %s: true, version %s", __func__, name.c_str(), version.toString().c_str()); return true; } bool hasHidlHalService(const InterfaceName& interface, const AudioHalVersionInfo& version) { using ::android::hidl::manager::V1_0::IServiceManager; sp sm = ::android::hardware::defaultServiceManager(); if (!sm) { ALOGW("Failed to obtain HIDL ServiceManager"); return false; } // Since audio HAL doesn't support multiple clients, avoid instantiating // the interface right away. Instead, query the transport type for it. using ::android::hardware::Return; using Transport = IServiceManager::Transport; const std::string fqName = interface.first + "@" + version.toVersionString() + "::" + interface.second; const std::string instance = "default"; Return transport = sm->getTransport(fqName, instance); if (!transport.isOk()) { ALOGW("Failed to obtain transport type for %s/%s: %s", fqName.c_str(), instance.c_str(), transport.description().c_str()); return false; } return transport != Transport::EMPTY; } bool hasHalService(const InterfaceName& interface, const AudioHalVersionInfo& version) { auto halType = version.getType(); if (halType == AudioHalVersionInfo::Type::AIDL) { return hasAidlHalService(interface, version); } else if (halType == AudioHalVersionInfo::Type::HIDL) { return hasHidlHalService(interface, version); } else { ALOGE("HalType not supported %s", version.toString().c_str()); return false; } } } // namespace void *createPreferredImpl(bool isDevice) { auto findMostRecentVersion = [](const auto& iMap) { return std::find_if(sAudioHALVersions.begin(), sAudioHALVersions.end(), [iMap](const auto& v) { auto iface = iMap.find(v.getType()); return hasHalService(iface->second, v); }); }; auto interfaceMap = isDevice ? sDevicesHALInterfaces : sEffectsHALInterfaces; auto siblingInterfaceMap = isDevice ? sEffectsHALInterfaces : sDevicesHALInterfaces; auto ifaceVersionIt = findMostRecentVersion(interfaceMap); auto siblingVersionIt = findMostRecentVersion(siblingInterfaceMap); if (ifaceVersionIt != sAudioHALVersions.end() && siblingVersionIt != sAudioHALVersions.end() && // same HAL type (HIDL/AIDL) and same major version ifaceVersionIt->getType() == siblingVersionIt->getType() && ifaceVersionIt->getMajorVersion() == siblingVersionIt->getMajorVersion()) { void* rawInterface; if (createHalService(std::max(*ifaceVersionIt, *siblingVersionIt), isDevice, &rawInterface)) { return rawInterface; } else { ALOGE("Failed to create HAL services with major %s, sibling %s!", ifaceVersionIt->toString().c_str(), siblingVersionIt->toString().c_str()); } } else { ALOGE("Found no HAL version, main(%s) %s %s!", isDevice ? "Device" : "Effect", (ifaceVersionIt == sAudioHALVersions.end()) ? "null" : ifaceVersionIt->toString().c_str(), (siblingVersionIt == sAudioHALVersions.end()) ? "null" : siblingVersionIt->toString().c_str()); } return nullptr; } } // namespace android::detail