1 /*
2  * Copyright (C) 2023-2023 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 "wifi_app_parser.h"
16 #include <unordered_map>
17 #include "wifi_common_def.h"
18 #include "wifi_config_file_impl.h"
19 #include <algorithm>
20 #include "wifi_logger.h"
21 #include "json/json.h"
22 
23 namespace OHOS {
24 namespace Wifi {
25 DEFINE_WIFILOG_LABEL("WifiAppXmlParser");
26 
27 constexpr auto WIFI_MONITOR_APP_FILE_PATH = "/system/etc/wifi/wifi_monitor_apps.xml";
28 constexpr auto WIFI_MONITOR_CLOUD_PUSH_INSTALL_PATH = "/data/service/el1/public/update/param_service/install/system/";
29 constexpr auto WIFI_MONITOR_CLOUD_PUSH_FILE_PATH = "etc/WifiHighTemSpeedLimit/";
30 constexpr auto WIFI_MONITOR_CLOUD_PUSH_VERIOSN_FILE_NAME = "version.txt";
31 constexpr auto WIFI_MONITOR_CLOUD_PUSH_FILE_NAME = "HighTemperatureSpeedLimit.json";
32 constexpr auto XML_TAG_SECTION_HEADER_MONITOR_APP = "MonitorAPP";
33 constexpr auto XML_TAG_SECTION_HEADER_GAME_INFO = "GameInfo";
34 constexpr auto XML_TAG_SECTION_HEADER_APP_WHITE_LIST = "AppWhiteList";
35 constexpr auto XML_TAG_SECTION_HEADER_APP_BLACK_LIST = "AppBlackList";
36 constexpr auto XML_TAG_SECTION_HEADER_MULTILINK_BLACK_LIST = "MultiLinkBlackList";
37 constexpr auto XML_TAG_SECTION_HEADER_CHARIOT_APP = "ChariotApp";
38 constexpr auto XML_TAG_SECTION_HEADER_HIGH_TEMP_LIMIT_SPEED_APP = "HighTempLimitSpeedApp";
39 constexpr auto XML_TAG_SECTION_KEY_GAME_NAME = "gameName";
40 constexpr auto XML_TAG_SECTION_KEY_PACKAGE_NAME = "packageName";
41 constexpr auto VERSION_FILE_MAX_LINE = 50;
42 constexpr auto VERSION_FILE_KEY_WORD = "version=";
43 const char* XML_VERSION_NODE_NAME = "HighTempLimitSpeedAppVersionInfo";
44 
45 const std::unordered_map<std::string, AppType> appTypeMap = {
46     { XML_TAG_SECTION_HEADER_GAME_INFO, AppType::LOW_LATENCY_APP },
47     { XML_TAG_SECTION_HEADER_APP_WHITE_LIST, AppType::WHITE_LIST_APP },
48     { XML_TAG_SECTION_HEADER_APP_BLACK_LIST, AppType::BLACK_LIST_APP },
49     { XML_TAG_SECTION_HEADER_MULTILINK_BLACK_LIST, AppType::MULTILINK_BLACK_LIST_APP },
50     { XML_TAG_SECTION_HEADER_CHARIOT_APP, AppType::CHARIOT_APP },
51     {XML_TAG_SECTION_HEADER_HIGH_TEMP_LIMIT_SPEED_APP, AppType::HIGH_TEMP_LIMIT_SPEED_APP},
52 };
53 
AppParser()54 AppParser::AppParser()
55 {
56     WIFI_LOGI("%{public}s enter", __FUNCTION__);
57 }
58 
~AppParser()59 AppParser::~AppParser()
60 {
61     WIFI_LOGI("%{public}s enter", __FUNCTION__);
62 }
63 
GetInstance()64 AppParser &AppParser::GetInstance()
65 {
66     static AppParser instance;
67     return instance;
68 }
69 
Init()70 bool AppParser::Init()
71 {
72     if (!initFlag_) {
73         if (IsReadCloudConfig()) {
74             ReadPackageCloudFilterConfig();
75         }
76         if (InitAppParser(WIFI_MONITOR_APP_FILE_PATH)) {
77             initFlag_ = true;
78             WIFI_LOGD("%{public}s InitAppParser successful", __FUNCTION__);
79         } else {
80             WIFI_LOGE("%{public}s InitAppParser fail", __FUNCTION__);
81         };
82     }
83     return initFlag_;
84 }
85 
IsLowLatencyApp(const std::string & bundleName) const86 bool AppParser::IsLowLatencyApp(const std::string &bundleName) const
87 {
88     return std::any_of(m_lowLatencyAppVec.begin(), m_lowLatencyAppVec.end(),
89         [bundleName](const LowLatencyAppInfo &app) { return app.packageName == bundleName; });
90 }
91 
IsWhiteListApp(const std::string & bundleName) const92 bool AppParser::IsWhiteListApp(const std::string &bundleName) const
93 {
94     return std::any_of(m_whiteAppVec.begin(), m_whiteAppVec.end(),
95         [bundleName](const WhiteListAppInfo &app) { return app.packageName == bundleName; });
96 }
97 
IsBlackListApp(const std::string & bundleName) const98 bool AppParser::IsBlackListApp(const std::string &bundleName) const
99 {
100     return std::any_of(m_blackAppVec.begin(), m_blackAppVec.end(),
101         [bundleName](const BlackListAppInfo &app) { return app.packageName == bundleName; });
102 }
103 
IsMultiLinkApp(const std::string & bundleName) const104 bool AppParser::IsMultiLinkApp(const std::string &bundleName) const
105 {
106     return std::any_of(m_multilinkAppVec.begin(), m_multilinkAppVec.end(),
107         [bundleName](const MultiLinkAppInfo &app) { return app.packageName == bundleName; });
108 }
109 
IsChariotApp(const std::string & bundleName) const110 bool AppParser::IsChariotApp(const std::string &bundleName) const
111 {
112     return std::any_of(m_chariotAppVec.begin(), m_chariotAppVec.end(),
113         [bundleName](const ChariotAppInfo &app) { return app.packageName == bundleName; });
114 }
115 
IsHighTempLimitSpeedApp(const std::string & bundleName) const116 bool AppParser::IsHighTempLimitSpeedApp(const std::string &bundleName) const
117 {
118     if (mIshighTempLimitSpeedReadCloudPush) {
119         return std::any_of(m_highTempLimitSpeedAppVecCloudPush.begin(), m_highTempLimitSpeedAppVecCloudPush.end(),
120             [bundleName](const HighTempLimitSpeedAppInfo &app) { return app.packageName == bundleName; });
121     } else {
122         return std::any_of(m_highTempLimitSpeedAppVec.begin(), m_highTempLimitSpeedAppVec.end(),
123             [bundleName](const HighTempLimitSpeedAppInfo &app) { return app.packageName == bundleName; });
124     }
125 }
126 
InitAppParser(const char * appXmlFilePath)127 bool AppParser::InitAppParser(const char *appXmlFilePath)
128 {
129     if (appXmlFilePath == nullptr) {
130         WIFI_LOGE("%{public}s appXmlFilePath is null", __FUNCTION__);
131         return false;
132     }
133     std::string xmlPath(appXmlFilePath);
134     std::filesystem::path pathName = xmlPath;
135     std::error_code code;
136     if (!std::filesystem::exists(pathName, code)) {
137         WIFI_LOGE("%{public}s %{public}s not exists", __FUNCTION__, appXmlFilePath);
138         return false;
139     }
140     bool ret = LoadConfiguration(appXmlFilePath);
141     if (!ret) {
142         WIFI_LOGE("%{public}s load failed", __FUNCTION__);
143         return ret;
144     }
145     ret = Parse();
146     if (!ret) {
147         WIFI_LOGE("%{public}s parse failed", __FUNCTION__);
148         return ret;
149     }
150     WIFI_LOGD("%{public}s, wifi monitor app xml parsed successfully", __FUNCTION__);
151     return ret;
152 }
153 
ParseInternal(xmlNodePtr node)154 bool AppParser::ParseInternal(xmlNodePtr node)
155 {
156     if (node == nullptr) {
157         WIFI_LOGE("%{public}s node is null", __FUNCTION__);
158         return false;
159     }
160     ParseAppList(node);
161     return true;
162 }
163 
ParseAppList(const xmlNodePtr & innode)164 void AppParser::ParseAppList(const xmlNodePtr &innode)
165 {
166     if (xmlStrcmp(innode->name, BAD_CAST(XML_TAG_SECTION_HEADER_MONITOR_APP)) != 0) {
167         WIFI_LOGE("innode name=%{public}s not equal MonitorAPP", innode->name);
168         return;
169     }
170     m_lowLatencyAppVec.clear();
171     m_whiteAppVec.clear();
172     m_blackAppVec.clear();
173     m_multilinkAppVec.clear();
174     m_chariotAppVec.clear();
175     m_highTempLimitSpeedAppVec.clear();
176     for (xmlNodePtr node = innode->children; node != nullptr; node = node->next) {
177         switch (GetAppTypeAsInt(node)) {
178             case AppType::LOW_LATENCY_APP:
179                 m_lowLatencyAppVec.push_back(ParseLowLatencyAppInfo(node));
180                 break;
181             case AppType::WHITE_LIST_APP:
182                 m_whiteAppVec.push_back(ParseWhiteAppInfo(node));
183                 break;
184             case AppType::BLACK_LIST_APP:
185                 m_blackAppVec.push_back(ParseBlackAppInfo(node));
186                 break;
187             case AppType::MULTILINK_BLACK_LIST_APP:
188                 m_multilinkAppVec.push_back(ParseMultiLinkAppInfo(node));
189                 break;
190             case AppType::CHARIOT_APP:
191                 m_chariotAppVec.push_back(ParseChariotAppInfo(node));
192                 break;
193             case AppType::HIGH_TEMP_LIMIT_SPEED_APP:
194                 m_highTempLimitSpeedAppVec.push_back(ParseHighTempLimitSpeedAppInfo(node));
195                 break;
196             default:
197                 WIFI_LOGD("app type: %{public}s is not monitored", GetNodeValue(node).c_str());
198                 break;
199         }
200     }
201     WIFI_LOGI("%{public}s out,m_highTempLimitSpeedAppVec count:%{public}d!",
202         __FUNCTION__, (int)m_highTempLimitSpeedAppVec.size());
203     WIFI_LOGI("%{public}s out,m_multilinkAppVec count:%{public}d!",
204         __FUNCTION__, (int)m_multilinkAppVec.size());
205 }
206 
ParseLowLatencyAppInfo(const xmlNodePtr & innode)207 LowLatencyAppInfo AppParser::ParseLowLatencyAppInfo(const xmlNodePtr &innode)
208 {
209     LowLatencyAppInfo appInfo;
210     xmlChar *value = xmlGetProp(innode, BAD_CAST(XML_TAG_SECTION_KEY_GAME_NAME));
211     std::string gameName = std::string(reinterpret_cast<char *>(value));
212     appInfo.packageName = gameName;
213     xmlFree(value);
214     return appInfo;
215 }
216 
ParseWhiteAppInfo(const xmlNodePtr & innode)217 WhiteListAppInfo AppParser::ParseWhiteAppInfo(const xmlNodePtr &innode)
218 {
219     WhiteListAppInfo appInfo;
220     xmlChar *value = xmlGetProp(innode, BAD_CAST(XML_TAG_SECTION_KEY_PACKAGE_NAME));
221     std::string packageName = std::string(reinterpret_cast<char *>(value));
222     appInfo.packageName = packageName;
223     xmlFree(value);
224     return appInfo;
225 }
226 
ParseBlackAppInfo(const xmlNodePtr & innode)227 BlackListAppInfo AppParser::ParseBlackAppInfo(const xmlNodePtr &innode)
228 {
229     BlackListAppInfo appInfo;
230     xmlChar *value = xmlGetProp(innode, BAD_CAST(XML_TAG_SECTION_KEY_PACKAGE_NAME));
231     std::string packageName = std::string(reinterpret_cast<char *>(value));
232     appInfo.packageName = packageName;
233     xmlFree(value);
234     return appInfo;
235 }
236 
ParseMultiLinkAppInfo(const xmlNodePtr & innode)237 MultiLinkAppInfo AppParser::ParseMultiLinkAppInfo(const xmlNodePtr &innode)
238 {
239     MultiLinkAppInfo appInfo;
240     xmlChar *value = xmlGetProp(innode, BAD_CAST(XML_TAG_SECTION_KEY_PACKAGE_NAME));
241     std::string packageName = std::string(reinterpret_cast<char *>(value));
242     appInfo.packageName = packageName;
243     WIFI_LOGD("%{public}s packageName:%{public}s", __FUNCTION__, packageName.c_str());
244     xmlFree(value);
245     return appInfo;
246 }
247 
ParseChariotAppInfo(const xmlNodePtr & innode)248 ChariotAppInfo AppParser::ParseChariotAppInfo(const xmlNodePtr &innode)
249 {
250     ChariotAppInfo appInfo;
251     xmlChar *value = xmlGetProp(innode, BAD_CAST(XML_TAG_SECTION_KEY_PACKAGE_NAME));
252     std::string packageName = std::string(reinterpret_cast<char *>(value));
253     appInfo.packageName = packageName;
254     xmlFree(value);
255     return appInfo;
256 }
257 
ParseHighTempLimitSpeedAppInfo(const xmlNodePtr & innode)258 HighTempLimitSpeedAppInfo AppParser::ParseHighTempLimitSpeedAppInfo(const xmlNodePtr &innode)
259 {
260     HighTempLimitSpeedAppInfo appInfo;
261     xmlChar *value = xmlGetProp(innode, BAD_CAST(XML_TAG_SECTION_KEY_PACKAGE_NAME));
262     std::string packageName = std::string(reinterpret_cast<char *>(value));
263     appInfo.packageName = packageName;
264     xmlFree(value);
265     return appInfo;
266 }
267 
GetAppTypeAsInt(const xmlNodePtr & innode)268 AppType AppParser::GetAppTypeAsInt(const xmlNodePtr &innode)
269 {
270     std::string tagName = GetNodeValue(innode);
271     if (appTypeMap.find(tagName) != appTypeMap.end()) {
272         return appTypeMap.at(tagName);
273     }
274     WIFI_LOGD("%{public}s not find targName:%{public}s in appTypeMap", __FUNCTION__, tagName.c_str());
275     return AppType::OTHER_APP;
276 }
277 
ReadPackageCloudFilterConfig()278 bool AppParser::ReadPackageCloudFilterConfig()
279 {
280     WIFI_LOGI("%{public}s enter!", __FUNCTION__);
281     std::ifstream ifs;
282     ifs.open(GetCloudPushJsonFilePath().c_str());
283     if (!ifs.is_open()) {
284         WIFI_LOGE("%{public}s json file not exist,%{public}s!", __FUNCTION__, GetCloudPushJsonFilePath().c_str());
285         return false;
286     }
287     std::stringstream buffer;
288     buffer << ifs.rdbuf();
289     std::string jsonString = buffer.str();
290     Json::Value root;
291     Json::Reader reader;
292     ifs.close();
293     bool success = reader.parse(jsonString, root);
294     if (!success) {
295         WIFI_LOGE("%{public}s Failed to parse JSON data!", __FUNCTION__);
296         return false;
297     }
298     if (!root.isMember("HighTemperatureSpeedLimit")) {
299         WIFI_LOGE("%{public}s Failed to parse JSON data,no member HighTemperatureSpeedLimit!", __FUNCTION__);
300         return false;
301     }
302     int nSize = 0;
303     m_highTempLimitSpeedAppVecCloudPush.clear();
304     Json::Value packageName = root["HighTemperatureSpeedLimit"];
305     if (packageName.isArray()) {
306         m_highTempLimitSpeedAppVecCloudPush.clear();
307         HighTempLimitSpeedAppInfo appInfo;
308         nSize = (int)packageName.size();
309         for (int i = 0; i < nSize; ++i) {
310             appInfo.packageName = packageName[i].asString();
311             m_highTempLimitSpeedAppVecCloudPush.push_back(appInfo);
312         }
313     } else {
314         WIFI_LOGE("%{public}s Failed , JSON data Not ARRAY!", __FUNCTION__);
315         return false;
316     }
317     WIFI_LOGI("%{public}s out,count:%{public}d!", __FUNCTION__, nSize);
318     return true;
319 }
320 
IsReadCloudConfig()321 bool AppParser::IsReadCloudConfig()
322 {
323     std::string strLocal = GetLocalFileVersion(WIFI_MONITOR_APP_FILE_PATH);
324     std::string strCloud = GetCloudPushFileVersion(GetCloudPushVersionFilePath().c_str());
325     bool isReadCloudConfig = (strCloud > strLocal) || (strCloud.empty() && strLocal.empty());
326     WIFI_LOGI("%{public}s out,IsReadCloudConfig:%{public}d,strLocal=%{public}s,strCloud =%{public}s !", __FUNCTION__,
327         isReadCloudConfig, strLocal.c_str(), strCloud.c_str());
328     mIshighTempLimitSpeedReadCloudPush = isReadCloudConfig;
329     return isReadCloudConfig;
330 }
331 
GetCloudPushFileVersion(const char * appVersionFilePath)332 std::string AppParser::GetCloudPushFileVersion(const char *appVersionFilePath)
333 {
334     if (appVersionFilePath == nullptr) {
335         return "";
336     }
337     std::string strFileVersion = "";
338     std::ifstream ifs;
339     ifs.open(appVersionFilePath);
340     bool isVersionFileExist = ifs.is_open();
341     if (!isVersionFileExist) {
342         WIFI_LOGE("%{public}s %{public}s not exists", __FUNCTION__, appVersionFilePath);
343         return strFileVersion;
344     }
345     int nLineCount = 0;
346     std::string strTemp = "";
347     while (getline(ifs, strTemp)) {
348         if (nLineCount > VERSION_FILE_MAX_LINE) {
349             WIFI_LOGE("%{public}s %{public}s Failed to parse local version data!", __FUNCTION__, appVersionFilePath);
350             break;
351         }
352         nLineCount++;
353         int nPos = strTemp.find(VERSION_FILE_KEY_WORD);
354         if (nPos != -1) {
355             strFileVersion = strTemp.substr(nPos + strlen(VERSION_FILE_KEY_WORD),
356                 strTemp.length() - nPos - strlen(VERSION_FILE_KEY_WORD));
357             break;
358         }
359     }
360     ifs.close();
361     return strFileVersion;
362 }
363 
GetLocalFileVersion(const char * appXmlVersionFilePath)364 std::string AppParser::GetLocalFileVersion(const char *appXmlVersionFilePath)
365 {
366     WIFI_LOGI("%{public}s enter!", __FUNCTION__);
367     std::string strFileVersion = "";
368     if (appXmlVersionFilePath == nullptr) {
369         WIFI_LOGE("%{public}s appXmlVersionFilePath null!", __FUNCTION__);
370         return strFileVersion;
371     }
372     std::string xmlPath(appXmlVersionFilePath);
373     std::filesystem::path pathName = xmlPath;
374     std::error_code code;
375     if (!std::filesystem::exists(xmlPath, code)) {
376         WIFI_LOGE("%{public}s %{public}s not exists", __FUNCTION__, appXmlVersionFilePath);
377         return strFileVersion;
378     }
379     xmlDoc *xmlObj = xmlReadFile(appXmlVersionFilePath, nullptr, XML_PARSE_NOBLANKS);
380     if (xmlObj == nullptr) {
381         WIFI_LOGE("%{public}s xmlReadFile failed", __FUNCTION__);
382         return strFileVersion;
383     }
384     do {
385         xmlNodePtr root = xmlDocGetRootElement(xmlObj);
386         if (root == nullptr) {
387             WIFI_LOGE("%{public}s Parse root null!", __FUNCTION__);
388             break;
389         }
390         xmlNodePtr cur = root;
391         xmlNodePtr pNode = nullptr;
392         cur = cur->xmlChildrenNode;
393         while (cur != NULL) {
394             if ((xmlStrcmp(cur->name, (const xmlChar *)XML_VERSION_NODE_NAME)==0)) {
395                 pNode = cur;
396                 break;
397             }
398             cur = cur->next;
399         }
400         if (pNode == nullptr) {
401             WIFI_LOGE("%{public}s VersionInfo not find", __FUNCTION__);
402             break;
403         }
404         strFileVersion = GetStringValue(pNode);
405     } while (0);
406 
407     if (xmlObj != nullptr) {
408         xmlFreeDoc(xmlObj);
409         xmlCleanupParser();
410         xmlObj = nullptr;
411     }
412     return strFileVersion;
413 }
414 
GetCloudPushVersionFilePath()415 std::string AppParser::GetCloudPushVersionFilePath()
416 {
417     std::string path = WIFI_MONITOR_CLOUD_PUSH_INSTALL_PATH;
418     path += WIFI_MONITOR_CLOUD_PUSH_FILE_PATH;
419     return path + WIFI_MONITOR_CLOUD_PUSH_VERIOSN_FILE_NAME;
420 }
421 
GetCloudPushJsonFilePath()422 std::string AppParser::GetCloudPushJsonFilePath()
423 {
424     std::string path = WIFI_MONITOR_CLOUD_PUSH_INSTALL_PATH;
425     path += WIFI_MONITOR_CLOUD_PUSH_FILE_PATH;
426     return path + WIFI_MONITOR_CLOUD_PUSH_FILE_NAME;
427 }
428 } // namespace Wifi
429 } // namespace OHOS