1 /*
2  * Copyright (c) 2024 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 "base/bridge/ark_web_bridge_helper.h"
17 
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 
22 #include "base/bridge/ark_web_bridge_macros.h"
23 
24 namespace OHOS::ArkWeb {
25 
26 int g_ark_web_init_addr = 1;
27 
~ArkWebBridgeHelper()28 ArkWebBridgeHelper::~ArkWebBridgeHelper()
29 {
30     UnloadLibFile();
31 }
32 
LoadLibFile(int openMode,const std::string & libFilePath,bool isPrintLog)33 bool ArkWebBridgeHelper::LoadLibFile(int openMode, const std::string& libFilePath, bool isPrintLog)
34 {
35     if (libFileHandler_) {
36         return true;
37     }
38 
39     void* libFileHandler = ::dlopen(libFilePath.c_str(), openMode);
40     if (!libFileHandler) {
41         if (isPrintLog) {
42             ARK_WEB_BRIDGE_ERROR_LOG("failed to load lib file %{public}s", libFilePath.c_str());
43         }
44 
45         return false;
46     }
47 
48     if (isPrintLog) {
49         ARK_WEB_BRIDGE_INFO_LOG("succeed to load lib file %{public}s", libFilePath.c_str());
50     }
51 
52     libFileHandler_ = libFileHandler;
53     return true;
54 }
55 
56 #if defined(OHOS_WEBVIEW_GLUE)
LoadLibFile(int openMode,const std::string & libNsName,const std::string & libDirPath,const std::string & libFileName,bool isPrintLog)57 bool ArkWebBridgeHelper::LoadLibFile(int openMode, const std::string& libNsName, const std::string& libDirPath,
58     const std::string& libFileName, bool isPrintLog)
59 {
60     if (libFileHandler_) {
61         return true;
62     }
63 
64     Dl_namespace dlns;
65     dlns_init(&dlns, libNsName.c_str());
66     dlns_create(&dlns, libDirPath.c_str());
67 
68     void* libFileHandler = dlopen_ns(&dlns, libFileName.c_str(), openMode);
69     if (!libFileHandler) {
70         if (isPrintLog) {
71             ARK_WEB_BRIDGE_ERROR_LOG(
72                 "failed to load lib file %{public}s/%{public}s", libDirPath.c_str(), libFileName.c_str());
73         }
74 
75         return false;
76     }
77 
78     if (isPrintLog) {
79         ARK_WEB_BRIDGE_INFO_LOG(
80             "succeed to load lib file %{public}s/%{public}s", libDirPath.c_str(), libFileName.c_str());
81     }
82 
83     libFileHandler_ = libFileHandler;
84     return true;
85 }
86 #endif
87 
UnloadLibFile()88 void ArkWebBridgeHelper::UnloadLibFile()
89 {
90     if (libFileHandler_ != nullptr) {
91         ::dlclose(libFileHandler_);
92         libFileHandler_ = nullptr;
93     }
94 }
95 
PrereadLibFile(const std::string & libFilePath,bool isPrintLog)96 void ArkWebBridgeHelper::PrereadLibFile(const std::string& libFilePath, bool isPrintLog)
97 {
98     char realPath[PATH_MAX] = { 0 };
99     if (realpath(libFilePath.c_str(), realPath) == nullptr) {
100         if (isPrintLog) {
101             ARK_WEB_BRIDGE_ERROR_LOG("failed to get real path,lib file is %{public}s,errno is %{public}d(%{public}s)",
102                 libFilePath.c_str(), errno, strerror(errno));
103         }
104         return;
105     }
106 
107     struct stat stats;
108     if (stat(realPath, &stats) < 0) {
109         if (isPrintLog) {
110             ARK_WEB_BRIDGE_ERROR_LOG("failed to stat lib file %{public}s,errno is %{public}d(%{public}s)",
111                 libFilePath.c_str(), errno, strerror(errno));
112         }
113         return;
114     }
115 
116     int fd = open(realPath, O_RDONLY);
117     if (fd <= 0) {
118         if (isPrintLog) {
119             ARK_WEB_BRIDGE_ERROR_LOG("failed to open lib file %{public}s,errno is %{public}d : %{public}s",
120                 libFilePath.c_str(), errno, strerror(errno));
121         }
122         return;
123     }
124 
125     static const int SINGLE_READ_SIZE = 5 * 1024 * 1024;
126     char* buf = new (std::nothrow) char[SINGLE_READ_SIZE];
127     if (buf == nullptr) {
128         (void)close(fd);
129         if (isPrintLog) {
130             ARK_WEB_BRIDGE_ERROR_LOG("failed to malloc buf,lib file is %{public}s", libFilePath.c_str());
131         }
132         return;
133     }
134 
135     int readCnt = stats.st_size / SINGLE_READ_SIZE;
136     if (readCnt * SINGLE_READ_SIZE < stats.st_size) {
137         readCnt += 1;
138     }
139 
140     for (int i = 0; i < readCnt; i++) {
141         (void)read(fd, buf, SINGLE_READ_SIZE);
142     }
143 
144     (void)close(fd);
145     delete[] buf;
146 
147     if (isPrintLog) {
148         ARK_WEB_BRIDGE_INFO_LOG("succeed to preread lib file %{public}s", libFilePath.c_str());
149     }
150 }
151 
LoadFuncSymbol(const char * funcName,bool isPrintLog)152 void* ArkWebBridgeHelper::LoadFuncSymbol(const char* funcName, bool isPrintLog)
153 {
154     if (!libFileHandler_) {
155         if (isPrintLog) {
156             ARK_WEB_BRIDGE_ERROR_LOG("lib file handle is nullptr,func name is %{public}s", funcName);
157         }
158 
159         return nullptr;
160     }
161 
162     if (isPrintLog) {
163         ARK_WEB_BRIDGE_INFO_LOG("load func %{public}s", funcName);
164     }
165 
166     return dlsym(libFileHandler_, funcName);
167 }
168 
InitFuncMemberMaps(ArkWebBridgeType init,ArkWebBridgeType butt,bool isPrintLog)169 void ArkWebBridgeHelper::InitFuncMemberMaps(ArkWebBridgeType init, ArkWebBridgeType butt, bool isPrintLog)
170 {
171     std::map<std::string, void*> funcMemberMap;
172     for (int type = static_cast<int>(init); type < static_cast<int>(butt); type++) {
173         funcMemberMaps_[type] = funcMemberMap;
174     }
175 
176     if (isPrintLog) {
177         ARK_WEB_BRIDGE_DV_LOG("init func member maps,bridge type is %{public}d - %{public}d", init, butt);
178     }
179 }
180 
RegisterFuncMember(ArkWebBridgeType bridgeType,const std::map<std::string,void * > & funcMemberMap)181 void ArkWebBridgeHelper::RegisterFuncMember(
182     ArkWebBridgeType bridgeType, const std::map<std::string, void*>& funcMemberMap)
183 {
184     auto itor = funcMemberMaps_.find(static_cast<int>(bridgeType));
185     if (itor == funcMemberMaps_.end()) {
186         ARK_WEB_BRIDGE_INFO_LOG("func member map isn't exist,bridge type is %{public}d", bridgeType);
187         return;
188     }
189 
190     itor->second = funcMemberMap;
191     ARK_WEB_BRIDGE_DV_LOG("func member map is registered and bridge type is %{public}d", bridgeType);
192 }
193 
CheckFuncMemberForCalled(ArkWebBridgeType bridgeType,const std::string & funcName)194 void* ArkWebBridgeHelper::CheckFuncMemberForCalled(ArkWebBridgeType bridgeType, const std::string& funcName)
195 {
196     if (funcName.empty()) {
197         ARK_WEB_BRIDGE_INFO_LOG("func name is empty,bridge ype is %{public}d", bridgeType);
198         return nullptr;
199     }
200 
201     auto itor0 = funcMemberMaps_.find(static_cast<int>(bridgeType));
202     if (itor0 == funcMemberMaps_.end()) {
203         ARK_WEB_BRIDGE_INFO_LOG("func member map isn't registered,bridge type is %{public}d,func name is %{public}s",
204             bridgeType, funcName.c_str());
205         return nullptr;
206     }
207 
208     auto itor1 = itor0->second.find(funcName);
209     if (itor1 == itor0->second.end()) {
210         ARK_WEB_BRIDGE_INFO_LOG("func member isn't registered,bridge type is %{public}d,func name is %{public}s",
211             bridgeType, funcName.c_str());
212         return nullptr;
213     }
214 
215     return itor1->second;
216 }
217 
CheckFuncMemberForCaller(ArkWebBridgeType bridgeType,const std::string & funcName)218 void* ArkWebBridgeHelper::CheckFuncMemberForCaller(ArkWebBridgeType bridgeType, const std::string& funcName)
219 {
220     if (!memberCheckFunc_) {
221         return ARK_WEB_INIT_ADDR;
222     }
223 
224     ArkWebString stFuncName = ArkWebStringClassToStruct(funcName);
225     void* func = memberCheckFunc_(bridgeType, &stFuncName);
226     ArkWebStringStructRelease(stFuncName);
227     return func;
228 }
229 
230 } // namespace OHOS::ArkWeb
231