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 auto XML_ATTR_NAME = "name";
40 const auto XML_ATTR_MIN = "min";
41 const auto XML_ATTR_MAX = "max";
42 const auto XML_ATTR_FPS = "preferred_fps";
43 const std::unordered_map<std::string_view, std::function<std::string(std::string&)>> configMap = {
44 { "renderConfig/renderProcessCount",
__anon6791e8bb0202() 45 [](std::string& contentStr) { return std::string("--renderer-process-limit=") + contentStr; } },
46 { "mediaConfig/backgroundMediaShouldSuspend",
__anon6791e8bb0302() 47 [](std::string& contentStr) {
48 return contentStr == "false" ? std::string("--disable-background-media-suspend") : std::string();
49 } },
50 { "loadurlSocPerfConfig/loadurlSocPerfParam",
__anon6791e8bb0402() 51 [](std::string& contentStr) {
52 return contentStr == "true" ? std::string("--ohos-enable-loadurl-soc-perf") : std::string();
53 } },
54 { "mouseWheelSocPerfConfig/mouseWheelSocPerfParam",
__anon6791e8bb0502() 55 [](std::string& contentStr) {
56 return contentStr == "true" ? std::string("--ohos-enable-mousewheel-soc-perf") : std::string();
57 } },
58 { "touchEventConfig/touchEventShouldRegister",
__anon6791e8bb0602() 59 [](std::string& contentStr) {
60 return contentStr == "false" ? std::string("--disable-touch-event-register") : std::string();
61 } },
62 { "settingConfig/enableWaitForUsername",
__anon6791e8bb0702() 63 [](std::string& contentStr) {
64 return contentStr == "true" ? std::string("--ohos-enable-wait-for-username") : std::string();
65 } },
66 { "settingConfig/enableMaxNumberOfSavedFrames",
__anon6791e8bb0802() 67 [](std::string& contentStr) {
68 return contentStr == "true" ? std::string("--ohos-enable-max-number-of-saved-frames") : std::string();
69 } },
70 { "settingConfig/enableNumRasterThreads",
__anon6791e8bb0902() 71 [](std::string& contentStr) {
72 return contentStr == "true" ? std::string("--ohos-enable-num-raster-threads") : std::string();
73 } },
74 { "settingConfig/enableSingleRenderProcess",
__anon6791e8bb0a02() 75 [](std::string& contentStr) {
76 return contentStr == "true" ? std::string("--ohos-enable-single-render-process") : std::string();
77 } },
78 { "userAgentConfig/userAgentValue",
__anon6791e8bb0b02() 79 [](std::string& contentStr) { return std::string("--ohos-user-agent-value=") + contentStr; } },
80 { "settingConfig/enableSimpleBackendIsDefault",
__anon6791e8bb0c02() 81 [](std::string& contentStr) {
82 return contentStr == "true" ? std::string("--ohos-enable-simple-backend-is-default") : std::string();
83 } },
84 { "settingConfig/enableEmbedMode",
__anon6791e8bb0d02() 85 [](std::string& contentStr) {
86 return contentStr == "true" ? std::string("--ohos-enable-embed-mode") : std::string();
87 } },
88 { "settingConfig/enableWebViewImplForLargeScreen",
__anon6791e8bb0e02() 89 [](std::string& contentStr) {
90 return contentStr == "true" ? std::string("--ohos-enable-web-view-impl-for-large-screen") : std::string();
91 } },
92 { "settingConfig/enableDeleteUnusedResourcesDelay",
__anon6791e8bb0f02() 93 [](std::string& contentStr) {
94 return contentStr == "true" ? std::string("--ohos-enable-delete-unused-resources-delay") : std::string();
95 } },
96 { "settingConfig/enableSetHttpCacheMaxSize",
__anon6791e8bb1002() 97 [](std::string& contentStr) {
98 return contentStr == "true" ? std::string("--ohos-enable-set-http-cache-max-size") : std::string();
99 } },
100 { "settingConfig/enableCookieConfigPersistSession",
__anon6791e8bb1102() 101 [](std::string& contentStr) {
102 return contentStr == "true" ? std::string("--ohos-enable-cookie-config-persist-session") : std::string();
103 } },
104 { "settingConfig/enableDoubleTapForPlatform",
__anon6791e8bb1202() 105 [](std::string& contentStr) {
106 return contentStr == "true" ? std::string("--ohos-enable-double-tap-for-platform") : std::string();
107 } },
108 { "settingConfig/enableIgnoreLockdownMode",
__anon6791e8bb1302() 109 [](std::string& contentStr) {
110 return contentStr == "true" ? std::string("--ohos-enable-Ignore-lockdown-mode") : std::string();
111 } },
112 { "settingConfig/enablePrinting",
__anon6791e8bb1402() 113 [](std::string& contentStr) {
114 return contentStr == "true" ? std::string("--ohos-enable-printing") : std::string();
115 } },
116 { "settingConfig/enableHttpCacheSimple",
__anon6791e8bb1502() 117 [](std::string& contentStr) {
118 return contentStr == "true" ? std::string("--ohos-enable-http-cache-simple") : std::string();
119 } },
120 { "settingConfig/enableCalcTabletMode",
__anon6791e8bb1602() 121 [](std::string& contentStr) {
122 return contentStr == "true" ? std::string("--ohos-enable-calc-tablet-mode") : std::string();
123 } },
124 { "outOfProcessGPUConfig/enableOopGpu",
__anon6791e8bb1702() 125 [](std::string& contentStr) { return contentStr == "true" ? std::string("--in-process-gpu") : std::string(); } }
126 };
127 } // namespace
128
129 namespace OHOS::NWeb {
Instance()130 NWebConfigHelper &NWebConfigHelper::Instance()
131 {
132 static NWebConfigHelper helper;
133 return helper;
134 }
135
ReadConfigIfNeeded()136 void NWebConfigHelper::ReadConfigIfNeeded()
137 {
138 if (perfConfig_.empty()) {
139 std::shared_ptr<NWebEngineInitArgsImpl> initArgs = std::make_shared<NWebEngineInitArgsImpl>();
140 NWebConfigHelper::Instance().ParseConfig(initArgs);
141 }
142 }
143
GetConfigPath(const std::string & configFileName)144 std::string NWebConfigHelper::GetConfigPath(const std::string &configFileName)
145 {
146 char buf[PATH_MAX + 1];
147 char *configPath = GetOneCfgFile(configFileName.c_str(), buf, PATH_MAX + 1);
148 char tmpPath[PATH_MAX + 1] = { 0 };
149 if (!configPath || strlen(configPath) == 0 || strlen(configPath) > PATH_MAX || !realpath(configPath, tmpPath)) {
150 WVLOG_I("can not get customization config file");
151 return "/system/" + configFileName;
152 }
153 return std::string(tmpPath);
154 }
155
ReadConfig(const xmlNodePtr & rootPtr,std::shared_ptr<NWebEngineInitArgsImpl> initArgs)156 void NWebConfigHelper::ReadConfig(const xmlNodePtr &rootPtr, std::shared_ptr<NWebEngineInitArgsImpl> initArgs)
157 {
158 for (xmlNodePtr curNodePtr = rootPtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
159 if (curNodePtr->name == nullptr || curNodePtr->type == XML_COMMENT_NODE) {
160 WVLOG_E("invalid node!");
161 continue;
162 }
163 std::string nodeName = reinterpret_cast<const char *>(curNodePtr->name);
164 for (xmlNodePtr curChildNodePtr = curNodePtr->xmlChildrenNode; curChildNodePtr != nullptr;
165 curChildNodePtr = curChildNodePtr->next) {
166 if (curChildNodePtr->name == nullptr || curChildNodePtr->type == XML_COMMENT_NODE) {
167 WVLOG_E("invalid node!");
168 continue;
169 }
170 std::string childNodeName = reinterpret_cast<const char *>(curChildNodePtr->name);
171 xmlChar *content = xmlNodeGetContent(curChildNodePtr);
172 if (content == nullptr) {
173 WVLOG_E("read xml node error: nodeName:(%{public}s)", curChildNodePtr->name);
174 continue;
175 }
176 std::string contentStr = reinterpret_cast<const char *>(content);
177 xmlFree(content);
178 auto it = configMap.find(nodeName + "/" + childNodeName);
179 if (it == configMap.end()) {
180 WVLOG_W("not found for web_config: %{public}s/%{public}s", nodeName.c_str(), childNodeName.c_str());
181 continue;
182 }
183 std::string param = it->second(contentStr);
184 if (!param.empty()) {
185 initArgs->AddArg(param);
186 }
187 }
188 }
189 }
190
GetChildrenNode(xmlNodePtr NodePtr,const std::string & childrenNodeName)191 xmlNodePtr NWebConfigHelper::GetChildrenNode(xmlNodePtr NodePtr, const std::string &childrenNodeName)
192 {
193 WVLOG_D("GetChildrenNode:(%{public}s)", childrenNodeName.c_str());
194 for (xmlNodePtr curNodePtr = NodePtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
195 if (curNodePtr->name == nullptr || curNodePtr->type == XML_COMMENT_NODE) {
196 WVLOG_E("invalid node!");
197 continue;
198 }
199 if (!xmlStrcmp(curNodePtr->name, reinterpret_cast<const xmlChar*>(childrenNodeName.c_str()))) {
200 return curNodePtr;
201 }
202 }
203 return nullptr;
204 }
205
ParseConfig(std::shared_ptr<NWebEngineInitArgsImpl> initArgs)206 void NWebConfigHelper::ParseConfig(std::shared_ptr<NWebEngineInitArgsImpl> initArgs)
207 {
208 CfgFiles* cfgFiles = GetCfgFiles(WEB_CONFIG_PATH.c_str());
209 std::string defaultConfigPath = "/system/" + WEB_CONFIG_PATH;
210 if (cfgFiles == nullptr) {
211 WVLOG_E("Not found webConfigxml,read system config");
212 ParseWebConfigXml(defaultConfigPath, initArgs);
213 return;
214 }
215
216 // When i is 0 ,it means /system/ + WEB_CONFIG_PATH, ignore
217 for (int32_t i = 1; i < MAX_CFG_POLICY_DIRS_CNT; i++) {
218 auto cfgFilePath = cfgFiles->paths[i];
219 if (!cfgFilePath || *(cfgFilePath) == '\0') {
220 break;
221 }
222 WVLOG_D("web config file path:%{public}s", cfgFilePath);
223 if (!cfgFilePath || strlen(cfgFilePath) == 0 || strlen(cfgFilePath) > PATH_MAX) {
224 WVLOG_W("can not get customization config file");
225 ParseWebConfigXml(defaultConfigPath, initArgs);
226 continue;
227 }
228 ParseWebConfigXml(cfgFiles->paths[i], initArgs);
229 }
230 FreeCfgFiles(cfgFiles);
231 }
232
ParseWebConfigXml(const std::string & configFilePath,std::shared_ptr<NWebEngineInitArgsImpl> initArgs)233 void NWebConfigHelper::ParseWebConfigXml(const std::string& configFilePath,
234 std::shared_ptr<NWebEngineInitArgsImpl> initArgs)
235 {
236 xmlDocPtr docPtr = xmlReadFile(configFilePath.c_str(), nullptr, XML_PARSE_NOBLANKS);
237 if (docPtr == nullptr) {
238 WVLOG_E("load xml error!");
239 return;
240 }
241
242 xmlNodePtr rootPtr = xmlDocGetRootElement(docPtr);
243 if (rootPtr == nullptr || rootPtr->name == nullptr ||
244 xmlStrcmp(rootPtr->name, reinterpret_cast<const xmlChar *>("WEB"))) {
245 WVLOG_E("get root element failed!");
246 xmlFreeDoc(docPtr);
247 return;
248 }
249
250 xmlNodePtr initNodePtr = GetChildrenNode(rootPtr, INIT_CONFIG);
251 if (initNodePtr != nullptr) {
252 WVLOG_D("read config from init node");
253 ReadConfig(initNodePtr, initArgs);
254 } else {
255 WVLOG_D("read config from root node");
256 ReadConfig(rootPtr, initArgs);
257 }
258
259 xmlNodePtr deleteNodePtr = GetChildrenNode(rootPtr, DELETE_CONFIG);
260 if (deleteNodePtr != nullptr) {
261 WVLOG_D("read config from delete node");
262 ParseDeleteConfig(deleteNodePtr, initArgs);
263 }
264
265 if (perfConfig_.empty()) {
266 xmlNodePtr perfNodePtr = GetChildrenNode(rootPtr, PERFORMANCE_CONFIG);
267 if (perfNodePtr != nullptr) {
268 ParsePerfConfig(perfNodePtr);
269 }
270 xmlNodePtr adapterNodePtr = GetChildrenNode(rootPtr, BASE_WEB_CONFIG);
271 if (adapterNodePtr != nullptr) {
272 ParsePerfConfig(adapterNodePtr);
273 }
274 }
275
276 if (ltpoConfig_.empty()) {
277 xmlNodePtr ltpoConfigNodePtr = GetChildrenNode(rootPtr, WEB_ANIMATION_DYNAMIC_SETTING_CONFIG);
278 if (ltpoConfigNodePtr != nullptr) {
279 ParseNWebLTPOConfig(ltpoConfigNodePtr);
280 }
281 }
282 xmlFreeDoc(docPtr);
283 }
284
ParseNWebLTPOConfig(xmlNodePtr nodePtr)285 void NWebConfigHelper::ParseNWebLTPOConfig(xmlNodePtr nodePtr)
286 {
287 for (xmlNodePtr curNodePtr = nodePtr->xmlChildrenNode; curNodePtr; curNodePtr = curNodePtr->next) {
288 if (curNodePtr->name == nullptr || curNodePtr->type == XML_COMMENT_NODE) {
289 WVLOG_E("invalid node!");
290 continue;
291 }
292 char* namePtr = (char *)xmlGetProp(curNodePtr, BAD_CAST(XML_ATTR_NAME));
293 if (!namePtr) {
294 WVLOG_E("invalid name!");
295 continue;
296 }
297 std::string settingName(namePtr);
298 xmlFree(namePtr);
299 std::vector<FrameRateSetting> frameRateSetting;
300 for (xmlNodePtr curDynamicNodePtr = curNodePtr->xmlChildrenNode; curDynamicNodePtr;
301 curDynamicNodePtr = curDynamicNodePtr->next) {
302 if (curDynamicNodePtr->name == nullptr || curDynamicNodePtr->type == XML_COMMENT_NODE) {
303 WVLOG_E("invalid node!");
304 continue;
305 }
306 FrameRateSetting setting;
307 int defaultValue = 0;
308 setting.min_ = safeGetPropAsInt(curDynamicNodePtr, BAD_CAST(XML_ATTR_MIN), defaultValue);
309 setting.max_ = safeGetPropAsInt(curDynamicNodePtr, BAD_CAST(XML_ATTR_MAX), defaultValue);
310 setting.preferredFrameRate_ = safeGetPropAsInt(curDynamicNodePtr, BAD_CAST(XML_ATTR_FPS), defaultValue);
311 if ((setting.max_ >= 0 && setting.min_ >= setting.max_) || setting.preferredFrameRate_ <= 0) {
312 continue;
313 }
314 frameRateSetting.emplace_back(setting);
315 }
316 ltpoConfig_[settingName] = frameRateSetting;
317 }
318 }
319
GetPerfConfig(const std::string & settingName)320 std::vector<FrameRateSetting> NWebConfigHelper::GetPerfConfig(const std::string& settingName)
321 {
322 if (ltpoConfig_.find(settingName) == ltpoConfig_.end()) {
323 WVLOG_E("%{public}s is not exist", settingName.c_str()) ;
324 return {};
325 }
326 return ltpoConfig_[settingName];
327 }
328
ParsePerfConfig(xmlNodePtr NodePtr)329 void NWebConfigHelper::ParsePerfConfig(xmlNodePtr NodePtr)
330 {
331 WVLOG_D("read performance config");
332 for (xmlNodePtr curNodePtr = NodePtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
333 if (curNodePtr->name == nullptr || curNodePtr->type == XML_COMMENT_NODE) {
334 WVLOG_E("invalid node!");
335 continue;
336 }
337 std::string nodeName = reinterpret_cast<const char*>(curNodePtr->name);
338 for (xmlNodePtr curChildNodePtr = curNodePtr->xmlChildrenNode; curChildNodePtr != nullptr;
339 curChildNodePtr = curChildNodePtr->next) {
340 if (curChildNodePtr->name == nullptr || curChildNodePtr->type == XML_COMMENT_NODE) {
341 WVLOG_E("invalid node!");
342 continue;
343 }
344 std::string childNodeName = reinterpret_cast<const char*>(curChildNodePtr->name);
345 xmlChar* content = xmlNodeGetContent(curChildNodePtr);
346 if (content == nullptr) {
347 WVLOG_E("read xml node error: nodeName:(%{public}s)", childNodeName.c_str());
348 continue;
349 }
350 std::string contentStr = reinterpret_cast<const char*>(content);
351 xmlFree(content);
352 perfConfig_.emplace(nodeName + "/" + childNodeName, contentStr);
353 WriteConfigValueToSysPara(nodeName + "/" + childNodeName, contentStr);
354 }
355 }
356 }
357
ParsePerfConfig(const std::string & configNodeName,const std::string & argsNodeName)358 std::string NWebConfigHelper::ParsePerfConfig(const std::string &configNodeName, const std::string &argsNodeName)
359 {
360 auto it = perfConfig_.find(configNodeName + "/" + argsNodeName);
361 if (it == perfConfig_.end()) {
362 WVLOG_W("not found perf config for web_config: %{public}s/%{public}s", configNodeName.c_str(),
363 argsNodeName.c_str());
364 return "";
365 }
366 WVLOG_D("find performance config %{public}s/%{public}s, value is %{public}s.", configNodeName.c_str(),
367 argsNodeName.c_str(), it->second.c_str());
368 return it->second;
369 }
370
WriteConfigValueToSysPara(const std::string & configName,const std::string & value)371 void NWebConfigHelper::WriteConfigValueToSysPara(const std::string &configName, const std::string &value)
372 {
373 if (configName == "flowBufferConfig/maxFdNumber") {
374 OHOS::system::SetParameter("web.flowbuffer.maxfd", value);
375 }
376 }
377
ParseDeleteConfig(const xmlNodePtr & rootPtr,std::shared_ptr<NWebEngineInitArgsImpl> initArgs)378 void NWebConfigHelper::ParseDeleteConfig(const xmlNodePtr &rootPtr, std::shared_ptr<NWebEngineInitArgsImpl> initArgs)
379 {
380 for (xmlNodePtr curNodePtr = rootPtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
381 if (curNodePtr->name == nullptr || curNodePtr->type == XML_COMMENT_NODE) {
382 WVLOG_E("invalid node!");
383 continue;
384 }
385 std::string nodeName = reinterpret_cast<const char *>(curNodePtr->name);
386 for (xmlNodePtr curChildNodePtr = curNodePtr->xmlChildrenNode; curChildNodePtr != nullptr;
387 curChildNodePtr = curChildNodePtr->next) {
388 if (curChildNodePtr->name == nullptr || curChildNodePtr->type == XML_COMMENT_NODE) {
389 WVLOG_E("invalid node!");
390 continue;
391 }
392 std::string childNodeName = reinterpret_cast<const char *>(curChildNodePtr->name);
393 xmlChar *content = xmlNodeGetContent(curChildNodePtr);
394 if (content == nullptr) {
395 WVLOG_E("read xml node error: nodeName:(%{public}s)", curChildNodePtr->name);
396 continue;
397 }
398 std::string contentStr = reinterpret_cast<const char *>(content);
399 xmlFree(content);
400 auto it = configMap.find(nodeName + "/" + childNodeName);
401 if (it == configMap.end()) {
402 WVLOG_W("not found for web_config: %{public}s/%{public}s", nodeName.c_str(), childNodeName.c_str());
403 continue;
404 }
405 std::string param = it->second(contentStr);
406 if (!param.empty()) {
407 initArgs->AddDeleteArg(param);
408 }
409 }
410 }
411 }
412
safeGetPropAsInt(xmlNode * node,const xmlChar * propName,int defaultValue)413 int NWebConfigHelper::safeGetPropAsInt(xmlNode* node, const xmlChar* propName, int defaultValue)
414 {
415 xmlChar* propValue = xmlGetProp(node, propName);
416 if (propValue == nullptr) {
417 return defaultValue;
418 }
419 int value = atoi((const char*)propValue);
420 xmlFree(propValue);
421 return value;
422 }
423
424 } // namespace OHOS::NWeb
425