1 /*
2  * Copyright (c) 2022 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 #include "config_reader.h"
17 #include "res_sched_log.h"
18 
19 using namespace std;
20 
21 namespace OHOS {
22 namespace ResourceSchedule {
23 namespace {
24 constexpr auto XML_TAG_RES_SCHED = "ressched";
25 constexpr auto XML_TAG_PLUGIN = "plugin";
26 constexpr auto XML_TAG_CONFIG = "config";
27 constexpr auto XML_TAG_ITEM = "item";
28 constexpr auto XML_ATTR_NAME = "name";
29 }
30 
IsInvalidNode(const xmlNode & currNode)31 bool ConfigReader::IsInvalidNode(const xmlNode& currNode)
32 {
33     if (!currNode.name || currNode.type == XML_COMMENT_NODE) {
34         return true;
35     }
36     return false;
37 }
38 
ParseProperties(const xmlNode & currNode,map<string,string> & properties)39 void ConfigReader::ParseProperties(const xmlNode& currNode, map<string, string>& properties)
40 {
41     auto attrs = currNode.properties;
42     xmlChar *value;
43     for (; attrs; attrs = attrs->next) {
44         auto name = attrs->name;
45         if (!name) {
46             RESSCHED_LOGW("%{public}s, name null!", __func__);
47             continue;
48         }
49         value = xmlGetProp(&currNode, name);
50         if (!value) {
51             RESSCHED_LOGW("%{public}s, name(%{public}s) value null!", __func__, name);
52             continue;
53         }
54         properties[reinterpret_cast<const char*>(name)] = reinterpret_cast<const char*>(value);
55         xmlFree(value);
56     }
57 }
58 
ParseSubItem(const xmlNode & parentNode,Item & item)59 void ConfigReader::ParseSubItem(const xmlNode& parentNode, Item& item)
60 {
61     auto currNodePtr = parentNode.xmlChildrenNode;
62     xmlChar *value;
63     for (; currNodePtr; currNodePtr = currNodePtr->next) {
64         if (IsInvalidNode(*currNodePtr)) {
65             RESSCHED_LOGW("%{public}s, skip invalid node!", __func__);
66             continue;
67         }
68         SubItem subItem;
69         ParseProperties(*currNodePtr, subItem.properties);
70         subItem.name = reinterpret_cast<const char*>(currNodePtr->name);
71         value = xmlNodeGetContent(currNodePtr);
72         if (value) {
73             string itemValue(reinterpret_cast<const char*>(value));
74             subItem.value = std::move(itemValue);
75             xmlFree(value);
76         }
77         item.subItemList.emplace_back(subItem);
78     }
79 }
80 
ParseItem(const xmlNode & parentNode,PluginConfig & pluginConfig)81 void ConfigReader::ParseItem(const xmlNode& parentNode, PluginConfig& pluginConfig)
82 {
83     auto currNodePtr = parentNode.xmlChildrenNode;
84     for (; currNodePtr; currNodePtr = currNodePtr->next) {
85         if (IsInvalidNode(*currNodePtr) ||
86             xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_ITEM)) != 0) {
87             continue;
88         }
89         Item item;
90         ParseProperties(*currNodePtr, item.itemProperties);
91         ParseSubItem(*currNodePtr, item);
92         pluginConfig.itemList.emplace_back(item);
93     }
94 }
95 
ParseConfig(const xmlNode & parentNode,PluginConfigMap & pluginConfigMap)96 void ConfigReader::ParseConfig(const xmlNode& parentNode, PluginConfigMap& pluginConfigMap)
97 {
98     auto currNodePtr = parentNode.xmlChildrenNode;
99     for (; currNodePtr; currNodePtr = currNodePtr->next) {
100         if (IsInvalidNode(*currNodePtr) ||
101             xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_CONFIG)) != 0) {
102             continue;
103         }
104         auto propName = xmlGetProp(currNodePtr, reinterpret_cast<const xmlChar*>(XML_ATTR_NAME));
105         if (!propName) {
106             RESSCHED_LOGW("%{public}s, propName null!", __func__);
107             continue;
108         }
109 
110         string configName(reinterpret_cast<char*>(propName));
111         xmlFree(propName);
112         auto& pluginConfig = pluginConfigMap[configName];
113         ParseItem(*currNodePtr, pluginConfig);
114     }
115 }
116 
ParsePluginConfig(const xmlNode & currNode,map<string,PluginConfigMap> & pluginConfigs)117 bool ConfigReader::ParsePluginConfig(const xmlNode& currNode, map<string, PluginConfigMap>& pluginConfigs)
118 {
119     auto propName = xmlGetProp(&currNode, reinterpret_cast<const xmlChar*>(XML_ATTR_NAME));
120     if (!propName) {
121         RESSCHED_LOGW("%{public}s, propName null!", __func__);
122         return false;
123     }
124     string pluginName(reinterpret_cast<char*>(propName));
125     xmlFree(propName);
126     ParseConfig(currNode, pluginConfigs[pluginName]);
127     return true;
128 }
129 
LoadFromConfigContent(const string & content)130 bool ConfigReader::LoadFromConfigContent(const string& content)
131 {
132     // skip the empty string, else you will get empty node
133     xmlDocPtr xmlDocPtr = xmlReadMemory(content.c_str(), content.length(), nullptr, nullptr,
134         XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
135     if (!xmlDocPtr) {
136         RESSCHED_LOGE("%{public}s, xmlReadFile error!", __func__);
137         return false;
138     }
139     xmlNodePtr rootNodePtr = xmlDocGetRootElement(xmlDocPtr);
140     if (!rootNodePtr || !rootNodePtr->name ||
141         xmlStrcmp(rootNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_RES_SCHED)) != 0) {
142         RESSCHED_LOGE("%{public}s, root element tag wrong!", __func__);
143         xmlFreeDoc(xmlDocPtr);
144         return false;
145     }
146     map<string, PluginConfigMap> allPluginConfigs;
147     xmlNodePtr currNodePtr = rootNodePtr->xmlChildrenNode;
148     for (; currNodePtr; currNodePtr = currNodePtr->next) {
149         if (IsInvalidNode(*currNodePtr)) {
150             continue;
151         }
152         bool ret = false;
153         if (xmlStrcmp(currNodePtr->name, reinterpret_cast<const xmlChar*>(XML_TAG_PLUGIN)) == 0) {
154             ret = ParsePluginConfig(*currNodePtr, allPluginConfigs);
155         }
156         if (!ret) {
157             RESSCHED_LOGW("%{public}s, plugin (%{public}s) config wrong!", __func__, currNodePtr->name);
158             xmlFreeDoc(xmlDocPtr);
159             return false;
160         }
161     }
162     xmlFreeDoc(xmlDocPtr);
163     lock_guard<mutex> autoLock(configMutex_);
164     MergeConfigList(allPluginConfigs);
165     return true;
166 }
167 
MergeConfigList(std::map<std::string,PluginConfigMap> & pluginConfigs)168 void ConfigReader::MergeConfigList(std::map<std::string, PluginConfigMap>& pluginConfigs)
169 {
170     for (auto iter : pluginConfigs) {
171         if (allPluginConfigs_.find(iter.first) == allPluginConfigs_.end()) {
172             allPluginConfigs_[iter.first] = iter.second;
173             continue;
174         }
175         MergePluginConfigMap(allPluginConfigs_[iter.first], iter.second);
176     }
177 }
178 
MergePluginConfigMap(PluginConfigMap & curPluginConfigMap,const PluginConfigMap & nextPluginConfigMap)179 void ConfigReader::MergePluginConfigMap(PluginConfigMap& curPluginConfigMap,
180     const PluginConfigMap& nextPluginConfigMap)
181 {
182     for (auto iter : nextPluginConfigMap) {
183         curPluginConfigMap[iter.first] = iter.second;
184     }
185 }
186 
GetConfig(const std::string & pluginName,const std::string & configName)187 PluginConfig ConfigReader::GetConfig(const std::string& pluginName, const std::string& configName)
188 {
189     lock_guard<mutex> autoLock(configMutex_);
190     PluginConfig config;
191     auto itMap = allPluginConfigs_.find(pluginName);
192     if (itMap == allPluginConfigs_.end()) {
193         RESSCHED_LOGE("%{public}s, no pluginName:%{public}s config!", __func__, pluginName.c_str());
194         return config;
195     }
196     PluginConfigMap configMap = allPluginConfigs_[pluginName];
197     auto itConfig = configMap.find(configName);
198     if (itConfig == configMap.end()) {
199         RESSCHED_LOGE("%{public}s, pluginName:%{public}s config:%{public}s null!", __func__,
200             pluginName.c_str(), configName.c_str());
201         return config;
202     }
203     return configMap[configName];
204 }
205 
Dump(std::string & result)206 void ConfigReader::Dump(std::string &result)
207 {
208     result.append("================Resource Schedule Plugin Config ================\n");
209     for (auto pluginIter : allPluginConfigs_) {
210         result.append("pluginName:").append(pluginIter.first).append(" \n");
211         auto pluginConfigMap = pluginIter.second;
212         for (auto pluginConfigMapIter : pluginConfigMap) {
213             result.append("configName:").append(pluginConfigMapIter.first).append(" \n");
214             auto pluginConfig = pluginConfigMapIter.second;
215             for (auto item : pluginConfig.itemList) {
216                 DumpItem(item, result);
217             }
218         }
219     }
220 }
221 
DumpItem(const Item & item,std::string & result)222 void ConfigReader::DumpItem(const Item& item, std::string &result)
223 {
224     result.append("Item : ");
225     for (auto itemProPerty : item.itemProperties) {
226         result.append(itemProPerty.first).append(" = ").append(itemProPerty.second).append(" ");
227     }
228     result.append(" \n");
229     for (auto subItem : item.subItemList) {
230         result.append("subItemName : ").append(subItem.name).append(" ");
231         for (auto subItemProPerty : subItem.properties) {
232             result.append(subItemProPerty.first).append(" = ").append(subItemProPerty.second).append(" ");
233         }
234         result.append(" value :").append(subItem.value).append(" \n");
235     }
236 }
237 } // namespace ResourceSchedule
238 } // namespace OHOS
239