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