1 /*
2  * Copyright (C) 2020 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 #define LOG_TAG "FactoryHalHidl"
18 
19 #include <media/audiohal/FactoryHalHidl.h>
20 
21 #include <dlfcn.h>
22 
23 #include <android/hidl/manager/1.0/IServiceManager.h>
24 #include <hidl/ServiceManagement.h>
25 #include <hidl/Status.h>
26 #include <utils/Log.h>
27 
28 namespace android::detail {
29 
30 namespace {
31 /** Supported HAL versions, in order of preference.
32  */
33 const char* sAudioHALVersions[] = {
34     "6.0",
35     "5.0",
36     "4.0",
37     "2.0",
38     nullptr
39 };
40 
createHalService(const std::string & version,const std::string & interface,void ** rawInterface)41 bool createHalService(const std::string& version, const std::string& interface,
42         void** rawInterface) {
43     const std::string libName = "libaudiohal@" + version + ".so";
44     const std::string factoryFunctionName = "create" + interface;
45     constexpr int dlMode = RTLD_LAZY;
46     void* handle = nullptr;
47     dlerror(); // clear
48     handle = dlopen(libName.c_str(), dlMode);
49     if (handle == nullptr) {
50         const char* error = dlerror();
51         ALOGE("Failed to dlopen %s: %s", libName.c_str(),
52                 error != nullptr ? error : "unknown error");
53         return false;
54     }
55     void* (*factoryFunction)();
56     *(void **)(&factoryFunction) = dlsym(handle, factoryFunctionName.c_str());
57     if (!factoryFunction) {
58         const char* error = dlerror();
59         ALOGE("Factory function %s not found in library %s: %s",
60                 factoryFunctionName.c_str(), libName.c_str(),
61                 error != nullptr ? error : "unknown error");
62         dlclose(handle);
63         return false;
64     }
65     *rawInterface = (*factoryFunction)();
66     ALOGW_IF(!*rawInterface, "Factory function %s from %s returned nullptr",
67             factoryFunctionName.c_str(), libName.c_str());
68     return true;
69 }
70 
hasHalService(const std::string & package,const std::string & version,const std::string & interface)71 bool hasHalService(const std::string& package, const std::string& version,
72         const std::string& interface) {
73     using ::android::hidl::manager::V1_0::IServiceManager;
74     sp<IServiceManager> sm = ::android::hardware::defaultServiceManager();
75     if (!sm) {
76         ALOGE("Failed to obtain HIDL ServiceManager");
77         return false;
78     }
79     // Since audio HAL doesn't support multiple clients, avoid instantiating
80     // the interface right away. Instead, query the transport type for it.
81     using ::android::hardware::Return;
82     using Transport = IServiceManager::Transport;
83     const std::string fqName = package + "@" + version + "::" + interface;
84     const std::string instance = "default";
85     Return<Transport> transport = sm->getTransport(fqName, instance);
86     if (!transport.isOk()) {
87         ALOGE("Failed to obtain transport type for %s/%s: %s",
88                 fqName.c_str(), instance.c_str(), transport.description().c_str());
89         return false;
90     }
91     return transport != Transport::EMPTY;
92 }
93 
94 }  // namespace
95 
createPreferredImpl(const std::string & package,const std::string & interface)96 void* createPreferredImpl(const std::string& package, const std::string& interface) {
97     for (auto version = detail::sAudioHALVersions; version != nullptr; ++version) {
98         void* rawInterface = nullptr;
99         if (hasHalService(package, *version, interface)
100                 && createHalService(*version, interface, &rawInterface)) {
101             return rawInterface;
102         }
103     }
104     return nullptr;
105 }
106 
107 }  // namespace android::detail
108