1 /*
2 * Copyright (c) 2022-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
17 #include <cstdint>
18 #include <dirent.h>
19 #include <dlfcn.h>
20 #include <memory>
21 #include <sys/stat.h>
22 #include <thread>
23 #include <unistd.h>
24 #include <fcntl.h>
25
26 #include "config_policy_utils.h"
27 #include "nweb_config_helper.h"
28 #include "nweb_log.h"
29 #include "parameters.h"
30
31 namespace {
32 const std::string WEB_CONFIG_PATH = "etc/web/web_config.xml";
33 const std::string INIT_CONFIG = "initConfig";
34 const std::string DELETE_CONFIG = "deleteArgsConfig";
35 const std::string PERFORMANCE_CONFIG = "performanceConfig";
36 // The config used in base/web/webview
37 const std::string BASE_WEB_CONFIG = "baseWebConfig";
38 const std::string WEB_ANIMATION_DYNAMIC_SETTING_CONFIG = "property_animation_dynamic_settings";
39 const std::string WEB_ANIMATION_DYNAMIC_APP = "dynamic_apps";
40 const std::string WEB_LTPO_STRATEGY = "ltpo_strategy";
41 const auto XML_ATTR_NAME = "name";
42 const auto XML_ATTR_MIN = "min";
43 const auto XML_ATTR_MAX = "max";
44 const auto XML_ATTR_FPS = "preferred_fps";
45 const std::unordered_map<std::string_view, std::function<std::string(std::string&)>> configMap = {
46 { "renderConfig/renderProcessCount",
__anon669529c30202() 47 [](std::string& contentStr) { return std::string("--renderer-process-limit=") + contentStr; } },
48 { "mediaConfig/backgroundMediaShouldSuspend",
__anon669529c30302() 49 [](std::string& contentStr) {
50 return contentStr == "false" ? std::string("--disable-background-media-suspend") : std::string();
51 } },
52 { "loadurlSocPerfConfig/loadurlSocPerfParam",
__anon669529c30402() 53 [](std::string& contentStr) {
54 return contentStr == "true" ? std::string("--ohos-enable-loadurl-soc-perf") : std::string();
55 } },
56 { "mouseWheelSocPerfConfig/mouseWheelSocPerfParam",
__anon669529c30502() 57 [](std::string& contentStr) {
58 return contentStr == "true" ? std::string("--ohos-enable-mousewheel-soc-perf") : std::string();
59 } },
60 { "touchEventConfig/touchEventShouldRegister",
__anon669529c30602() 61 [](std::string& contentStr) {
62 return contentStr == "false" ? std::string("--disable-touch-event-register") : std::string();
63 } },
64 { "settingConfig/enableWaitForUsername",
__anon669529c30702() 65 [](std::string& contentStr) {
66 return contentStr == "true" ? std::string("--ohos-enable-wait-for-username") : std::string();
67 } },
68 { "settingConfig/enableMaxNumberOfSavedFrames",
__anon669529c30802() 69 [](std::string& contentStr) {
70 return contentStr == "true" ? std::string("--ohos-enable-max-number-of-saved-frames") : std::string();
71 } },
72 { "settingConfig/enableNumRasterThreads",
__anon669529c30902() 73 [](std::string& contentStr) {
74 return contentStr == "true" ? std::string("--ohos-enable-num-raster-threads") : std::string();
75 } },
76 { "settingConfig/enableSingleRenderProcess",
__anon669529c30a02() 77 [](std::string& contentStr) {
78 return contentStr == "true" ? std::string("--ohos-enable-single-render-process") : std::string();
79 } },
80 { "userAgentConfig/userAgentValue",
__anon669529c30b02() 81 [](std::string& contentStr) { return std::string("--ohos-user-agent-value=") + contentStr; } },
82 { "settingConfig/enableSimpleBackendIsDefault",
__anon669529c30c02() 83 [](std::string& contentStr) {
84 return contentStr == "true" ? std::string("--ohos-enable-simple-backend-is-default") : std::string();
85 } },
86 { "settingConfig/enableEmbedMode",
__anon669529c30d02() 87 [](std::string& contentStr) {
88 return contentStr == "true" ? std::string("--ohos-enable-embed-mode") : std::string();
89 } },
90 { "settingConfig/enableWebViewImplForLargeScreen",
__anon669529c30e02() 91 [](std::string& contentStr) {
92 return contentStr == "true" ? std::string("--ohos-enable-web-view-impl-for-large-screen") : std::string();
93 } },
94 { "settingConfig/enableDeleteUnusedResourcesDelay",
__anon669529c30f02() 95 [](std::string& contentStr) {
96 return contentStr == "true" ? std::string("--ohos-enable-delete-unused-resources-delay") : std::string();
97 } },
98 { "settingConfig/enableSetHttpCacheMaxSize",
__anon669529c31002() 99 [](std::string& contentStr) {
100 return contentStr == "true" ? std::string("--ohos-enable-set-http-cache-max-size") : std::string();
101 } },
102 { "settingConfig/enableCookieConfigPersistSession",
__anon669529c31102() 103 [](std::string& contentStr) {
104 return contentStr == "true" ? std::string("--ohos-enable-cookie-config-persist-session") : std::string();
105 } },
106 { "settingConfig/enableDoubleTapForPlatform",
__anon669529c31202() 107 [](std::string& contentStr) {
108 return contentStr == "true" ? std::string("--ohos-enable-double-tap-for-platform") : std::string();
109 } },
110 { "settingConfig/enableIgnoreLockdownMode",
__anon669529c31302() 111 [](std::string& contentStr) {
112 return contentStr == "true" ? std::string("--ohos-enable-Ignore-lockdown-mode") : std::string();
113 } },
114 { "settingConfig/enablePrinting",
__anon669529c31402() 115 [](std::string& contentStr) {
116 return contentStr == "true" ? std::string("--ohos-enable-printing") : std::string();
117 } },
118 { "settingConfig/enableHttpCacheSimple",
__anon669529c31502() 119 [](std::string& contentStr) {
120 return contentStr == "true" ? std::string("--ohos-enable-http-cache-simple") : std::string();
121 } },
122 { "settingConfig/enableCalcTabletMode",
__anon669529c31602() 123 [](std::string& contentStr) {
124 return contentStr == "true" ? std::string("--ohos-enable-calc-tablet-mode") : std::string();
125 } },
126 { "outOfProcessGPUConfig/enableOopGpu",
__anon669529c31702() 127 [](std::string& contentStr) {
128 return contentStr == "true" ? std::string("--in-process-gpu") : std::string();
129 } },
130 { "enableVulkanConfig/enableVulkan",
__anon669529c31802() 131 [](std::string& contentStr) {
132 return contentStr == "true" ? std::string("--ohos-enable-vulkan") : std::string();
133 } }
134 };
135 } // namespace
136
137 namespace OHOS::NWeb {
Instance()138 NWebConfigHelper &NWebConfigHelper::Instance()
139 {
140 static NWebConfigHelper helper;
141 return helper;
142 }
143
ReadConfigIfNeeded()144 void NWebConfigHelper::ReadConfigIfNeeded()
145 {
146 if (perfConfig_.empty()) {
147 std::shared_ptr<NWebEngineInitArgsImpl> initArgs = std::make_shared<NWebEngineInitArgsImpl>();
148 NWebConfigHelper::Instance().ParseConfig(initArgs);
149 }
150 }
151
GetConfigPath(const std::string & configFileName)152 std::string NWebConfigHelper::GetConfigPath(const std::string &configFileName)
153 {
154 char buf[PATH_MAX + 1];
155 char *configPath = GetOneCfgFile(configFileName.c_str(), buf, PATH_MAX + 1);
156 char tmpPath[PATH_MAX + 1] = { 0 };
157 if (!configPath || strlen(configPath) == 0 || strlen(configPath) > PATH_MAX || !realpath(configPath, tmpPath)) {
158 WVLOG_I("can not get customization config file");
159 return "/system/" + configFileName;
160 }
161 return std::string(tmpPath);
162 }
163
ReadConfig(const xmlNodePtr & rootPtr,std::shared_ptr<NWebEngineInitArgsImpl> initArgs)164 void NWebConfigHelper::ReadConfig(const xmlNodePtr &rootPtr, std::shared_ptr<NWebEngineInitArgsImpl> initArgs)
165 {
166 for (xmlNodePtr curNodePtr = rootPtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
167 if (curNodePtr->name == nullptr || curNodePtr->type == XML_COMMENT_NODE) {
168 WVLOG_E("invalid node!");
169 continue;
170 }
171 std::string nodeName = reinterpret_cast<const char *>(curNodePtr->name);
172 for (xmlNodePtr curChildNodePtr = curNodePtr->xmlChildrenNode; curChildNodePtr != nullptr;
173 curChildNodePtr = curChildNodePtr->next) {
174 if (curChildNodePtr->name == nullptr || curChildNodePtr->type == XML_COMMENT_NODE) {
175 WVLOG_E("invalid node!");
176 continue;
177 }
178 std::string childNodeName = reinterpret_cast<const char *>(curChildNodePtr->name);
179 xmlChar *content = xmlNodeGetContent(curChildNodePtr);
180 if (content == nullptr) {
181 WVLOG_E("read xml node error: nodeName:(%{public}s)", curChildNodePtr->name);
182 continue;
183 }
184 std::string contentStr = reinterpret_cast<const char *>(content);
185 xmlFree(content);
186 auto it = configMap.find(nodeName + "/" + childNodeName);
187 if (it == configMap.end()) {
188 WVLOG_W("not found for web_config: %{public}s/%{public}s", nodeName.c_str(), childNodeName.c_str());
189 continue;
190 }
191 std::string param = it->second(contentStr);
192 if (!param.empty()) {
193 initArgs->AddArg(param);
194 }
195 }
196 }
197 }
198
GetChildrenNode(xmlNodePtr NodePtr,const std::string & childrenNodeName)199 xmlNodePtr NWebConfigHelper::GetChildrenNode(xmlNodePtr NodePtr, const std::string &childrenNodeName)
200 {
201 WVLOG_D("GetChildrenNode:(%{public}s)", childrenNodeName.c_str());
202 for (xmlNodePtr curNodePtr = NodePtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
203 if (curNodePtr->name == nullptr || curNodePtr->type == XML_COMMENT_NODE) {
204 WVLOG_E("invalid node!");
205 continue;
206 }
207 if (!xmlStrcmp(curNodePtr->name, reinterpret_cast<const xmlChar*>(childrenNodeName.c_str()))) {
208 return curNodePtr;
209 }
210 }
211 return nullptr;
212 }
213
ParseConfig(std::shared_ptr<NWebEngineInitArgsImpl> initArgs)214 void NWebConfigHelper::ParseConfig(std::shared_ptr<NWebEngineInitArgsImpl> initArgs)
215 {
216 CfgFiles* cfgFiles = GetCfgFiles(WEB_CONFIG_PATH.c_str());
217 std::string defaultConfigPath = "/system/" + WEB_CONFIG_PATH;
218 if (cfgFiles == nullptr) {
219 WVLOG_E("Not found webConfigxml,read system config");
220 ParseWebConfigXml(defaultConfigPath, initArgs);
221 return;
222 }
223
224 // When i is 0 ,it means /system/ + WEB_CONFIG_PATH, ignore
225 for (int32_t i = 1; i < MAX_CFG_POLICY_DIRS_CNT; i++) {
226 auto cfgFilePath = cfgFiles->paths[i];
227 if (!cfgFilePath || *(cfgFilePath) == '\0') {
228 break;
229 }
230 WVLOG_D("web config file path:%{public}s", cfgFilePath);
231 if (!cfgFilePath || strlen(cfgFilePath) == 0 || strlen(cfgFilePath) > PATH_MAX) {
232 WVLOG_W("can not get customization config file");
233 ParseWebConfigXml(defaultConfigPath, initArgs);
234 continue;
235 }
236 ParseWebConfigXml(cfgFiles->paths[i], initArgs);
237 }
238 FreeCfgFiles(cfgFiles);
239 }
240
ParseWebConfigXml(const std::string & configFilePath,std::shared_ptr<NWebEngineInitArgsImpl> initArgs)241 void NWebConfigHelper::ParseWebConfigXml(const std::string& configFilePath,
242 std::shared_ptr<NWebEngineInitArgsImpl> initArgs)
243 {
244 xmlDocPtr docPtr = xmlReadFile(configFilePath.c_str(), nullptr, XML_PARSE_NOBLANKS);
245 if (docPtr == nullptr) {
246 WVLOG_E("load xml error!");
247 return;
248 }
249
250 xmlNodePtr rootPtr = xmlDocGetRootElement(docPtr);
251 if (rootPtr == nullptr || rootPtr->name == nullptr ||
252 xmlStrcmp(rootPtr->name, reinterpret_cast<const xmlChar *>("WEB"))) {
253 WVLOG_E("get root element failed!");
254 xmlFreeDoc(docPtr);
255 return;
256 }
257
258 xmlNodePtr initNodePtr = GetChildrenNode(rootPtr, INIT_CONFIG);
259 if (initNodePtr != nullptr) {
260 WVLOG_D("read config from init node");
261 ReadConfig(initNodePtr, initArgs);
262 } else {
263 WVLOG_D("read config from root node");
264 ReadConfig(rootPtr, initArgs);
265 }
266
267 xmlNodePtr deleteNodePtr = GetChildrenNode(rootPtr, DELETE_CONFIG);
268 if (deleteNodePtr != nullptr) {
269 WVLOG_D("read config from delete node");
270 ParseDeleteConfig(deleteNodePtr, initArgs);
271 }
272
273 if (perfConfig_.empty()) {
274 xmlNodePtr perfNodePtr = GetChildrenNode(rootPtr, PERFORMANCE_CONFIG);
275 if (perfNodePtr != nullptr) {
276 ParsePerfConfig(perfNodePtr);
277 }
278 xmlNodePtr adapterNodePtr = GetChildrenNode(rootPtr, BASE_WEB_CONFIG);
279 if (adapterNodePtr != nullptr) {
280 ParsePerfConfig(adapterNodePtr);
281 }
282 }
283
284 if (ltpoConfig_.empty() && ltpoStrategy_ == 0) {
285 xmlNodePtr ltpoConfigNodePtr = GetChildrenNode(rootPtr, WEB_ANIMATION_DYNAMIC_SETTING_CONFIG);
286 if (ltpoConfigNodePtr != nullptr) {
287 ParseNWebLTPOConfig(ltpoConfigNodePtr);
288 }
289 }
290 xmlFreeDoc(docPtr);
291 }
292
ParseNWebLTPOConfig(xmlNodePtr nodePtr)293 void NWebConfigHelper::ParseNWebLTPOConfig(xmlNodePtr nodePtr)
294 {
295 for (xmlNodePtr curNodePtr = nodePtr->xmlChildrenNode; curNodePtr; curNodePtr = curNodePtr->next) {
296 if (curNodePtr->name == nullptr || curNodePtr->type == XML_COMMENT_NODE) {
297 WVLOG_E("invalid node!");
298 continue;
299 }
300 char* namePtr = (char *)xmlGetProp(curNodePtr, BAD_CAST(XML_ATTR_NAME));
301 if (!namePtr) {
302 WVLOG_E("invalid name!");
303 continue;
304 }
305 std::string settingName(namePtr);
306 xmlFree(namePtr);
307 if (settingName == WEB_ANIMATION_DYNAMIC_APP) {
308 ParseNWebLTPOApp(curNodePtr);
309 continue;
310 }
311 if (settingName == WEB_LTPO_STRATEGY) {
312 ParseNWebLTPOStrategy(curNodePtr);
313 continue;
314 }
315 std::vector<FrameRateSetting> frameRateSetting;
316 for (xmlNodePtr curDynamicNodePtr = curNodePtr->xmlChildrenNode; curDynamicNodePtr;
317 curDynamicNodePtr = curDynamicNodePtr->next) {
318 if (curDynamicNodePtr->name == nullptr || curDynamicNodePtr->type == XML_COMMENT_NODE) {
319 WVLOG_E("invalid node!");
320 continue;
321 }
322 FrameRateSetting setting;
323 int defaultValue = 0;
324 setting.min_ = safeGetPropAsInt(curDynamicNodePtr, BAD_CAST(XML_ATTR_MIN), defaultValue);
325 setting.max_ = safeGetPropAsInt(curDynamicNodePtr, BAD_CAST(XML_ATTR_MAX), defaultValue);
326 setting.preferredFrameRate_ = safeGetPropAsInt(curDynamicNodePtr, BAD_CAST(XML_ATTR_FPS), defaultValue);
327 if ((setting.max_ >= 0 && setting.min_ >= setting.max_) || setting.preferredFrameRate_ <= 0) {
328 continue;
329 }
330 frameRateSetting.emplace_back(setting);
331 }
332 ltpoConfig_[settingName] = frameRateSetting;
333 }
334 }
335
ParseNWebLTPOApp(xmlNodePtr nodePtr)336 void NWebConfigHelper::ParseNWebLTPOApp(xmlNodePtr nodePtr)
337 {
338 for (xmlNodePtr curDynamicNodePtr = nodePtr->xmlChildrenNode; curDynamicNodePtr;
339 curDynamicNodePtr = curDynamicNodePtr->next) {
340 if (curDynamicNodePtr->name == nullptr || curDynamicNodePtr->type == XML_COMMENT_NODE) {
341 WVLOG_E("invalid node!");
342 continue;
343 }
344 std::string bundleName = (char *)xmlGetProp(curDynamicNodePtr, BAD_CAST(XML_ATTR_NAME));
345 ltpoAllowedApps_.emplace(bundleName);
346 WVLOG_D("ltpo dynamic app: %{public}s", bundleName.c_str());
347 }
348 }
349
ParseNWebLTPOStrategy(xmlNodePtr nodePtr)350 void NWebConfigHelper::ParseNWebLTPOStrategy(xmlNodePtr nodePtr)
351 {
352 ltpoStrategy_ = atoi((char *)xmlNodeGetContent(nodePtr));
353 WVLOG_D("ltpo strategy is: %{public}d", ltpoStrategy_);
354 }
355
IsLTPODynamicApp(const std::string & bundleName)356 bool NWebConfigHelper::IsLTPODynamicApp(const std::string& bundleName)
357 {
358 return ltpoAllowedApps_.find(bundleName) != ltpoAllowedApps_.end();
359 }
360
GetLTPOStrategy()361 int32_t NWebConfigHelper::GetLTPOStrategy()
362 {
363 return ltpoStrategy_;
364 }
365
GetPerfConfig(const std::string & settingName)366 std::vector<FrameRateSetting> NWebConfigHelper::GetPerfConfig(const std::string& settingName)
367 {
368 if (ltpoConfig_.find(settingName) == ltpoConfig_.end()) {
369 WVLOG_E("%{public}s is not exist", settingName.c_str()) ;
370 return {};
371 }
372 return ltpoConfig_[settingName];
373 }
374
ParsePerfConfig(xmlNodePtr NodePtr)375 void NWebConfigHelper::ParsePerfConfig(xmlNodePtr NodePtr)
376 {
377 WVLOG_D("read performance config");
378 for (xmlNodePtr curNodePtr = NodePtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
379 if (curNodePtr->name == nullptr || curNodePtr->type == XML_COMMENT_NODE) {
380 WVLOG_E("invalid node!");
381 continue;
382 }
383 std::string nodeName = reinterpret_cast<const char*>(curNodePtr->name);
384 for (xmlNodePtr curChildNodePtr = curNodePtr->xmlChildrenNode; curChildNodePtr != nullptr;
385 curChildNodePtr = curChildNodePtr->next) {
386 if (curChildNodePtr->name == nullptr || curChildNodePtr->type == XML_COMMENT_NODE) {
387 WVLOG_E("invalid node!");
388 continue;
389 }
390 std::string childNodeName = reinterpret_cast<const char*>(curChildNodePtr->name);
391 xmlChar* content = xmlNodeGetContent(curChildNodePtr);
392 if (content == nullptr) {
393 WVLOG_E("read xml node error: nodeName:(%{public}s)", childNodeName.c_str());
394 continue;
395 }
396 std::string contentStr = reinterpret_cast<const char*>(content);
397 xmlFree(content);
398 perfConfig_.emplace(nodeName + "/" + childNodeName, contentStr);
399 WriteConfigValueToSysPara(nodeName + "/" + childNodeName, contentStr);
400 }
401 }
402 }
403
ParsePerfConfig(const std::string & configNodeName,const std::string & argsNodeName)404 std::string NWebConfigHelper::ParsePerfConfig(const std::string &configNodeName, const std::string &argsNodeName)
405 {
406 auto it = perfConfig_.find(configNodeName + "/" + argsNodeName);
407 if (it == perfConfig_.end()) {
408 WVLOG_W("not found perf config for web_config: %{public}s/%{public}s", configNodeName.c_str(),
409 argsNodeName.c_str());
410 return "";
411 }
412 WVLOG_D("find performance config %{public}s/%{public}s, value is %{public}s.", configNodeName.c_str(),
413 argsNodeName.c_str(), it->second.c_str());
414 return it->second;
415 }
416
WriteConfigValueToSysPara(const std::string & configName,const std::string & value)417 void NWebConfigHelper::WriteConfigValueToSysPara(const std::string &configName, const std::string &value)
418 {
419 if (configName == "flowBufferConfig/maxFdNumber") {
420 OHOS::system::SetParameter("web.flowbuffer.maxfd", value);
421 }
422 }
423
ParseDeleteConfig(const xmlNodePtr & rootPtr,std::shared_ptr<NWebEngineInitArgsImpl> initArgs)424 void NWebConfigHelper::ParseDeleteConfig(const xmlNodePtr &rootPtr, std::shared_ptr<NWebEngineInitArgsImpl> initArgs)
425 {
426 for (xmlNodePtr curNodePtr = rootPtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
427 if (curNodePtr->name == nullptr || curNodePtr->type == XML_COMMENT_NODE) {
428 WVLOG_E("invalid node!");
429 continue;
430 }
431 std::string nodeName = reinterpret_cast<const char *>(curNodePtr->name);
432 for (xmlNodePtr curChildNodePtr = curNodePtr->xmlChildrenNode; curChildNodePtr != nullptr;
433 curChildNodePtr = curChildNodePtr->next) {
434 if (curChildNodePtr->name == nullptr || curChildNodePtr->type == XML_COMMENT_NODE) {
435 WVLOG_E("invalid node!");
436 continue;
437 }
438 std::string childNodeName = reinterpret_cast<const char *>(curChildNodePtr->name);
439 xmlChar *content = xmlNodeGetContent(curChildNodePtr);
440 if (content == nullptr) {
441 WVLOG_E("read xml node error: nodeName:(%{public}s)", curChildNodePtr->name);
442 continue;
443 }
444 std::string contentStr = reinterpret_cast<const char *>(content);
445 xmlFree(content);
446 auto it = configMap.find(nodeName + "/" + childNodeName);
447 if (it == configMap.end()) {
448 WVLOG_W("not found for web_config: %{public}s/%{public}s", nodeName.c_str(), childNodeName.c_str());
449 continue;
450 }
451 std::string param = it->second(contentStr);
452 if (!param.empty()) {
453 initArgs->AddDeleteArg(param);
454 }
455 }
456 }
457 }
458
safeGetPropAsInt(xmlNode * node,const xmlChar * propName,int defaultValue)459 int NWebConfigHelper::safeGetPropAsInt(xmlNode* node, const xmlChar* propName, int defaultValue)
460 {
461 xmlChar* propValue = xmlGetProp(node, propName);
462 int value = (propValue) ? atoi((const char*)propValue) : defaultValue;
463 xmlFree(propValue);
464 return value;
465 }
466
SetBundleName(const std::string & bundleName)467 void NWebConfigHelper::SetBundleName(const std::string& bundleName)
468 {
469 bundleName_ = bundleName;
470 }
471
GetBundleName()472 std::string NWebConfigHelper::GetBundleName()
473 {
474 return bundleName_;
475 }
476
477 } // namespace OHOS::NWeb