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