Update libaudiohal with AudioHalVersionInfo

Bug: 261129656
Test: atest VtsHalAudioEffectTargetTest
Flash to Cuttlefish and Panther and check audio.

Change-Id: Ieace37b25dc03d50048b35b1c63b4ec5f39257c8
diff --git a/media/libaudiohal/FactoryHal.cpp b/media/libaudiohal/FactoryHal.cpp
new file mode 100644
index 0000000..16d591c
--- /dev/null
+++ b/media/libaudiohal/FactoryHal.cpp
@@ -0,0 +1,189 @@
+/*
+ * 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 <map>
+#include <memory>
+#define LOG_TAG "FactoryHal"
+
+#include <algorithm>
+#include <array>
+#include <cstddef>
+#include <dlfcn.h>
+#include <utility>
+
+#include <android/binder_manager.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+#include <utils/Log.h>
+
+#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<std::string, std::string>;
+
+/**
+ * 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<AudioHalVersionInfo, 5> 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<AudioHalVersionInfo::Type, InterfaceName> 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<AudioHalVersionInfo::Type, InterfaceName> 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";
+    AIBinder* binder = AServiceManager_checkService(name.c_str());
+    if (binder == nullptr) {
+        ALOGW("%s Service %s doesn't exist", __func__, name.c_str());
+        return false;
+    }
+    ALOGI("%s AIDL Service %s exist: %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<IServiceManager> 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> 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 (version.getType() == 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 major version
+        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