• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "hdi_support.h"
17 #include <dlfcn.h>
18 #include <map>
19 #include <mutex>
20 #include <regex>
21 #include <sstream>
22 #include <securec.h>
23 #include <string>
24 #include <unistd.h>
25 
26 #include "hdf_base.h"
27 #include "hdf_log.h"
28 
29 #define HDF_LOG_TAG load_hdi
30 
31 namespace {
32 #ifdef __LITEOS__
33 static constexpr const char *HDI_SO_EXTENSION = ".so";
34 #else
35 static constexpr const char *HDI_SO_EXTENSION = ".z.so";
36 #endif
37 
38 constexpr size_t INTERFACE_MATCH_RESIZE = 4;
39 constexpr size_t INTERFACE_VERSION_MAJOR_INDEX = 1;
40 constexpr size_t INTERFACE_VERSION_MINOR_INDEX = 2;
41 constexpr size_t INTERFACE_NAME_INDEX = 3;
42 static const std::regex reInfDesc("[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)*\\."
43                                   "[V|v]([0-9]+)_([0-9]+)\\."
44                                   "([a-zA-Z_][a-zA-Z0-9_]*)");
45 using HdiImplInstanceFunc = void *(*)(void);
46 using HdiImplReleaseFunc = void (*)(void *);
47 } // namespace
48 
TransFileName(const std::string & interfaceName)49 static std::string TransFileName(const std::string &interfaceName)
50 {
51     if (interfaceName.empty()) {
52         return interfaceName;
53     }
54 
55     std::string result;
56     for (size_t i = 0; i < interfaceName.size(); i++) {
57         char c = interfaceName[i];
58         if (std::isupper(c) != 0) {
59             if (i > 1) {
60                 result += '_';
61             }
62             result += std::tolower(c);
63         } else {
64             result += c;
65         }
66     }
67     return result;
68 }
69 
ParseLibName(const std::string & interfaceName,const std::string & serviceName,uint32_t versionMajor,uint32_t versionMinor)70 static std::string ParseLibName(const std::string &interfaceName, const std::string &serviceName,
71     uint32_t versionMajor, uint32_t versionMinor)
72 {
73     std::ostringstream libName;
74     libName << "lib" << interfaceName << "_" << serviceName << "_" << versionMajor << "." << versionMinor;
75     libName << HDI_SO_EXTENSION;
76     return libName.str();
77 }
78 
79 struct HdiImpl {
HdiImplHdiImpl80     HdiImpl() : handler(nullptr), constructor(nullptr), destructor(nullptr), useCount(0) {}
81     ~HdiImpl() = default;
UnloadHdiImpl82     void Unload()
83     {
84         if (handler != nullptr) {
85             dlclose(handler);
86         }
87     }
88     void *handler;
89     void *(*constructor)(void);
90     void (*destructor)(void *);
91     uint32_t useCount;
92 };
93 
94 static std::map<std::string, HdiImpl> g_hdiConstructorMap;
95 static std::mutex g_loaderMutex;
96 
ParseInterface(const std::string & desc,std::string & interface,std::string & libName,const char * serviceName)97 static int32_t ParseInterface(
98     const std::string &desc, std::string &interface, std::string &libName, const char *serviceName)
99 {
100     std::smatch result;
101     if (!std::regex_match(desc, result, reInfDesc)) {
102         return HDF_FAILURE;
103     }
104 
105     if (result.size() < INTERFACE_MATCH_RESIZE) {
106         return HDF_FAILURE;
107     }
108 
109     uint32_t versionMajor = std::stoul(result[INTERFACE_VERSION_MAJOR_INDEX]);
110     uint32_t versionMinor = std::stoul(result[INTERFACE_VERSION_MINOR_INDEX]);
111     std::string interfaceName = result[INTERFACE_NAME_INDEX];
112 
113     interface = interfaceName[0] == 'I' ? interfaceName.substr(1) : interfaceName;
114     if (interface.empty()) {
115         return HDF_FAILURE;
116     }
117 
118     libName = ParseLibName(TransFileName(interface), serviceName, versionMajor, versionMinor);
119     return HDF_SUCCESS;
120 }
121 
122 /*
123  * service name: xxx_service
124  * interface descriptor name: ohos.hdi.sample.v1_0.IFoo, the last two are version and interface base name
125  * interface: Foo
126  * versionMajor: 1
127  * versionMinor: 0
128  * library name: libfoo_xxx_service_1.0.z.so
129  * method name: FooImplGetInstance
130  */
LoadHdiImpl(const char * desc,const char * serviceName)131 void *LoadHdiImpl(const char *desc, const char *serviceName)
132 {
133     if (desc == nullptr || serviceName == nullptr || strlen(desc) == 0 || strlen(serviceName) == 0) {
134         HDF_LOGE("%{public}s invalid interface descriptor or service name", __func__);
135         return nullptr;
136     }
137 
138     std::string interfaceName;
139     std::string libName;
140     if (ParseInterface(desc, interfaceName, libName, serviceName) != HDF_SUCCESS) {
141         HDF_LOGE("failed to parse hdi interface info from '%{public}s'", desc);
142         return nullptr;
143     }
144 
145     std::lock_guard<std::mutex> lock(g_loaderMutex);
146     auto constructor = g_hdiConstructorMap.find(libName);
147     if (constructor != g_hdiConstructorMap.end()) {
148         return constructor->second.constructor();
149     }
150 
151     HdiImpl hdiImpl;
152     hdiImpl.handler = dlopen(libName.c_str(), RTLD_LAZY);
153     if (hdiImpl.handler == nullptr) {
154         HDF_LOGE("%{public}s failed to dlopen, %{public}s", __func__, dlerror());
155         return nullptr;
156     }
157     std::string symName = interfaceName + "ImplGetInstance";
158     hdiImpl.constructor = reinterpret_cast<HdiImplInstanceFunc>(dlsym(hdiImpl.handler, symName.data()));
159     if (hdiImpl.constructor == nullptr) {
160         HDF_LOGE("%{public}s failed to get symbol of '%s', %{public}s", __func__, symName.c_str(), dlerror());
161         hdiImpl.Unload();
162         return nullptr;
163     }
164     std::string desSymName = interfaceName + "ImplRelease";
165     hdiImpl.destructor = reinterpret_cast<HdiImplReleaseFunc>(dlsym(hdiImpl.handler, desSymName.data()));
166     if (hdiImpl.destructor == nullptr) {
167         HDF_LOGE("%{public}s failed to get symbol of '%s', %{public}s", __func__, desSymName.c_str(), dlerror());
168     }
169 
170     void *implInstance = hdiImpl.constructor();
171     if (implInstance == nullptr) {
172         HDF_LOGE("%{public}s no full hdi implementation in %{public}s", __func__, libName.c_str());
173         hdiImpl.Unload();
174     } else {
175         g_hdiConstructorMap.emplace(std::make_pair(libName, std::move(hdiImpl)));
176     }
177     return implInstance;
178 }
179 
UnloadHdiImpl(const char * desc,const char * serviceName,void * impl)180 void UnloadHdiImpl(const char *desc, const char *serviceName, void *impl)
181 {
182     if (desc == nullptr || impl == nullptr) {
183         return;
184     }
185 
186     std::string interfaceName;
187     std::string libName;
188     if (ParseInterface(desc, interfaceName, libName, serviceName) != HDF_SUCCESS) {
189         HDF_LOGE("%{public}s: failed to parse hdi interface info from '%{public}s'", __func__, desc);
190         return;
191     }
192     std::lock_guard<std::mutex> lock(g_loaderMutex);
193     auto constructor = g_hdiConstructorMap.find(libName);
194     if (constructor != g_hdiConstructorMap.end() && constructor->second.destructor != nullptr) {
195         constructor->second.destructor(impl);
196     }
197 }
198