| /* |
| * Copyright (C) 2020 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. |
| */ |
| |
| #define LOG_TAG "FactoryHalHidl" |
| |
| #include <algorithm> |
| #include <array> |
| #include <utility> |
| |
| #include <media/audiohal/FactoryHalHidl.h> |
| |
| #include <dlfcn.h> |
| |
| #include <android/hidl/manager/1.0/IServiceManager.h> |
| #include <hidl/ServiceManagement.h> |
| #include <hidl/Status.h> |
| #include <utils/Log.h> |
| |
| namespace android::detail { |
| |
| namespace { |
| /** Supported HAL versions, from most recent to least recent. |
| */ |
| #define CONC_VERSION(maj, min) #maj "." #min |
| #define DECLARE_VERSION(maj, min) std::make_pair(std::make_pair(maj, min), CONC_VERSION(maj, min)) |
| static constexpr std::array<std::pair<std::pair<int, int>, const char*>, 5> sAudioHALVersions = { |
| DECLARE_VERSION(7, 1), |
| DECLARE_VERSION(7, 0), |
| DECLARE_VERSION(6, 0), |
| DECLARE_VERSION(5, 0), |
| DECLARE_VERSION(4, 0) |
| }; |
| |
| bool createHalService(const std::string& version, const std::string& interface, |
| void** rawInterface) { |
| const std::string libName = "libaudiohal@" + version + ".so"; |
| const std::string factoryFunctionName = "create" + interface; |
| 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 hasHalService(const std::string& package, const std::string& version, |
| const std::string& interface) { |
| using ::android::hidl::manager::V1_0::IServiceManager; |
| sp<IServiceManager> sm = ::android::hardware::defaultServiceManager(); |
| if (!sm) { |
| ALOGE("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 = package + "@" + version + "::" + interface; |
| const std::string instance = "default"; |
| Return<Transport> transport = sm->getTransport(fqName, instance); |
| if (!transport.isOk()) { |
| ALOGE("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; |
| } |
| |
| } // namespace |
| |
| void* createPreferredImpl(const InterfaceName& iface, const InterfaceName& siblingIface) { |
| auto findMostRecentVersion = [](const InterfaceName& iface) { |
| return std::find_if(detail::sAudioHALVersions.begin(), detail::sAudioHALVersions.end(), |
| [&](const auto& v) { return hasHalService(iface.first, v.second, iface.second); }); |
| }; |
| auto ifaceVersionIt = findMostRecentVersion(iface); |
| auto siblingVersionIt = findMostRecentVersion(siblingIface); |
| if (ifaceVersionIt != detail::sAudioHALVersions.end() && |
| siblingVersionIt != detail::sAudioHALVersions.end() && |
| // same major version |
| ifaceVersionIt->first.first == siblingVersionIt->first.first) { |
| std::string libraryVersion = |
| ifaceVersionIt->first >= siblingVersionIt->first ? |
| ifaceVersionIt->second : siblingVersionIt->second; |
| void* rawInterface; |
| if (createHalService(libraryVersion, iface.second, &rawInterface)) { |
| return rawInterface; |
| } |
| } |
| return nullptr; |
| } |
| |
| } // namespace android::detail |