1/*
2 * Copyright (c) 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#include <cstdlib>
16#include <string>
17#include <climits>
18
19#include "config_reader.h"
20#include "config_policy_utils.h"
21#include "concurrent_task_log.h"
22#include "parameters.h"
23
24using namespace std;
25
26namespace OHOS {
27namespace ConcurrentTask {
28namespace {
29    const std::string XML_TAG_QOS_CONFIG = "qosconfig";
30    const std::string XML_TAG_QOS_AUTH = "auth";
31    const std::string XML_TAG_UIDLIST = "uidlist";
32    const std::string XML_TAG_UID = "uid";
33    const std::string XML_TAG_BUNDLENAMELIST = "bundlenamelist";
34    const std::string XML_TAG_BUNDLENAME = "bundlename";
35    const std::string XML_TAG_POWER_MODE = "powermode";
36    const std::string XML_TAG_SWITCH = "switch";
37    const std::string XML_TAG_FPS = "fps";
38    const std::string XML_TAG_DEGRADATION_FPS = "degradationfps";
39    const std::string XML_TAG_FPS_HIGH = "120";
40    const std::string XML_TAG_FPS_MEDIUM = "90";
41    const std::string XML_TAG_FPS_STANDARD = "60";
42    constexpr int FPS_OFFSET = 10000;
43}
44
45bool ConfigReader::IsValidNode(const xmlNode* currNode)
46{
47    if (!currNode) {
48        return false;
49    }
50    if (!currNode->name || currNode->type == XML_COMMENT_NODE) {
51        return false;
52    }
53    return true;
54}
55
56bool ConfigReader::FillinUidInfo(const xmlNode* currNode)
57{
58    if (!IsValidNode(currNode)) {
59        CONCUR_LOGE("FillinUidInfo:: currNode is nullptr!");
60        return false;
61    }
62    xmlNodePtr currNodePtr = currNode->xmlChildrenNode;
63    for (; currNodePtr; currNodePtr = currNodePtr->next) {
64        if (xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_UID.c_str())) == 0) {
65            xmlChar *attrValue = xmlGetProp(currNodePtr, reinterpret_cast<const xmlChar*>(XML_TAG_UID.c_str()));
66            if (!attrValue) {
67                CONCUR_LOGE("FillinUidInfo:: uid null!");
68                return false;
69            }
70            int64_t uid = atoi(reinterpret_cast<const char*>(attrValue));
71            authProcUidConfigs_.insert(uid);
72            xmlFree(attrValue);
73        }
74    }
75    return true;
76}
77
78bool ConfigReader::FillinBundleNameInfo(const xmlNode* currNode)
79{
80    if (!IsValidNode(currNode)) {
81        CONCUR_LOGE("FillinBundleNameInfo:: currNode is nullptr!");
82        return false;
83    }
84    xmlNodePtr currNodePtr = currNode->xmlChildrenNode;
85    for (; currNodePtr; currNodePtr = currNodePtr->next) {
86        if (xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_BUNDLENAME.c_str())) == 0) {
87            xmlChar *attrValue = xmlGetProp(currNodePtr, reinterpret_cast<const xmlChar*>(XML_TAG_BUNDLENAME.c_str()));
88            if (!attrValue) {
89                CONCUR_LOGE("FillinBundleNameInfo:: bundleName null!");
90                return false;
91            }
92            std::string bundleName = reinterpret_cast<const char*>(attrValue);
93            authProcBundleNameConfigs_.insert(bundleName);
94            xmlFree(attrValue);
95        }
96    }
97    return true;
98}
99
100void ConfigReader::ParseAuth(const xmlNode* currNode)
101{
102    xmlNodePtr currNodePtr = currNode->xmlChildrenNode;
103    for (; currNodePtr; currNodePtr = currNodePtr->next) {
104        if (xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_UIDLIST.c_str())) == 0) {
105            if (!FillinUidInfo(currNodePtr)) {
106                CONCUR_LOGE("ParseAuth:: uid fill in authProcUidConfigs_ error!");
107                continue;
108            }
109        }
110
111        if (xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_BUNDLENAMELIST.c_str())) == 0) {
112            if (!FillinBundleNameInfo(currNodePtr)) {
113                CONCUR_LOGE("ParseAuth:: bundleName fill in authProcBundleNameConfigs_ error!");
114                continue;
115            }
116        }
117    }
118}
119
120void ConfigReader::ParsePowerMode(const xmlNode* currNode)
121{
122    if (!IsValidNode(currNode)) {
123        CONCUR_LOGE("ParsePowerMode:: currNode is nullptr!");
124        return;
125    }
126    xmlNodePtr currNodePtr = currNode->xmlChildrenNode;
127    for (; currNodePtr; currNodePtr = currNodePtr->next) {
128        if (xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_SWITCH.c_str())) == 0) {
129            char* switchValue = reinterpret_cast<char*>(xmlNodeGetContent(currNodePtr));
130            if (!switchValue) {
131                CONCUR_LOGE("ParsePowerMode:: switch is null!");
132                continue;
133            }
134            if (strncmp(switchValue, "1", 1) == 0) {
135                powerModeSchedSwitch_ = true;
136            } else if (strncmp(switchValue, "0", 1) == 0) {
137                powerModeSchedSwitch_ = false;
138            } else {
139                CONCUR_LOGE("ParsePowerMode:: invalid switch value!");
140            }
141            xmlFree(switchValue);
142        }
143
144        if (xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_DEGRADATION_FPS.c_str())) == 0) {
145            char* fpsValue = reinterpret_cast<char*>(xmlGetProp(currNodePtr,
146                reinterpret_cast<const xmlChar*>(XML_TAG_FPS.c_str())));
147            char* deFpsValue = reinterpret_cast<char*>(xmlNodeGetContent(currNodePtr));
148            if (fpsValue && deFpsValue && IsValidFps(fpsValue) && IsPositiveInt(deFpsValue)) {
149                degradationFpsMap_.insert(std::make_pair(atoi(fpsValue), atoi(deFpsValue)));
150            } else {
151                CONCUR_LOGE("ParsePowerMode:: fps is null or invalid!");
152            }
153            if (fpsValue) {
154                xmlFree(fpsValue);
155            }
156            if (deFpsValue) {
157                xmlFree(deFpsValue);
158            }
159        }
160    }
161}
162
163bool ConfigReader::LoadFromConfigFile(const std::string& configFile)
164{
165    // skip the empty string, else you will get empty node
166    xmlDocPtr xmlDocPtr = xmlReadFile(configFile.c_str(), nullptr,
167        XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
168    if (!xmlDocPtr) {
169        CONCUR_LOGE("LoadFromConfigFile:: xmlReadFile error!");
170        return false;
171    }
172    xmlNodePtr rootNodePtr = xmlDocGetRootElement(xmlDocPtr);
173    if (!rootNodePtr || !rootNodePtr->name ||
174        xmlStrcmp(rootNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_QOS_CONFIG.c_str())) != 0) {
175        CONCUR_LOGE("LoadFromConfigFile:: root element tag error!");
176        xmlFreeDoc(xmlDocPtr);
177        return false;
178    }
179    xmlNodePtr currNodePtr = rootNodePtr->xmlChildrenNode;
180    for (; currNodePtr; currNodePtr = currNodePtr->next) {
181        if (!IsValidNode(currNodePtr)) {
182            CONCUR_LOGE("LoadFromConfigFile:: IsInvalidNode!");
183            continue;
184        }
185        if (xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_QOS_AUTH.c_str())) == 0) {
186            ParseAuth(currNodePtr);
187        }
188        if (xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_POWER_MODE.c_str())) == 0) {
189            ParsePowerMode(currNodePtr);
190        }
191    }
192    ConfigHilog();
193    xmlFreeDoc(xmlDocPtr);
194    return true;
195}
196
197void ConfigReader::GetRealConfigPath(const char* configName, std::string& configPath)
198{
199    if (!configName) {
200        CONCUR_LOGE("GetRealConfigPath:: configName is nullptr!");
201        return;
202    }
203    char buf[PATH_MAX] = {0};
204    char* configFilePath = GetOneCfgFile(configName, buf, PATH_MAX);
205    char tmpPath[PATH_MAX] = {0};
206    if (!configFilePath || strlen(configFilePath) == 0 || strlen(configFilePath) > PATH_MAX ||
207        !realpath(configFilePath, tmpPath)) {
208        CONCUR_LOGE("GetRealConfigPath:: get config file path error!");
209        configPath = "";
210        return;
211    }
212    configPath = tmpPath;
213}
214
215bool ConfigReader::IsUidAuth(pid_t uid)
216{
217    if (authProcUidConfigs_.find(uid) != authProcUidConfigs_.end()) {
218        return true;
219    }
220    return false;
221}
222
223bool ConfigReader::IsBundleNameAuth(std::string& bundleName)
224{
225    if (authProcBundleNameConfigs_.find(bundleName) != authProcBundleNameConfigs_.end()) {
226        return true;
227    }
228    return false;
229}
230
231bool ConfigReader::GetPowerModeSchedSwitch()
232{
233    return powerModeSchedSwitch_;
234}
235
236int ConfigReader::GetDegratationFps(int fps)
237{
238    if (degradationFpsMap_.find(fps) == degradationFpsMap_.end()) {
239        return fps + FPS_OFFSET;
240    }
241    return degradationFpsMap_[fps] + FPS_OFFSET;
242}
243
244bool ConfigReader::IsValidFps(const std::string& fps)
245{
246    if (fps == XML_TAG_FPS_HIGH || fps == XML_TAG_FPS_MEDIUM || fps == XML_TAG_FPS_STANDARD) {
247        return true;
248    }
249    return false;
250}
251
252bool ConfigReader::IsPositiveInt(const std::string& intStr)
253{
254    int num = 0;
255    try {
256        num = stoi(intStr);
257    } catch (...) {
258        CONCUR_LOGE("Unexpected number format!");
259        return false;
260    }
261    return num > 0;
262}
263
264void ConfigReader::ConfigHilog()
265{
266    bool getConfigRead = OHOS::system::GetBoolParameter("persist.qos.configreadlog", false);
267    if (getConfigRead) {
268        for (auto iter : authProcUidConfigs_) {
269            CONCUR_LOGI("authProcUidConfigs_ contain uid = %{public}d", (int32_t)iter);
270        }
271        for (auto iter : authProcBundleNameConfigs_) {
272            CONCUR_LOGI("authProcBundleNameConfigs_ contain bundleName = %{public}s", iter.c_str());
273        }
274        CONCUR_LOGI("powerModeSchedSwitch_ = %{public}d", powerModeSchedSwitch_);
275        for (auto iter : degradationFpsMap_) {
276            CONCUR_LOGI("fps = %{public}d degradationFps = %{public}d", iter.first, iter.second);
277        }
278    }
279}
280}
281}