1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <algorithm>
17 #include "hdi_support.h"
18 #include <dlfcn.h>
19 #include <map>
20 #include <mutex>
21 #include <regex>
22 #include <sstream>
23 #include <securec.h>
24 #include <string>
25 #include <unistd.h>
26
27 #include "hdf_base.h"
28 #include "hdf_core_log.h"
29
30 #define HDF_LOG_TAG load_hdi
31
32 namespace {
33 #ifdef __LITEOS__
34 static constexpr const char *HDI_SO_EXTENSION = ".so";
35 #else
36 static constexpr const char *HDI_SO_EXTENSION = ".z.so";
37 #endif
38
39 constexpr size_t INTERFACE_MATCH_RESIZE = 4;
40 constexpr size_t INTERFACE_VERSION_MAJOR_INDEX = 1;
41 constexpr size_t INTERFACE_VERSION_MINOR_INDEX = 2;
42 constexpr size_t INTERFACE_NAME_INDEX = 3;
43 static const std::regex REINFDESC("[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)*\\."
44 "[V|v]([0-9]+)_([0-9]+)\\."
45 "([a-zA-Z_][a-zA-Z0-9_]*)");
46 using HdiImplInstanceFunc = void *(*)(void);
47 using HdiImplReleaseFunc = void (*)(void *);
48 } // namespace
49
TransFileName(const std::string & interfaceName)50 static std::string TransFileName(const std::string &interfaceName)
51 {
52 if (interfaceName.empty()) {
53 return interfaceName;
54 }
55
56 std::string result;
57 for (size_t i = 0; i < interfaceName.size(); i++) {
58 char c = interfaceName[i];
59 if (std::isupper(c) != 0) {
60 if (i > 1) {
61 result += '_';
62 }
63 result += std::tolower(c);
64 } else {
65 result += c;
66 }
67 }
68 return result;
69 }
70
ParseLibName(const std::string & interfaceName,const std::string & serviceName,uint32_t versionMajor,uint32_t versionMinor)71 static std::string ParseLibName(const std::string &interfaceName, const std::string &serviceName,
72 uint32_t versionMajor, uint32_t versionMinor)
73 {
74 std::ostringstream libName;
75 libName << "lib" << interfaceName << "_" << serviceName << "_" << versionMajor << "." << versionMinor;
76 libName << HDI_SO_EXTENSION;
77 return libName.str();
78 }
79
80 struct HdiImpl {
HdiImplHdiImpl81 HdiImpl() : handler(nullptr), constructor(nullptr), destructor(nullptr), useCount(0) {}
82 ~HdiImpl() = default;
UnloadHdiImpl83 void Unload()
84 {
85 if (handler != nullptr) {
86 dlclose(handler);
87 }
88 }
89 void *handler;
90 void *(*constructor)(void);
91 void (*destructor)(void *);
92 uint32_t useCount;
93 };
94
95 static std::map<std::string, HdiImpl> g_hdiConstructorMap;
96 static std::mutex g_loaderMutex;
97
ParseInterface(const std::string & desc,std::string & interface,std::string & libName,const char * serviceName)98 static int32_t ParseInterface(
99 const std::string &desc, std::string &interface, std::string &libName, const char *serviceName)
100 {
101 std::smatch result;
102 if (!std::regex_match(desc, result, REINFDESC)) {
103 return HDF_FAILURE;
104 }
105
106 if (result.size() < INTERFACE_MATCH_RESIZE) {
107 return HDF_FAILURE;
108 }
109
110 const auto &majorVersion = result[INTERFACE_VERSION_MAJOR_INDEX].str();
111 const auto &minorVersion = result[INTERFACE_VERSION_MINOR_INDEX].str();
112
113 bool isNumeric = std::all_of(majorVersion.begin(), majorVersion.end(), ::isdigit);
114 isNumeric = isNumeric && std::all_of(minorVersion.begin(), minorVersion.end(), ::isdigit);
115 if (!isNumeric) {
116 return HDF_FAILURE;
117 }
118
119 uint32_t versionMajor = std::stoul(majorVersion);
120 uint32_t versionMinor = std::stoul(minorVersion);
121 std::string interfaceName = result[INTERFACE_NAME_INDEX];
122
123 interface = interfaceName[0] == 'I' ? interfaceName.substr(1) : interfaceName;
124 if (interface.empty()) {
125 return HDF_FAILURE;
126 }
127
128 libName = ParseLibName(TransFileName(interface), serviceName, versionMajor, versionMinor);
129 return HDF_SUCCESS;
130 }
131
132 /*
133 * service name: xxx_service
134 * interface descriptor name: ohos.hdi.sample.v1_0.IFoo, the last two are version and interface base name
135 * interface: Foo
136 * versionMajor: 1
137 * versionMinor: 0
138 * library name: libfoo_xxx_service_1.0.z.so
139 * method name: FooImplGetInstance
140 */
LoadHdiImpl(const char * desc,const char * serviceName)141 void *LoadHdiImpl(const char *desc, const char *serviceName)
142 {
143 if (desc == nullptr || serviceName == nullptr || strlen(desc) == 0 || strlen(serviceName) == 0) {
144 HDF_LOGE("%{public}s invalid interface descriptor or service name", __func__);
145 return nullptr;
146 }
147
148 std::string interfaceName;
149 std::string libName;
150 if (ParseInterface(desc, interfaceName, libName, serviceName) != HDF_SUCCESS) {
151 HDF_LOGE("failed to parse hdi interface info from '%{public}s'", desc);
152 return nullptr;
153 }
154
155 std::lock_guard<std::mutex> lock(g_loaderMutex);
156 auto constructor = g_hdiConstructorMap.find(libName);
157 if (constructor != g_hdiConstructorMap.end()) {
158 return constructor->second.constructor();
159 }
160
161 HdiImpl hdiImpl;
162 hdiImpl.handler = dlopen(libName.c_str(), RTLD_LAZY);
163 if (hdiImpl.handler == nullptr) {
164 HDF_LOGE("%{public}s failed to dlopen, %{public}s", __func__, dlerror());
165 return nullptr;
166 }
167 std::string symName = interfaceName + "ImplGetInstance";
168 hdiImpl.constructor = reinterpret_cast<HdiImplInstanceFunc>(dlsym(hdiImpl.handler, symName.data()));
169 if (hdiImpl.constructor == nullptr) {
170 HDF_LOGE("%{public}s failed to get symbol of '%{public}s', %{public}s", __func__, symName.c_str(), dlerror());
171 hdiImpl.Unload();
172 return nullptr;
173 }
174 std::string desSymName = interfaceName + "ImplRelease";
175 hdiImpl.destructor = reinterpret_cast<HdiImplReleaseFunc>(dlsym(hdiImpl.handler, desSymName.data()));
176 if (hdiImpl.destructor == nullptr) {
177 HDF_LOGW("%{public}s failed to get symbol of '%{public}s', %{public}s",
178 __func__, desSymName.c_str(), dlerror());
179 }
180
181 void *implInstance = hdiImpl.constructor();
182 if (implInstance == nullptr) {
183 HDF_LOGE("%{public}s no full hdi implementation in %{public}s", __func__, libName.c_str());
184 hdiImpl.Unload();
185 } else {
186 g_hdiConstructorMap.emplace(std::make_pair(libName, std::move(hdiImpl)));
187 }
188 return implInstance;
189 }
190
UnloadHdiImpl(const char * desc,const char * serviceName,void * impl)191 void UnloadHdiImpl(const char *desc, const char *serviceName, void *impl)
192 {
193 if (desc == nullptr || impl == nullptr) {
194 return;
195 }
196
197 std::string interfaceName;
198 std::string libName;
199 if (ParseInterface(desc, interfaceName, libName, serviceName) != HDF_SUCCESS) {
200 HDF_LOGE("%{public}s: failed to parse hdi interface info from '%{public}s'", __func__, desc);
201 return;
202 }
203 std::lock_guard<std::mutex> lock(g_loaderMutex);
204 auto constructor = g_hdiConstructorMap.find(libName);
205 if (constructor != g_hdiConstructorMap.end() && constructor->second.destructor != nullptr) {
206 constructor->second.destructor(impl);
207 }
208 }
209