1 /*
2  * Copyright (c) 2022-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 
16 #include "thermal_config_file_parser.h"
17 
18 #include "string_ex.h"
19 #include "string_operation.h"
20 
21 namespace OHOS {
22 namespace PowerMgr {
23 namespace {
24 static const std::string VENDOR_THERMAL_SRV_CONFIG_XML = "/vendor/etc/thermal_config/thermal_service_config.xml";
25 static const std::string SYSTEM_THERMAL_SRV_CONFIG_XML = "/system/etc/thermal_config/thermal_service_config.xml";
26 const std::string TRUE_STR = "1";
27 } // namespace
Init()28 bool ThermalConfigFileParser::Init()
29 {
30     if (!LoadThermalSrvConfigXml(VENDOR_THERMAL_SRV_CONFIG_XML)) {
31         THERMAL_HILOGE(LABEL_TEST, "Failed to load vendor thermal config xml file");
32         if (!LoadThermalSrvConfigXml(SYSTEM_THERMAL_SRV_CONFIG_XML)) {
33             THERMAL_HILOGE(LABEL_TEST, "Failed to load system thermal config xml file");
34             return false;
35         }
36     }
37     return true;
38 }
39 
GetActionEnableEvent(const std::string & actionName)40 bool ThermalConfigFileParser::GetActionEnableEvent(const std::string& actionName)
41 {
42     for (auto iter : actionItem_) {
43         if (iter.name.compare(actionName) == 0 ||
44             actionName.find(iter.name) != std::string::npos) {
45             return iter.enableEvent;
46         }
47     }
48     return false;
49 }
50 
GetActionStrict(const std::string & actionName)51 bool ThermalConfigFileParser::GetActionStrict(const std::string& actionName)
52 {
53     for (auto iter : actionItem_) {
54         if (iter.name.compare(actionName) == 0 ||
55             actionName.find(iter.name) != std::string::npos) {
56             return iter.strict;
57         }
58     }
59     return false;
60 }
61 
GetActionPolicy(const std::string & name,uint32_t level,std::vector<PolicyAction> & policy)62 bool ThermalConfigFileParser::GetActionPolicy(const std::string& name, uint32_t level,
63     std::vector<PolicyAction>& policy)
64 {
65     auto vPolicyCfg = policyConfigMap_.find(name);
66     if (vPolicyCfg != policyConfigMap_.end()) {
67         for (auto cfgIter : vPolicyCfg->second) {
68             if (cfgIter.level == level) {
69                 policy = cfgIter.policyActionList;
70                 return true;
71             }
72         }
73     }
74     return false;
75 }
76 
GetLevelItems(const std::string & name,const std::string & sensor)77 std::vector<LevelItem> ThermalConfigFileParser::GetLevelItems(const std::string& name, const std::string& sensor)
78 {
79     auto sensorInfo = sensorInfoMap_.find(name);
80     if (sensorInfo != sensorInfoMap_.end()) {
81         auto levelInfo = sensorInfo->second.find(sensor);
82         if (levelInfo != sensorInfo->second.end()) {
83             return levelInfo->second;
84         }
85     }
86     return std::vector<LevelItem>{};
87 }
88 
GetStateItem()89 std::vector<StateItem> ThermalConfigFileParser::GetStateItem()
90 {
91     return stateItem_;
92 }
93 
LoadThermalSrvConfigXml(const std::string & path)94 bool ThermalConfigFileParser::LoadThermalSrvConfigXml(const std::string& path)
95 {
96     if (!ParseXmlFile(path)) {
97         return false;
98     }
99     return true;
100 }
101 
ParseXmlFile(const std::string & path)102 bool ThermalConfigFileParser::ParseXmlFile(const std::string& path)
103 {
104     std::unique_ptr<xmlDoc, decltype(&xmlFreeDoc)> docPtr(
105         xmlReadFile(path.c_str(), nullptr, XML_PARSE_NOBLANKS), xmlFreeDoc);
106     if (docPtr == nullptr) {
107         THERMAL_HILOGE(LABEL_TEST, "ParseXMLFile::Init failed, read file failed.");
108         return false;
109     }
110 
111     auto rootNode = xmlDocGetRootElement(docPtr.get());
112     if (rootNode == nullptr) {
113         THERMAL_HILOGE(LABEL_TEST, "ParseXMLFile::Get root node failed.");
114         return false;
115     }
116 
117     for (auto node = rootNode->children; node; node = node->next) {
118         if (node == nullptr) {
119             continue;
120         }
121         if (!xmlStrcmp(node->name, BAD_CAST"base")) {
122             ParseBaseNode(node);
123         } else if (!xmlStrcmp(node->name, BAD_CAST"level")) {
124             ParseLevelNode(node);
125         } else if (!xmlStrcmp(node->name, BAD_CAST"state")) {
126             ParseStateNode(node);
127         } else if (!xmlStrcmp(node->name, BAD_CAST"action")) {
128             ParseActionNode(node);
129         } else if (!xmlStrcmp(node->name, BAD_CAST"policy")) {
130             ParsePolicyNode(node);
131         } else if (!xmlStrcmp(node->name, BAD_CAST"idle")) {
132             ParseIdleNode(node);
133         }
134     }
135     return true;
136 }
137 
ParseBaseNode(xmlNodePtr node)138 void ThermalConfigFileParser::ParseBaseNode(xmlNodePtr node)
139 {
140     auto curNode = node->xmlChildrenNode;
141     while (curNode != nullptr) {
142         BaseItem item;
143         xmlChar* xmlTag = xmlGetProp(curNode, BAD_CAST"tag");
144         if (xmlTag != nullptr) {
145             item.tag = reinterpret_cast<char*>(xmlTag);
146             xmlFree(xmlTag);
147         }
148 
149         xmlChar* xmlValue = xmlGetProp(curNode, BAD_CAST"value");
150         if (xmlValue != nullptr) {
151             item.value = reinterpret_cast<char*>(xmlValue);
152             xmlFree(xmlValue);
153         }
154         baseInfoMap_.emplace(item.tag, item.value);
155         curNode = curNode->next;
156         THERMAL_HILOGD(LABEL_TEST, "tag: %{public}s, value:%{public}s",
157             item.tag.c_str(), item.value.c_str());
158     }
159 }
160 
ParseLevelNode(xmlNodePtr node)161 void ThermalConfigFileParser::ParseLevelNode(xmlNodePtr node)
162 {
163     auto curNode = node->xmlChildrenNode;
164     while (curNode != nullptr) {
165         std::string name;
166         std::shared_ptr<ThermalConfigSensorCluster> sc = std::make_shared<ThermalConfigSensorCluster>();
167         xmlChar* xmlName = xmlGetProp(curNode, BAD_CAST"name");
168         if (xmlName != nullptr) {
169             name = reinterpret_cast<char*>(xmlName);
170             xmlFree(xmlName);
171         }
172         ParseAuxSensorInfo(name, curNode, sc);
173         ParseSensorInfo(name, curNode, sc);
174         xmlChar* desc = xmlGetProp(curNode, BAD_CAST("desc"));
175         if (desc != nullptr) {
176             std::string descValue = reinterpret_cast<char*>(desc);
177             if (TrimStr(descValue) == TRUE_STR) {
178                 sc->SetDescFlag(true);
179             }
180             xmlFree(desc);
181         }
182         sensorClusterMap_.emplace(std::pair(name, sc));
183         curNode = curNode->next;
184     }
185 }
186 
ParseStateNode(xmlNodePtr node)187 void ThermalConfigFileParser::ParseStateNode(xmlNodePtr node)
188 {
189     auto curNode = node->xmlChildrenNode;
190     while (curNode != nullptr) {
191         StateItem si;
192         xmlChar* xmlName = xmlGetProp(curNode, BAD_CAST"name");
193         if (xmlName != nullptr) {
194             si.name = reinterpret_cast<char*>(xmlName);
195             xmlFree(xmlName);
196         }
197 
198         xmlChar* param = xmlGetProp(curNode, BAD_CAST("param"));
199         if (param != nullptr) {
200             si.params = reinterpret_cast<char*>(param);
201             si.isExistParam = true;
202             xmlFree(param);
203         }
204         stateItem_.push_back(si);
205         THERMAL_HILOGI(LABEL_TEST, "si.name: %{public}s, si.params %{public}s",
206             si.name.c_str(), si.params.c_str());
207         curNode = curNode->next;
208     }
209 }
210 
ParseActionNode(xmlNodePtr node)211 void ThermalConfigFileParser::ParseActionNode(xmlNodePtr node)
212 {
213     auto curNode = node->xmlChildrenNode;
214     while (curNode != nullptr) {
215         if (!xmlStrcmp(curNode->name, BAD_CAST"item")) {
216             ActionItem ai;
217             xmlChar* xmlName = xmlGetProp(curNode, BAD_CAST"name");
218             if (xmlName != nullptr) {
219                 ai.name = reinterpret_cast<char*>(xmlName);
220                 xmlFree(xmlName);
221             }
222             xmlChar* param = xmlGetProp(curNode, BAD_CAST("param"));
223             if (param != nullptr) {
224                 ai.params = reinterpret_cast<char*>(param);
225                 xmlFree(param);
226             }
227             xmlChar* protocol = xmlGetProp(curNode, BAD_CAST("protocol"));
228             if (protocol != nullptr) {
229                 ai.protocol = reinterpret_cast<char*>(protocol);
230                 xmlFree(protocol);
231             }
232             xmlChar* strict = xmlGetProp(curNode, BAD_CAST("strict"));
233             if (strict != nullptr) {
234                 std::string strictValue = reinterpret_cast<char*>(strict);
235                 ai.strict = (TrimStr(strictValue) == TRUE_STR);
236                 xmlFree(strict);
237             }
238             xmlChar* event = xmlGetProp(curNode, BAD_CAST("event"));
239             if (event != nullptr) {
240                 std::string eventValue = reinterpret_cast<char*>(event);
241                 ai.enableEvent = (TrimStr(eventValue) == TRUE_STR);
242                 xmlFree(event);
243             }
244             THERMAL_HILOGD(LABEL_TEST,
245                 "ai.name: %{public}s, ai.strict: %{public}d, ai.params: %{public}s, ai.strict: %{public}s, "    \
246                 "ai.enableEvent: %{public}d",
247                 ai.name.c_str(), ai.strict, ai.params.c_str(), ai.protocol.c_str(), ai.enableEvent);
248 
249             actionItem_.push_back(ai);
250         }
251         curNode = curNode->next;
252     }
253 }
254 
ParsePolicyNode(xmlNodePtr node)255 void ThermalConfigFileParser::ParsePolicyNode(xmlNodePtr node)
256 {
257     auto curNode = node->xmlChildrenNode;
258     while (curNode != nullptr) {
259         PolicyConfig policyConfig;
260         std::string clusterName;
261         xmlChar* xmlName = xmlGetProp(curNode, BAD_CAST"name");
262         if (xmlName != nullptr) {
263             clusterName = reinterpret_cast<char*>(xmlName);
264             xmlFree(xmlName);
265         }
266 
267         xmlChar* xmlLevel = xmlGetProp(curNode, BAD_CAST"level");
268         if (xmlLevel != nullptr) {
269             uint32_t level = 0;
270             StringOperation::StrToUint(reinterpret_cast<char*>(xmlLevel), level);
271             policyConfig.level = level;
272             THERMAL_HILOGD(LABEL_TEST, "policyConfig.name: %{public}s, policyConfig.level:%{public}d",
273                 clusterName.c_str(), level);
274             xmlFree(xmlLevel);
275         }
276 
277         ParsePolicySubnode(curNode, policyConfig);
278 
279         const auto& clusterIter = policyConfigMap_.find(clusterName);
280         THERMAL_HILOGD(LABEL_TEST, "clusterName: %{public}s", clusterName.c_str());
281         if (clusterIter == policyConfigMap_.end()) {
282             std::vector<PolicyConfig> policyList;
283             policyList.push_back(policyConfig);
284             policyConfigMap_.emplace(clusterName, policyList);
285         } else {
286             clusterIter->second.push_back(policyConfig);
287         }
288         curNode = curNode->next;
289     }
290 }
291 
ParseIdleNode(xmlNodePtr node)292 void ThermalConfigFileParser::ParseIdleNode(xmlNodePtr node)
293 {
294     IdleState idleState;
295     for (auto subNode = node->children; subNode != nullptr; subNode = subNode->next) {
296         if (!xmlStrcmp(subNode->name, BAD_CAST"thermallevel")) {
297             xmlChar* value = xmlNodeGetContent(subNode);
298             if (value != nullptr) {
299                 StrToInt(reinterpret_cast<char*>(value), idleState.level);
300                 xmlFree(value);
301             }
302         } else if (!xmlStrcmp(subNode->name, BAD_CAST"soc")) {
303             xmlChar* value = xmlNodeGetContent(subNode);
304             if (value != nullptr) {
305                 StrToInt(reinterpret_cast<char*>(value), idleState.soc);
306                 xmlFree(value);
307             }
308         } else if (!xmlStrcmp(subNode->name, BAD_CAST"charging")) {
309             xmlChar* value = xmlNodeGetContent(subNode);
310             if (value != nullptr) {
311                 StrToInt(reinterpret_cast<char*>(value), idleState.charging);
312                 xmlFree(value);
313             }
314         } else if (!xmlStrcmp(subNode->name, BAD_CAST"current")) {
315             xmlChar* value = xmlNodeGetContent(subNode);
316             if (value != nullptr) {
317                 StrToInt(reinterpret_cast<char*>(value), idleState.current);
318                 xmlFree(value);
319             }
320         } else {
321             THERMAL_HILOGD(LABEL_TEST, "not supported node, name=%{public}s", subNode->name);
322         }
323     }
324     THERMAL_HILOGI(LABEL_TEST, "level=%{public}d, soc=%{public}d, charging=%{public}d, current=%{public}d",
325                    idleState.level, idleState.soc, idleState.charging, idleState.current);
326 }
327 
ParseAuxSensorInfo(const std::string & name,const xmlNode * cur,std::shared_ptr<ThermalConfigSensorCluster> & sc)328 void ThermalConfigFileParser::ParseAuxSensorInfo(
329     const std::string& name, const xmlNode* cur, std::shared_ptr<ThermalConfigSensorCluster>& sc)
330 {
331     xmlChar* auxSensorInfo = xmlGetProp(cur, BAD_CAST"aux_sensor");
332     if (auxSensorInfo != nullptr) {
333         std::vector<std::string> auxSensorList;
334         AuxSensorInfoMap auxSensorLevelInfo;
335         std::string auxSensor = reinterpret_cast<char*>(auxSensorInfo);
336         sc->SetAuxFlag(true);
337         StringOperation::SplitString(auxSensor, auxSensorList, ",");
338         for (uint32_t i = 0; i < auxSensorList.size(); i++) {
339             std::string sensorType = auxSensorList[i];
340             if (auxSensorList[i].empty()) {
341                 continue;
342             }
343             THERMAL_HILOGD(LABEL_TEST, "aux_sensor item: %{public}s", sensorType.c_str());
344             auxSensorLevelInfo.emplace(sensorType, ParseAuxSensorSubnodeInfo(cur, auxSensorList, i));
345         }
346         auxSensorInfoMap_.emplace(name, auxSensorLevelInfo);
347         sc->SetAuxSensorLevelInfo(auxSensorLevelInfo);
348         xmlFree(auxSensorInfo);
349     }
350 }
351 
ParseSensorInfo(const std::string & name,const xmlNode * cur,std::shared_ptr<ThermalConfigSensorCluster> & sc)352 void ThermalConfigFileParser::ParseSensorInfo(const std::string& name, const xmlNode* cur,
353     std::shared_ptr<ThermalConfigSensorCluster>& sc)
354 {
355     SensorInfoMap sensorLevelInfo;
356     std::vector<std::string> sensors;
357     xmlChar* xmlSensor = xmlGetProp(cur, BAD_CAST"sensor");
358     if (xmlSensor != nullptr) {
359         StringOperation::SplitString(reinterpret_cast<char*>(xmlSensor), sensors, ",");
360         for (uint32_t i = 0; i < sensors.size(); i++) {
361             std::string sensorType = sensors.at(i);
362             std::vector<LevelItem> vItem;
363             ParseSensorSubnodeInfo(cur, vItem, sensors, i, sc);
364             sensorLevelInfo.emplace(std::pair(sensorType, vItem));
365         }
366         sensorInfoMap_.insert(std::make_pair(name, sensorLevelInfo));
367         sc->SetSensorLevelInfo(sensorLevelInfo);
368         xmlFree(xmlSensor);
369     }
370 }
371 
ParseAuxSensorSubnodeInfo(const xmlNode * cur,std::vector<std::string> & auxSensorList,const uint32_t i)372 std::vector<AuxLevelItem> ThermalConfigFileParser::ParseAuxSensorSubnodeInfo(const xmlNode* cur,
373     std::vector<std::string>& auxSensorList, const uint32_t i)
374 {
375     std::vector<AuxLevelItem> auxItems;
376     for (auto subNode = cur->children; subNode != nullptr; subNode = subNode->next) {
377         std::string tempRanges;
378         AuxLevelItem auxlevelItem;
379         if (ParseAuxSensorSubnodeInfoTrigerRange(subNode, auxSensorList, tempRanges, i) == false) {
380             break;
381         }
382 
383         std::vector<std::string> tempRiseRanges;
384         StringOperation::SplitString(tempRanges, tempRiseRanges, "_");
385         const int32_t INDEX0 = 0;
386         const int32_t INDEX1 = 1;
387         StrToInt(tempRiseRanges[INDEX0], auxlevelItem.lowerTemp);
388         StrToInt(tempRiseRanges[INDEX1], auxlevelItem.upperTemp);
389         xmlChar* xmlLevel = xmlGetProp(subNode, BAD_CAST("level"));
390         if (xmlLevel != nullptr) {
391             StrToInt(reinterpret_cast<char*>(xmlLevel), auxlevelItem.level);
392             xmlFree(xmlLevel);
393         }
394         THERMAL_HILOGD(LABEL_TEST, "aux_trigger_range: %{public}s",
395             tempRanges.c_str());
396         THERMAL_HILOGD(LABEL_TEST, "lowerTemp: %{public}d, upperTemp: %{public}d",
397             auxlevelItem.lowerTemp, auxlevelItem.upperTemp);
398         auxItems.push_back(auxlevelItem);
399     }
400     return auxItems;
401 }
402 
ParseAuxSensorSubnodeInfoTrigerRange(const xmlNode * subNode,std::vector<std::string> & auxSensorList,std::string & tempRanges,const uint32_t i)403 bool ThermalConfigFileParser::ParseAuxSensorSubnodeInfoTrigerRange(const xmlNode* subNode,
404     std::vector<std::string>& auxSensorList, std::string& tempRanges, const uint32_t i)
405 {
406     xmlChar* xmlTriggerRange = xmlGetProp(subNode, BAD_CAST("aux_trigger_range"));
407     if (xmlTriggerRange != nullptr) {
408         std::string auxTriggerRange = reinterpret_cast<char*>(xmlTriggerRange);
409         if (!auxTriggerRange.empty()) {
410             std::vector<std::string> auxTempranges;
411             StringOperation::SplitString(auxTriggerRange, auxTempranges, ",");
412             if (auxSensorList.size() > auxTempranges.size()) {
413                 THERMAL_HILOGI(LABEL_TEST, "The auxiliary sensor does not match the threshold range");
414                 xmlFree(xmlTriggerRange);
415                 return false;
416             }
417             tempRanges = auxTempranges[i];
418         }
419         xmlFree(xmlTriggerRange);
420     }
421     return true;
422 }
423 
ParseSensorSubnodeInfo(const xmlNode * cur,std::vector<LevelItem> & vItem,std::vector<std::string> & sensors,const uint32_t i,std::shared_ptr<ThermalConfigSensorCluster> & sc)424 void ThermalConfigFileParser::ParseSensorSubnodeInfo(const xmlNode* cur, std::vector<LevelItem>& vItem,
425     std::vector<std::string>& sensors, const uint32_t i, std::shared_ptr<ThermalConfigSensorCluster>& sc)
426 {
427     for (auto subNode = cur->children; subNode; subNode = subNode->next) {
428         if (subNode == nullptr) {
429             continue;
430         }
431         LevelItem levelItem;
432         std::vector<std::string> thresholds;
433         std::vector<std::string> thresholdClrs;
434         xmlChar* xmlThreshold = xmlGetProp(subNode, BAD_CAST("threshold"));
435         if (xmlThreshold != nullptr) {
436             StringOperation::SplitString(reinterpret_cast<char*>(xmlThreshold), thresholds, ",");
437             xmlFree(xmlThreshold);
438         }
439         xmlChar* xmlThresholdClr = xmlGetProp(subNode, BAD_CAST("threshold_clr"));
440         if (xmlThresholdClr != nullptr) {
441             StringOperation::SplitString(reinterpret_cast<char*>(xmlThresholdClr), thresholdClrs, ",");
442             xmlFree(xmlThresholdClr);
443         }
444         if (sensors.size() > thresholds.size() || sensors.size() > thresholdClrs.size()) {
445             THERMAL_HILOGI(LABEL_TEST, "The sensor does not match the threshold range");
446             break;
447         }
448         xmlChar* xmlLevel = xmlGetProp(subNode, BAD_CAST("level"));
449         if (xmlLevel != nullptr) {
450             StringOperation::StrToUint(reinterpret_cast<char*>(xmlLevel), levelItem.level);
451             xmlFree(xmlLevel);
452         }
453 
454         StrToInt(thresholds.at(i), levelItem.threshold);
455         StrToInt(thresholdClrs.at(i), levelItem.thresholdClr);
456         xmlChar* tempRiseRates = xmlGetProp(subNode, BAD_CAST("temp_rise_rate"));
457         if (tempRiseRates != nullptr) {
458             std::vector<std::string> rates;
459             sc->SetRateFlag(true);
460             StringOperation::SplitString(reinterpret_cast<char*>(tempRiseRates), rates, ",");
461             if (sensors.size() > rates.size()) {
462                 break;
463             }
464             StringOperation::StrToDouble(rates.at(i), levelItem.tempRiseRate);
465         }
466         vItem.push_back(levelItem);
467         xmlFree(tempRiseRates);
468     }
469 }
470 
ParsePolicySubnode(const xmlNode * cur,PolicyConfig & policyConfig)471 void ThermalConfigFileParser::ParsePolicySubnode(const xmlNode* cur, PolicyConfig& policyConfig)
472 {
473     for (auto subNode = cur->children; subNode != nullptr; subNode = subNode->next) {
474         PolicyAction policyAction;
475         policyAction.actionName = reinterpret_cast<const char*>(subNode->name);
476         xmlChar* xmlActionValue = xmlNodeGetContent(subNode);
477         if (xmlActionValue != nullptr) {
478             policyAction.actionValue = reinterpret_cast<char*>(xmlActionValue);
479             THERMAL_HILOGD(LABEL_TEST,
480                 "policyAction.actionNodeName: %{public}s, policyAction.value:%{public}s",
481                 policyAction.actionName.c_str(), policyAction.actionValue.c_str());
482             xmlFree(xmlActionValue);
483         }
484 
485         if (subNode->properties == nullptr) {
486             THERMAL_HILOGD(LABEL_TEST, "action prop is nullptr");
487             policyAction.isProp = false;
488             policyConfig.policyActionList.push_back(policyAction);
489             continue;
490         }
491         for (auto actionProp = subNode->properties; actionProp != nullptr; actionProp = actionProp->next) {
492             std::string propName = reinterpret_cast<const char*>(actionProp->name);
493             xmlChar* xmlPropValue = xmlGetProp(subNode, actionProp->name);
494             if (xmlPropValue != nullptr) {
495                 std::string propValue = reinterpret_cast<char*>(xmlPropValue);
496                 THERMAL_HILOGD(LABEL_TEST, "propName.name: %{public}s, propValue:%{public}s",
497                     propName.c_str(), propValue.c_str());
498                 policyAction.actionPropMap.emplace(std::pair(propName, propValue));
499                 xmlFree(xmlPropValue);
500             }
501             policyAction.isProp = true;
502         }
503         policyConfig.policyActionList.push_back(policyAction);
504     }
505 }
506 } // namespace PowerMgr
507 } // namespace OHOS
508