1 /*
2 * Copyright (c) 2025 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 #include "arkweb_utils.h"
16
17 #include "parameters.h"
18 #include "nweb_log.h"
19 #include "json/json.h"
20 #include <cerrno>
21 #include <cstring>
22 #include <dlfcn.h>
23 #include <fstream>
24
25 namespace OHOS::ArkWeb {
26
27 static int g_appEngineVersion = static_cast<int>(ArkWebEngineVersion::SYSTEM_DEFAULT);
28 static bool g_webEngineInitFlag = false;
29
30 #if defined(webview_arm64)
31 const std::string ARK_WEB_CORE_MOCK_HAP_LIB_PATH =
32 "/data/storage/el1/bundle/libs/arm64";
33 const std::string ARK_WEB_CORE_HAP_LIB_PATH =
34 "/data/storage/el1/bundle/arkwebcore/libs/arm64";
35 const std::string ARK_WEB_CORE_LEGACY_HAP_LIB_PATH =
36 "/data/storage/el1/bundle/arkwebcorelegacy/libs/arm64";
37 const std::string ARK_WEB_CORE_PATH_FOR_MOCK = "libs/arm64";
38 const std::string ARK_WEB_CORE_PATH_FOR_BUNDLE = "arkwebcore/libs/arm64";
39 const std::string ARK_WEB_CORE_LEGACY_PATH_FOR_BUNDLE = "arkwebcorelegacy/libs/arm64";
40 #elif defined(webview_x86_64)
41 const std::string ARK_WEB_CORE_MOCK_HAP_LIB_PATH =
42 "/data/storage/el1/bundle/libs/x86_64";
43 const std::string ARK_WEB_CORE_HAP_LIB_PATH =
44 "/data/storage/el1/bundle/arkwebcore/libs/x86_64";
45 const std::string ARK_WEB_CORE_LEGACY_HAP_LIB_PATH =
46 "/data/storage/el1/bundle/arkwebcorelegacy/libs/x86_64";
47 const std::string ARK_WEB_CORE_PATH_FOR_MOCK = "libs/x86_64";
48 const std::string ARK_WEB_CORE_PATH_FOR_BUNDLE = "arkwebcore/libs/x86_64";
49 const std::string ARK_WEB_CORE_LEGACY_PATH_FOR_BUNDLE = "arkwebcorelegacy/libs/x86_64";
50 #else
51 const std::string ARK_WEB_CORE_MOCK_HAP_LIB_PATH =
52 "/data/storage/el1/bundle/libs/arm";
53 const std::string ARK_WEB_CORE_HAP_LIB_PATH =
54 "/data/storage/el1/bundle/arkwebcore/libs/arm";
55 const std::string ARK_WEB_CORE_LEGACY_HAP_LIB_PATH =
56 "/data/storage/el1/bundle/arkwebcorelegacy/libs/arm";
57 const std::string ARK_WEB_CORE_PATH_FOR_MOCK = "libs/arm";
58 const std::string ARK_WEB_CORE_PATH_FOR_BUNDLE = "arkwebcore/libs/arm";
59 const std::string ARK_WEB_CORE_LEGACY_PATH_FOR_BUNDLE = "arkwebcorelegacy/libs/arm";
60 #endif
61
62 #if defined(IS_ASAN)
63 #if defined(webview_arm64)
64 const std::string ARK_WEB_CORE_ASAN_PATH_FOR_BUNDLE = "arkwebcore_asan/libs/arm64";
65 const std::string WEBVIEW_RELATIVE_SANDBOX_PATH_FOR_LIBRARY =
66 "data/storage/el1/bundle/arkwebcore_asan/libs/arm64/libarkweb_engine.so";
67 const std::string ARK_WEB_CORE_HAP_LIB_PATH_ASAN = "/data/storage/el1/bundle/arkwebcore_asan/libs/arm64";
68 #elif defined(webview_x86_64)
69 const std::string ARK_WEB_CORE_ASAN_PATH_FOR_BUNDLE = "arkwebcore_asan/libs/x86_64";
70 #else
71 const std::string ARK_WEB_CORE_ASAN_PATH_FOR_BUNDLE = "arkwebcore_asan/libs/arm";
72 #endif
73 #endif
74
75 const std::string PRECONFIG_LEGACY_HAP_PATH = "/system/app/ArkWebCoreLegacy/ArkWebCoreLegacy.hap";
76 const std::string PRECONFIG_EVERGREEN_HAP_PATH =
77 "/system/app/com.ohos.arkwebcore/ArkWebCore.hap";
78 const std::string PRECONFIG_EVERGREEN_WATCH_HAP_PATH =
79 "/system/app/NWeb/NWeb.hap";
80 const std::string SANDBOX_LEGACY_HAP_PATH = "/data/storage/el1/bundle/arkwebcorelegacy/entry.hap";
81 const std::string SANDBOX_EVERGREEN_HAP_PATH = "/data/storage/el1/bundle/arkwebcore/entry.hap";
82
83 const std::string JSON_CONFIG_PATH =
84 "/data/service/el1/public/update/param_service/install/system/etc/ArkWebSafeBrowsing/generic/ArkWebCoreCfg.json";
85 const std::string WEB_PARAM_PREFIX = "web.engine.";
86
validateSpecialParams(const std::string & key,int value)87 static bool validateSpecialParams(const std::string& key, int value)
88 {
89 if (key == "web.engine.default") {
90 if (value != static_cast<int>(ArkWebEngineType::EVERGREEN) &&
91 value != static_cast<int>(ArkWebEngineType::LEGACY)) {
92 WVLOG_E("Invalid value for %{public}s: %{public}d, must be EVERGREEN or LEGACY",
93 key.c_str(), value);
94 return false;
95 }
96 }
97 else if (key == "web.engine.enforce") {
98 if (value != static_cast<int>(ArkWebEngineType::EVERGREEN)) {
99 WVLOG_E("Invalid value for %{public}s: %{public}d, must be EVERGREEN",
100 key.c_str(), value);
101 return false;
102 }
103 }
104 return true;
105 }
106
processJsonConfig(const Json::Value & root)107 static void processJsonConfig(const Json::Value& root)
108 {
109 if (!root.isObject()) {
110 WVLOG_E("Not a JSON object");
111 return;
112 }
113
114 Json::Value::Members keys = root.getMemberNames();
115 for (const auto& key : keys) {
116 const Json::Value& value = root[key];
117 if (!value.isInt() || key.rfind(WEB_PARAM_PREFIX, 0) != 0) {
118 WVLOG_E("Invalid param %{public}s", key.c_str());
119 continue;
120 }
121
122 int intValue = value.asInt();
123
124 // 验证特殊参数
125 if (!validateSpecialParams(key, intValue)) {
126 continue; // 跳过非法值
127 }
128
129 // 设置有效参数
130 std::string valueStr = std::to_string(intValue);
131 if (OHOS::system::SetParameter(key, valueStr)) {
132 WVLOG_I("Set param %{public}s with %{public}s", key.c_str(), valueStr.c_str());
133 } else {
134 WVLOG_E("Set param %{public}s with %{public}s failed", key.c_str(), valueStr.c_str());
135 }
136 }
137 }
138
updateCfgToSystemParam()139 static void updateCfgToSystemParam()
140 {
141 std::ifstream jsonFile(JSON_CONFIG_PATH.c_str());
142 if (!jsonFile.is_open()) {
143 WVLOG_E("Failed to open file reason: %{public}s", strerror(errno));
144 return;
145 }
146
147 Json::Value root;
148 Json::CharReaderBuilder readerBuilder;
149 std::string parseErrors;
150 bool parsingSuccessful = Json::parseFromStream(readerBuilder, jsonFile, &root, &parseErrors);
151
152 if (!parsingSuccessful) {
153 WVLOG_E("JSON parse failed, parseErrors:%{public}s", parseErrors.c_str());
154 return;
155 }
156
157 processJsonConfig(root);
158 }
159
PreloadArkWebLibForBrowser()160 void PreloadArkWebLibForBrowser()
161 {
162 updateCfgToSystemParam();
163 if (!(access(PRECONFIG_LEGACY_HAP_PATH.c_str(), F_OK) == 0)) {
164 if (OHOS::system::SetParameter("web.engine.enforce",
165 std::to_string(static_cast<int>(ArkWebEngineType::EVERGREEN)))) {
166 WVLOG_I("Set param web.engine.enforce with %{public}d", static_cast<int>(ArkWebEngineType::EVERGREEN));
167 } else {
168 WVLOG_I("Set param web.engine.enforce with %{public}d failed",
169 static_cast<int>(ArkWebEngineType::EVERGREEN));
170 }
171 }
172 return;
173 }
174
setActiveWebEngineVersion(ArkWebEngineVersion version)175 void setActiveWebEngineVersion(ArkWebEngineVersion version)
176 {
177 if (g_webEngineInitFlag) {
178 WVLOG_E("library resources have been loaded, can't set appEngineVersion");
179 return;
180 }
181
182 if (static_cast<int>(version) != static_cast<int>(ArkWebEngineType::LEGACY) &&
183 static_cast<int>(version) != static_cast<int>(ArkWebEngineType::EVERGREEN) &&
184 static_cast<int>(version) != static_cast<int>(ArkWebEngineVersion::SYSTEM_DEFAULT) &&
185 static_cast<int>(version) != static_cast<int>(ArkWebEngineVersion::SYSTEM_EVERGREEN)) {
186 WVLOG_I("set EngineVersion not support, setVersion: %{public}d", static_cast<int>(version));
187 return;
188 }
189 g_appEngineVersion = static_cast<int>(version);
190 WVLOG_I("set appEngineVersion: %{public}d", g_appEngineVersion);
191 }
192
getAppWebEngineVersion()193 ArkWebEngineVersion getAppWebEngineVersion()
194 {
195 return static_cast<ArkWebEngineVersion>(g_appEngineVersion);
196 }
197
getActiveWebEngineVersion()198 ArkWebEngineVersion getActiveWebEngineVersion()
199 {
200 int webEngineEnforce = OHOS::system::GetIntParameter("web.engine.enforce", 0);
201 if (webEngineEnforce == static_cast<int>(ArkWebEngineType::EVERGREEN)) {
202 WVLOG_I("WebEngineVersionResult, enforce EVERGREEN");
203 return static_cast<ArkWebEngineVersion>(ArkWebEngineType::EVERGREEN);
204 }
205
206 if (g_appEngineVersion != static_cast<int>(ArkWebEngineVersion::SYSTEM_DEFAULT)) {
207 WVLOG_I("get appEngineVersion: %{public}d", g_appEngineVersion);
208 if (g_appEngineVersion == static_cast<int>(ArkWebEngineVersion::SYSTEM_EVERGREEN)) {
209 return static_cast<ArkWebEngineVersion>(ArkWebEngineType::EVERGREEN);
210 }
211 return static_cast<ArkWebEngineVersion>(g_appEngineVersion);
212 }
213
214 int webEngineDefault = OHOS::system::GetIntParameter("web.engine.default",
215 static_cast<int>(ArkWebEngineType::EVERGREEN));
216 if (webEngineDefault != static_cast<int>(ArkWebEngineType::LEGACY) &&
217 webEngineDefault != static_cast<int>(ArkWebEngineType::EVERGREEN)) {
218 WVLOG_E("webEngineDefault is not EVERGREEN or LEGACY: %{public}d", webEngineDefault);
219 return static_cast<ArkWebEngineVersion>(ArkWebEngineType::EVERGREEN);
220 }
221
222 WVLOG_I("get webEngineDefault: %{public}d", webEngineDefault);
223 return static_cast<ArkWebEngineVersion>(webEngineDefault);
224 }
225
getActiveWebEngineType()226 ArkWebEngineType getActiveWebEngineType()
227 {
228 return static_cast<ArkWebEngineType>(getActiveWebEngineVersion());
229 }
230
IsActiveWebEngineEvergreen()231 bool IsActiveWebEngineEvergreen()
232 {
233 if (getActiveWebEngineType() == ArkWebEngineType::EVERGREEN) {
234 return true;
235 }
236 return false;
237 }
238
LogForUnsupportedFunc(ArkWebEngineVersion version,const char * msg)239 void LogForUnsupportedFunc(ArkWebEngineVersion version, const char* msg)
240 {
241 WVLOG_W("%{public}s unsupported engine version: %{public}d",
242 msg, static_cast<int>(version));
243 }
244
GetArkwebLibPath()245 std::string GetArkwebLibPath()
246 {
247 std::string path;
248 if (getActiveWebEngineType() == ArkWebEngineType::LEGACY) {
249 path = ARK_WEB_CORE_LEGACY_HAP_LIB_PATH;
250 } else {
251 path = ARK_WEB_CORE_HAP_LIB_PATH;
252 #if defined(IS_ASAN) && defined(webview_arm64)
253 if ((access(WEBVIEW_RELATIVE_SANDBOX_PATH_FOR_LIBRARY.c_str(), F_OK) == 0)) {
254 path = ARK_WEB_CORE_HAP_LIB_PATH_ASAN;
255 }
256 #endif
257 }
258 WVLOG_I("get arkweb lib path: %{public}s", path.c_str());
259 return path;
260 }
261
GetArkwebLibPathForMock()262 std::string GetArkwebLibPathForMock()
263 {
264 std::string path = ARK_WEB_CORE_MOCK_HAP_LIB_PATH;
265 WVLOG_I("get arkweb lib mock path: %{public}s", path.c_str());
266 return path;
267 }
268
GetArkwebNameSpace()269 std::string GetArkwebNameSpace()
270 {
271 std::string ns;
272 if (getActiveWebEngineType() == ArkWebEngineType::LEGACY) {
273 ns = "nweb_ns_legacy";
274 } else {
275 ns = "nweb_ns";
276 }
277 WVLOG_I("get arkweb name space: %{public}s", ns.c_str());
278 return ns;
279 }
280
GetArkwebRelativePathForBundle()281 std::string GetArkwebRelativePathForBundle()
282 {
283 std::string path;
284 #if defined(IS_ASAN) && defined(webview_arm64)
285 if (!(access(WEBVIEW_RELATIVE_SANDBOX_PATH_FOR_LIBRARY.c_str(), F_OK) == 0)) {
286 path = "arkwebcore/libs/arm64";
287 } else {
288 path = ARK_WEB_CORE_ASAN_PATH_FOR_BUNDLE;
289 }
290 #else
291 if (getActiveWebEngineType() == ArkWebEngineType::LEGACY) {
292 path = ARK_WEB_CORE_LEGACY_PATH_FOR_BUNDLE;
293 } else {
294 path = ARK_WEB_CORE_PATH_FOR_BUNDLE;
295 }
296 #endif
297 WVLOG_I("get arkweb relative bundle path: %{public}s", path.c_str());
298 return path;
299 }
300
GetArkwebRelativePathForMock()301 std::string GetArkwebRelativePathForMock()
302 {
303 std::string path = ARK_WEB_CORE_PATH_FOR_MOCK;
304 WVLOG_I("get arkweb mock path: %{public}s", path.c_str());
305 return path;
306 }
307
GetArkwebInstallPath()308 std::string GetArkwebInstallPath()
309 {
310 std::vector<std::string> legacyPaths = {SANDBOX_LEGACY_HAP_PATH, PRECONFIG_LEGACY_HAP_PATH,};
311 std::vector<std::string> greenPaths = {SANDBOX_EVERGREEN_HAP_PATH, PRECONFIG_EVERGREEN_HAP_PATH,
312 PRECONFIG_EVERGREEN_WATCH_HAP_PATH};
313
314 std::vector<std::string> workPaths;
315 if (getActiveWebEngineType() == ArkWebEngineType::LEGACY) {
316 workPaths = legacyPaths;
317 } else {
318 workPaths = greenPaths;
319 }
320
321 std::string installPath = "";
322 for (auto path : workPaths) {
323 if (access(path.c_str(), F_OK) == 0) {
324 installPath = path;
325 break;
326 }
327 }
328 if (installPath == "") {
329 WVLOG_E("failed to find hap path");
330 }
331 WVLOG_I("get arkweb install path: %{public}s", installPath.c_str());
332 return installPath;
333 }
334
ArkWebBridgeHelperLoadLibFile(int openMode,const std::string & libFilePath,bool isPrintLog=true)335 void* ArkWebBridgeHelperLoadLibFile(int openMode, const std::string& libFilePath,
336 bool isPrintLog = true)
337 {
338 void* libFileHandler = ::dlopen(libFilePath.c_str(), openMode);
339 if (!libFileHandler) {
340 if (isPrintLog) {
341 WVLOG_E("failed to load lib file %{public}s", libFilePath.c_str());
342 }
343 return nullptr;
344 }
345
346 if (isPrintLog) {
347 WVLOG_I("succeed to load lib file %{public}s", libFilePath.c_str());
348 }
349 return libFileHandler;
350 }
351
ArkWebBridgeHelperLoadLibFile(int openMode,const std::string & libNsName,const std::string & libDirPath,const std::string & libFileName,bool isPrintLog=true)352 void* ArkWebBridgeHelperLoadLibFile(int openMode, const std::string& libNsName,
353 const std::string& libDirPath, const std::string& libFileName, bool isPrintLog = true)
354 {
355 Dl_namespace dlns;
356
357 dlns_init(&dlns, libNsName.c_str());
358
359 int ret = dlns_create(&dlns, libDirPath.c_str());
360 if (ret != 0) {
361 WVLOG_E("dlns_create failed for '%{public}s': %{public}s (errno=%{public}d)",
362 libDirPath.c_str(), strerror(errno), ret);
363 }
364
365 Dl_namespace ndkns;
366 ret = dlns_get("ndk", &ndkns);
367 if (ret != 0) {
368 WVLOG_E("dlns_get(ndk) failed: %{public}s (errno=%{public}d)", strerror(errno), ret);
369 }
370
371 ret = dlns_inherit(&dlns, &ndkns, "allow_all_shared_libs");
372 if (ret != 0) {
373 WVLOG_E("dlns_inherit failed: %{public}s (errno=%{public}d)", strerror(errno), ret);
374 }
375
376 void* libFileHandler = dlopen_ns(&dlns, libFileName.c_str(), openMode);
377 if (!libFileHandler) {
378 if (isPrintLog) {
379 WVLOG_E(
380 "failed to load lib file %{public}s/%{public}s", libDirPath.c_str(), libFileName.c_str());
381 }
382 return nullptr;
383 }
384
385 if (isPrintLog) {
386 WVLOG_I(
387 "succeed to load lib file %{public}s/%{public}s", libDirPath.c_str(), libFileName.c_str());
388 }
389
390 return libFileHandler;
391 }
392
ArkWebBridgeHelperSharedInit(bool isPreDlopen,bool runMode)393 void* ArkWebBridgeHelperSharedInit(bool isPreDlopen, bool runMode)
394 {
395 std::string libFileName = "libarkweb_engine.so";
396
397 std::string libDirPath;
398 if (runMode) {
399 libDirPath = GetArkwebLibPath();
400 } else {
401 libDirPath = GetArkwebLibPathForMock();
402 }
403
404 std::string libNsName = GetArkwebNameSpace();
405
406 void* libFileHandler;
407
408 #ifdef __MUSL__
409 libFileHandler = ArkWebBridgeHelperLoadLibFile(RTLD_NOW | RTLD_GLOBAL, libNsName, libDirPath, libFileName);
410 #else
411 libFileHandler = ArkWebBridgeHelperLoadLibFile(RTLD_NOW, libDirPath + "/" + libFileName)
412 #endif
413
414 if (!isPreDlopen && libFileHandler != nullptr) {
415 g_webEngineInitFlag = true;
416 WVLOG_I("g_webEngineInitFlag set to true. setActiveWebEngineVersion will be ignored.");
417 }
418
419 return libFileHandler;
420 }
421 }