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 "egl_wrapper_loader.h"
17 
18 #include <dlfcn.h>
19 #include <string>
20 
21 #include "directory_ex.h"
22 
23 #include "egl_defs.h"
24 #include "wrapper_log.h"
25 
26 using namespace OHOS;
27 namespace OHOS {
28 namespace {
29 #if (defined(__aarch64__) || defined(__x86_64__))
30     constexpr const char *VENDOR_LIB_PATH = "/vendor/lib64/chipsetsdk/";
31     constexpr const char *SYSTEM_LIB_PATH = "/system/lib64/";
32 #else
33     constexpr const char *VENDOR_LIB_PATH = "/vendor/lib/chipsetsdk/";
34     constexpr const char *SYSTEM_LIB_PATH = "/system/lib/";
35 #endif
36 constexpr const char *LIB_EGL_NAME = "libEGL_impl.so";
37 constexpr const char *LIB_GLESV1_NAME = "libGLESv1_impl.so";
38 constexpr const char *LIB_GLESV2_NAME = "libGLESv2_impl.so";
39 constexpr const char *LIB_GLESV3_NAME = "libGLESv3_impl.so";
40 }
41 
GetInstance()42 EglWrapperLoader& EglWrapperLoader::GetInstance()
43 {
44     static EglWrapperLoader loader;
45     return loader;
46 }
47 
~EglWrapperLoader()48 EglWrapperLoader::~EglWrapperLoader()
49 {
50     WLOGD("");
51 }
52 
53 using GetProcAddressType = FunctionPointerType (*)(const char *);
LoadEgl(const char * libName,EglHookTable * table)54 bool EglWrapperLoader::LoadEgl(const char* libName, EglHookTable* table)
55 {
56     WLOGD("");
57     std::string path = std::string(VENDOR_LIB_PATH) + std::string(libName);
58     std::string realPath = "";
59     if (!PathToRealPath(path, realPath) ||
60         strncmp(realPath.c_str(), VENDOR_LIB_PATH, strlen(VENDOR_LIB_PATH)) != 0) {
61         WLOGD("Vendor path is invalid or not within vendor directory: %{private}s", path.c_str());
62         dlEglHandle_ = nullptr;
63     } else {
64         dlEglHandle_ = dlopen(realPath.c_str(), RTLD_NOW | RTLD_LOCAL);
65     }
66     if (dlEglHandle_ == nullptr) {
67         path = std::string(SYSTEM_LIB_PATH) + std::string(libName);
68         if (!PathToRealPath(path, realPath) ||
69             strncmp(realPath.c_str(), SYSTEM_LIB_PATH, strlen(SYSTEM_LIB_PATH)) != 0) {
70             WLOGE("System path is invalid or not within system directory: %{private}s", path.c_str());
71             return false;
72         }
73         dlEglHandle_ = dlopen(realPath.c_str(), RTLD_NOW | RTLD_LOCAL);
74         if (dlEglHandle_ == nullptr) {
75             WLOGE("dlopen failed. error: %{public}s.", dlerror());
76             return false;
77         }
78     }
79 
80     GetProcAddressType getProcAddr =
81         (GetProcAddressType)dlsym(dlEglHandle_, "eglGetProcAddress");
82     if (getProcAddr == nullptr) {
83         WLOGE("can't find eglGetProcAddress() in EGL driver library.");
84         return false;
85     }
86 
87     FunctionPointerType *current = (FunctionPointerType *)table;
88     char const * const *api = gEglApiNames;
89     while (*api) {
90         char const *name = *api;
91         FunctionPointerType func = (FunctionPointerType)dlsym(dlEglHandle_, name);
92         if (func == nullptr) {
93             WLOGD("try to getProcAddr %{public}s.", name);
94             func = getProcAddr(name);
95             if (func == nullptr) {
96                 WLOGD("couldn't find the entry-point: %{public}s.", name);
97             }
98         }
99 
100         *current++ = func;
101         api++;
102     }
103 
104     return true;
105 }
106 
LoadGl(const char * libName,char const * const * glName,FunctionPointerType * entry)107 void *EglWrapperLoader::LoadGl(const char *libName, char const * const *glName, FunctionPointerType *entry)
108 {
109     WLOGD("");
110     std::string path = std::string(VENDOR_LIB_PATH) + std::string(libName);
111     std::string realPath = "";
112     void *dlHandle = nullptr;
113     if (!PathToRealPath(path, realPath) ||
114         strncmp(realPath.c_str(), VENDOR_LIB_PATH, strlen(VENDOR_LIB_PATH)) != 0) {
115         WLOGD("Vendor path is invalid or not within vendor directory: %{private}s", path.c_str());
116     } else {
117         dlHandle = dlopen(realPath.c_str(), RTLD_NOW | RTLD_LOCAL);
118     }
119     if (dlHandle == nullptr) {
120         path = std::string(SYSTEM_LIB_PATH) + std::string(libName);
121         if (!PathToRealPath(path, realPath) ||
122             strncmp(realPath.c_str(), SYSTEM_LIB_PATH, strlen(SYSTEM_LIB_PATH)) != 0) {
123             WLOGE("System path is invalid or not within system directory: %{private}s", path.c_str());
124             return nullptr;
125         }
126         dlHandle = dlopen(realPath.c_str(), RTLD_NOW | RTLD_LOCAL);
127         if (dlHandle == nullptr) {
128             WLOGE("dlopen failed. error: %{public}s.", dlerror());
129             return nullptr;
130         }
131     }
132 
133     GetProcAddressType getProcAddr =
134         (GetProcAddressType)dlsym(dlEglHandle_, "eglGetProcAddress");
135     if (getProcAddr == nullptr) {
136         WLOGE("can't find eglGetProcAddress() in EGL driver library.");
137         return nullptr;
138     }
139 
140     FunctionPointerType *current = entry;
141     char const * const *api = glName;
142     while (*api) {
143         char const *name = *api;
144         FunctionPointerType func = (FunctionPointerType)dlsym(dlHandle, name);
145         if (func == nullptr) {
146             WLOGD("try to getProcAddr %{public}s.", name);
147             func = getProcAddr(name);
148             if (func == nullptr) {
149                 WLOGD("couldn't find the entry-point: %{public}s.", name);
150             }
151         }
152         *current++ = func;
153         api++;
154     }
155 
156     return dlHandle;
157 }
158 
LoadVendorDriver(EglWrapperDispatchTable * table)159 bool EglWrapperLoader::LoadVendorDriver(EglWrapperDispatchTable *table)
160 {
161     WLOGD("EGL");
162     if (!LoadEgl(LIB_EGL_NAME, &table->egl)) {
163         WLOGE("LoadEgl Failed.");
164         return false;
165     }
166 
167     WLOGD("GLESV1");
168     dlGlHandle1_ = LoadGl(LIB_GLESV1_NAME, gGlApiNames1, (FunctionPointerType *)&table->gl.table1);
169     if (!dlEglHandle_) {
170         WLOGE("LoadGl GLESV1 Failed.");
171         return false;
172     }
173 
174     WLOGD("GLESV2");
175     dlGlHandle2_ = LoadGl(LIB_GLESV2_NAME, gGlApiNames2, (FunctionPointerType *)&table->gl.table2);
176     if (!dlGlHandle2_) {
177         WLOGE("LoadGl GLESV2 Failed.");
178         return false;
179     }
180 
181     WLOGD("GLESV3");
182     dlGlHandle3_ = LoadGl(LIB_GLESV3_NAME, gGlApiNames3, (FunctionPointerType *)&table->gl.table3);
183     if (!dlGlHandle3_) {
184         WLOGE("LoadGl GLESV3 Failed.");
185         return false;
186     }
187 
188     return true;
189 }
190 
Load(EglWrapperDispatchTable * table)191 bool EglWrapperLoader::Load(EglWrapperDispatchTable *table)
192 {
193     WLOGD("");
194     if (table == nullptr) {
195         WLOGE("table is nullptr.");
196         return false;
197     }
198 
199     if (table->isLoad) {
200         WLOGI("EglWrapperLoader has been already loaded.");
201         return true;
202     }
203 
204     if (!LoadVendorDriver(table)) {
205         WLOGE("LoadVendorDriver Failed.");
206         return false;
207     }
208 
209     table->isLoad = true;
210     return true;
211 }
212 
Unload(EglWrapperDispatchTable * table)213 bool EglWrapperLoader::Unload(EglWrapperDispatchTable *table)
214 {
215     WLOGD("");
216     if (table == nullptr) {
217         WLOGE("table is nullptr.");
218         return false;
219     }
220     if (!table->isLoad) {
221         WLOGE("EglWrapperLoader is not loaded.");
222         return false;
223     }
224 
225     table->isLoad = false;
226 
227     if (dlEglHandle_) {
228         dlclose(dlEglHandle_);
229         dlEglHandle_ = nullptr;
230     }
231     if (dlGlHandle1_) {
232         dlclose(dlGlHandle1_);
233         dlGlHandle1_ = nullptr;
234     }
235     if (dlGlHandle2_) {
236         dlclose(dlGlHandle2_);
237         dlGlHandle2_ = nullptr;
238     }
239     if (dlGlHandle3_) {
240         dlclose(dlGlHandle3_);
241         dlGlHandle3_ = nullptr;
242     }
243 
244     return true;
245 }
246 
GetProcAddrFromDriver(const char * name)247 void *EglWrapperLoader::GetProcAddrFromDriver(const char *name)
248 {
249     void *func = nullptr;
250 
251     if (dlEglHandle_) {
252         func = dlsym(dlEglHandle_, name);
253     }
254 
255     if (!func && dlGlHandle3_) {
256         func = dlsym(dlGlHandle3_, name);
257     }
258 
259     if (!func && dlGlHandle2_) {
260         func = dlsym(dlGlHandle2_, name);
261     }
262 
263     if (!func && dlGlHandle1_) {
264         func = dlsym(dlGlHandle1_, name);
265     }
266 
267     return func;
268 }
269 } // namespace OHOS
270