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 "nweb_helper.h"
17
18 #include <dlfcn.h>
19 #include <refbase.h>
20 #include <surface.h>
21
22 #include <cstdint>
23 #include <memory>
24 #include <thread>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <dirent.h>
28
29 #include "nweb_adapter_helper.h"
30 #include "nweb_enhance_surface_adapter.h"
31 #include "nweb_log.h"
32 #include "nweb_surface_adapter.h"
33 #include "nweb_window_adapter.h"
34 #include "window.h"
35
36 namespace {
37 const uint32_t NWEB_SURFACE_MAX_WIDTH = 7680;
38 const uint32_t NWEB_SURFACE_MAX_HEIGHT = 7680;
39 #if defined(webview_arm64)
40 const std::string RELATIVE_PATH_FOR_MOCK = "libs/arm64";
41 const std::string RELATIVE_PATH_FOR_BUNDLE = "nweb/libs/arm64";
42 #elif defined(webview_x86_64)
43 const std::string RELATIVE_PATH_FOR_MOCK = "libs/x86_64";
44 const std::string RELATIVE_PATH_FOR_BUNDLE = "nweb/libs/x86_64";
45 #else
46 const std::string RELATIVE_PATH_FOR_MOCK = "libs/arm";
47 const std::string RELATIVE_PATH_FOR_BUNDLE = "nweb/libs/arm";
48 #endif
49 const std::string LIB_NAME_WEB_ENGINE = "libweb_engine.so";
50 const std::string LIB_NAME_NWEB_ADAPTER = "libnweb_adapter.so";
51 static bool g_isFirstTimeStartUp = false;
52 }
53
54 namespace OHOS::NWeb {
Instance()55 NWebHelper &NWebHelper::Instance()
56 {
57 static NWebHelper helper;
58 return helper;
59 }
60
61 #ifdef __MUSL__
LoadLib(bool from_ark)62 bool NWebHelper::LoadLib(bool from_ark)
63 {
64 if (libHandleWebEngine_ != nullptr) {
65 return true;
66 }
67 if (bundlePath_.empty()) {
68 return false;
69 }
70 std::string loadLibPath;
71 if (from_ark) {
72 loadLibPath = bundlePath_ + "/" + RELATIVE_PATH_FOR_BUNDLE;
73 } else {
74 loadLibPath = bundlePath_ + "/" + RELATIVE_PATH_FOR_MOCK;
75 }
76 Dl_namespace dlns;
77 dlns_init(&dlns, "nweb_ns");
78 dlns_create(&dlns, loadLibPath.c_str());
79 void *libHandleWebEngine = dlopen_ns(&dlns, LIB_NAME_WEB_ENGINE.c_str(), RTLD_NOW);
80 if (libHandleWebEngine == nullptr) {
81 WVLOG_E("fail to dlopen %{public}s, errmsg=%{public}s", LIB_NAME_WEB_ENGINE.c_str(), dlerror());
82 return false;
83 }
84 libHandleWebEngine_ = libHandleWebEngine;
85 return true;
86 }
87 #else
LoadLib(bool from_ark)88 bool NWebHelper::LoadLib(bool from_ark)
89 {
90 if (libHandleWebEngine_ != nullptr) {
91 return true;
92 }
93 if (bundlePath_.empty()) {
94 return false;
95 }
96 std::string loadLibPath;
97 if (from_ark) {
98 loadLibPath = bundlePath_ + "/" + RELATIVE_PATH_FOR_BUNDLE;
99 } else {
100 loadLibPath = bundlePath_ + "/" + RELATIVE_PATH_FOR_MOCK;
101 }
102 const std::string libPathWebEngine = loadLibPath + "/" + LIB_NAME_WEB_ENGINE;
103 void *libHandleWebEngine = ::dlopen(libPathWebEngine.c_str(), RTLD_NOW);
104 if (libHandleWebEngine == nullptr) {
105 WVLOG_E("fail to dlopen %{public}s, errmsg=%{public}s", libPathWebEngine.c_str(), dlerror());
106 return false;
107 }
108 libHandleWebEngine_ = libHandleWebEngine;
109 return true;
110 }
111 #endif
112
UnloadLib()113 void NWebHelper::UnloadLib()
114 {
115 if (libHandleWebEngine_ != nullptr) {
116 ::dlclose(libHandleWebEngine_);
117 libHandleWebEngine_ = nullptr;
118 }
119 }
120
DoPreReadLib(const std::string & bundlePath)121 static void DoPreReadLib(const std::string &bundlePath)
122 {
123 WVLOG_I("NWebHelper PreReadLib");
124 std::string libPathWebEngine = bundlePath + "/" + RELATIVE_PATH_FOR_BUNDLE + "/" + LIB_NAME_WEB_ENGINE;
125
126 char tempPath[PATH_MAX] = {0};
127 if (realpath(libPathWebEngine.c_str(), tempPath) == nullptr) {
128 WVLOG_E("path to realpath error");
129 return;
130 }
131
132 struct stat stats;
133 int ret = stat(tempPath, &stats);
134 if (ret < 0) {
135 WVLOG_E("stat web engine library failed, ret = %{public}d", ret);
136 return;
137 }
138
139 static const int SINGLE_READ_SIZE = 5 * 1024 * 1024;
140 char *buf = new (std::nothrow) char[SINGLE_READ_SIZE];
141 if (buf == nullptr) {
142 WVLOG_E("malloc buf failed");
143 return;
144 }
145
146 int fd = open(tempPath, O_RDONLY);
147 if (fd <= 0) {
148 WVLOG_E("open web engine library failed");
149 delete [] buf;
150 return;
151 }
152
153 int readCnt = stats.st_size / SINGLE_READ_SIZE;
154 if (readCnt * SINGLE_READ_SIZE < stats.st_size) {
155 readCnt += 1;
156 }
157
158 for (int i = 0; i < readCnt; i++) {
159 (void)read(fd, buf, SINGLE_READ_SIZE);
160 }
161
162 (void)close(fd);
163 delete [] buf;
164 WVLOG_I("NWebHelper PreReadLib Finish");
165 }
166
TryPreReadLib(bool isFirstTimeStartUpWeb,const std::string & bundlePath)167 void NWebHelper::TryPreReadLib(bool isFirstTimeStartUpWeb, const std::string &bundlePath)
168 {
169 g_isFirstTimeStartUp = isFirstTimeStartUpWeb;
170 if (isFirstTimeStartUpWeb) {
171 WVLOG_I("first time startup, need to wait until the nweb init stage");
172 return;
173 }
174
175 DoPreReadLib(bundlePath);
176 }
177
TryPreReadLibForFirstlyAppStartUp(const std::string & bundlePath)178 static void TryPreReadLibForFirstlyAppStartUp(const std::string &bundlePath)
179 {
180 if (g_isFirstTimeStartUp) {
181 std::thread preReadThread([bundlePath]() {
182 DoPreReadLib(bundlePath);
183 });
184
185 preReadThread.detach();
186 }
187 }
188
Init(bool from_ark)189 bool NWebHelper::Init(bool from_ark)
190 {
191 TryPreReadLibForFirstlyAppStartUp(bundlePath_);
192 return LoadLib(from_ark);
193 }
194
SetBundlePath(const std::string & path)195 void NWebHelper::SetBundlePath(const std::string &path)
196 {
197 bundlePath_ = path;
198 }
199
~NWebHelper()200 NWebHelper::~NWebHelper()
201 {
202 UnloadLib();
203 }
204
205 using CreateNWebFuncType = void(*)(const NWebCreateInfo &, std::shared_ptr<NWeb> &);
CreateNWeb(const NWebCreateInfo & create_info)206 std::shared_ptr<NWeb> NWebHelper::CreateNWeb(const NWebCreateInfo &create_info)
207 {
208 if (libHandleWebEngine_ == nullptr) {
209 return nullptr;
210 }
211
212 const std::string CREATE_NWEB_FUNC_NAME = "CreateNWeb";
213 CreateNWebFuncType funcCreateNWeb =
214 reinterpret_cast<CreateNWebFuncType>(dlsym(libHandleWebEngine_, CREATE_NWEB_FUNC_NAME.c_str()));
215 if (funcCreateNWeb == nullptr) {
216 WVLOG_E("fail to dlsym %{public}s from libohoswebview.so", CREATE_NWEB_FUNC_NAME.c_str());
217 return nullptr;
218 }
219 std::shared_ptr<NWeb> nweb;
220 funcCreateNWeb(create_info, nweb);
221 if (nweb == nullptr) {
222 WVLOG_E("fail to create nweb");
223 return nullptr;
224 }
225
226 return nweb;
227 }
228
229 using GetCookieManagerFunc = NWebCookieManager *(*)();
GetCookieManager()230 NWebCookieManager *NWebHelper::GetCookieManager()
231 {
232 if (libHandleWebEngine_ == nullptr) {
233 return nullptr;
234 }
235
236 const std::string COOKIE_FUNC_NAME = "GetCookieManager";
237 GetCookieManagerFunc cookieFunc =
238 reinterpret_cast<GetCookieManagerFunc>(dlsym(libHandleWebEngine_, COOKIE_FUNC_NAME.c_str()));
239 if (cookieFunc == nullptr) {
240 WVLOG_E("fail to dlsym %{public}s from libohoswebview.so", COOKIE_FUNC_NAME.c_str());
241 return nullptr;
242 }
243 return cookieFunc();
244 }
245
246 using GetNWebFunc = void(*)(int32_t, std::weak_ptr<NWeb> &);
GetNWeb(int32_t nweb_id)247 std::weak_ptr<NWeb> NWebHelper::GetNWeb(int32_t nweb_id)
248 {
249 std::weak_ptr<OHOS::NWeb::NWeb> nweb;
250 if (libHandleWebEngine_ == nullptr) {
251 WVLOG_E("libHandleWebEngine_ is nullptr");
252 return nweb;
253 }
254
255 const std::string GET_NWEB_FUNC_NAME = "GetNWeb";
256 GetNWebFunc getNWebFunc = reinterpret_cast<GetNWebFunc>(dlsym(libHandleWebEngine_, GET_NWEB_FUNC_NAME.c_str()));
257 if (getNWebFunc == nullptr) {
258 WVLOG_E("fail to dlsym %{public}s from libohoswebview.so", GET_NWEB_FUNC_NAME.c_str());
259 return nweb;
260 }
261
262 getNWebFunc(nweb_id, nweb);
263 return nweb;
264 }
265
266 using GetDataBaseFunc = NWebDataBase *(*)();
GetDataBase()267 NWebDataBase *NWebHelper::GetDataBase()
268 {
269 if (libHandleWebEngine_ == nullptr) {
270 return nullptr;
271 }
272
273 const std::string DATA_BASE_FUNC_NAME = "GetDataBase";
274 GetDataBaseFunc dataBaseFunc =
275 reinterpret_cast<GetDataBaseFunc>(dlsym(libHandleWebEngine_, DATA_BASE_FUNC_NAME.c_str()));
276 if (dataBaseFunc == nullptr) {
277 WVLOG_E("fail to dlsym %{public}s from libohoswebview.so", DATA_BASE_FUNC_NAME.c_str());
278 return nullptr;
279 }
280 return dataBaseFunc();
281 }
282
283 using GetWebStorageFunc = NWebWebStorage *(*)();
GetWebStorage()284 NWebWebStorage *NWebHelper::GetWebStorage()
285 {
286 if (libHandleWebEngine_ == nullptr) {
287 return nullptr;
288 }
289 const std::string STORAGE_FUNC_NAME = "GetWebStorage";
290 GetWebStorageFunc storageFunc =
291 reinterpret_cast<GetWebStorageFunc>(dlsym(libHandleWebEngine_, STORAGE_FUNC_NAME.c_str()));
292 if (storageFunc == nullptr) {
293 WVLOG_E("fail to dlsym %{public}s from libohoswebview.so", STORAGE_FUNC_NAME.c_str());
294 return nullptr;
295 }
296 return storageFunc();
297 }
298
Instance()299 NWebAdapterHelper &NWebAdapterHelper::Instance()
300 {
301 static NWebAdapterHelper helper;
302 return helper;
303 }
304
Init(bool from_ark)305 bool NWebAdapterHelper::Init(bool from_ark)
306 {
307 return NWebHelper::Instance().Init(from_ark);
308 }
309
CreateNWeb(Rosen::Window * window,const NWebInitArgs & initArgs)310 std::shared_ptr<NWeb> NWebAdapterHelper::CreateNWeb(Rosen::Window *window, const NWebInitArgs &initArgs)
311 {
312 if (window == nullptr) {
313 WVLOG_E("fail to create nweb, input window is nullptr");
314 return nullptr;
315 }
316 auto createInfo = NWebWindowAdapter::Instance().GetCreateInfo(window, initArgs);
317 auto nweb = NWebHelper::Instance().CreateNWeb(createInfo);
318 if (nweb == nullptr) {
319 WVLOG_E("fail to create nweb instance");
320 return nullptr;
321 }
322 NWebWindowAdapter::Instance().RegistEventCb(window, nweb);
323 NWebWindowAdapter::Instance().RequestVsync(window, nweb);
324 return nweb;
325 }
326
CreateNWeb(sptr<Surface> surface,const NWebInitArgs & initArgs,uint32_t width,uint32_t height)327 std::shared_ptr<NWeb> NWebAdapterHelper::CreateNWeb(sptr<Surface> surface, const NWebInitArgs &initArgs, uint32_t width,
328 uint32_t height)
329 {
330 if (surface == nullptr) {
331 WVLOG_E("fail to create nweb, input surface is nullptr");
332 return nullptr;
333 }
334 if (width > NWEB_SURFACE_MAX_WIDTH || height > NWEB_SURFACE_MAX_HEIGHT) {
335 WVLOG_E("input size %{public}u*%{public}u is invalid.", width, height);
336 return nullptr;
337 }
338 auto createInfo = NWebSurfaceAdapter::Instance().GetCreateInfo(surface, initArgs, width, height);
339 auto nweb = NWebHelper::Instance().CreateNWeb(createInfo);
340 if (nweb == nullptr) {
341 WVLOG_E("fail to create nweb instance");
342 }
343 return nweb;
344 }
345
CreateNWeb(void * enhanceSurfaceInfo,const NWebInitArgs & initArgs,uint32_t width,uint32_t height)346 std::shared_ptr<NWeb> NWebAdapterHelper::CreateNWeb(void *enhanceSurfaceInfo,
347 const NWebInitArgs &initArgs,
348 uint32_t width,
349 uint32_t height)
350 {
351 if (enhanceSurfaceInfo == nullptr) {
352 WVLOG_E("fail to create nweb, input surface is nullptr");
353 return nullptr;
354 }
355 if (width > NWEB_SURFACE_MAX_WIDTH || height > NWEB_SURFACE_MAX_HEIGHT) {
356 WVLOG_E("input size %{public}u*%{public}u is invalid.", width, height);
357 return nullptr;
358 }
359 auto createInfo = NWebEnhanceSurfaceAdapter::Instance().GetCreateInfo(enhanceSurfaceInfo, initArgs, width, height);
360 auto nweb = NWebHelper::Instance().CreateNWeb(createInfo);
361 if (nweb == nullptr) {
362 WVLOG_E("fail to create nweb instance");
363 }
364 return nweb;
365 }
366 } // namespace OHOS::NWeb
367