• 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 <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