• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "thermal_info.h"
17 
18 #include <android-base/file.h>
19 #include <android-base/logging.h>
20 #include <android-base/properties.h>
21 #include <android-base/strings.h>
22 #include <json/reader.h>
23 
24 #include <cmath>
25 #include <unordered_set>
26 
27 namespace aidl {
28 namespace android {
29 namespace hardware {
30 namespace thermal {
31 namespace implementation {
32 
33 constexpr std::string_view kPowerLinkDisabledProperty("vendor.disable.thermal.powerlink");
34 
35 namespace {
36 
37 template <typename T>
38 // Return false when failed parsing
getTypeFromString(std::string_view str,T * out)39 bool getTypeFromString(std::string_view str, T *out) {
40     auto types = ::ndk::enum_range<T>();
41     for (const auto &type : types) {
42         if (::aidl::android::hardware::thermal::toString(type) == str) {
43             *out = type;
44             return true;
45         }
46     }
47     return false;
48 }
49 
getFloatFromValue(const Json::Value & value)50 float getFloatFromValue(const Json::Value &value) {
51     if (value.isString()) {
52         return std::stof(value.asString());
53     } else {
54         return value.asFloat();
55     }
56 }
57 
getIntFromValue(const Json::Value & value)58 int getIntFromValue(const Json::Value &value) {
59     if (value.isString()) {
60         return (value.asString() == "max") ? std::numeric_limits<int>::max()
61                                            : std::stoul(value.asString());
62     } else {
63         return value.asInt();
64     }
65 }
66 
getIntFromJsonValues(const Json::Value & values,CdevArray * out,bool inc_check,bool dec_check)67 bool getIntFromJsonValues(const Json::Value &values, CdevArray *out, bool inc_check,
68                           bool dec_check) {
69     CdevArray ret;
70 
71     if (inc_check && dec_check) {
72         LOG(ERROR) << "Cannot enable inc_check and dec_check at the same time";
73         return false;
74     }
75 
76     if (values.size() != kThrottlingSeverityCount) {
77         LOG(ERROR) << "Values size is invalid";
78         return false;
79     } else {
80         int last;
81         for (Json::Value::ArrayIndex i = 0; i < kThrottlingSeverityCount; ++i) {
82             ret[i] = getIntFromValue(values[i]);
83             if (inc_check && ret[i] < last) {
84                 LOG(FATAL) << "Invalid array[" << i << "]" << ret[i] << " min=" << last;
85                 return false;
86             }
87             if (dec_check && ret[i] > last) {
88                 LOG(FATAL) << "Invalid array[" << i << "]" << ret[i] << " max=" << last;
89                 return false;
90             }
91             last = ret[i];
92             LOG(INFO) << "[" << i << "]: " << ret[i];
93         }
94     }
95 
96     *out = ret;
97     return true;
98 }
99 
getFloatFromJsonValues(const Json::Value & values,ThrottlingArray * out,bool inc_check,bool dec_check)100 bool getFloatFromJsonValues(const Json::Value &values, ThrottlingArray *out, bool inc_check,
101                             bool dec_check) {
102     ThrottlingArray ret;
103 
104     if (inc_check && dec_check) {
105         LOG(ERROR) << "Cannot enable inc_check and dec_check at the same time";
106         return false;
107     }
108 
109     if (values.size() != kThrottlingSeverityCount) {
110         LOG(ERROR) << "Values size is invalid";
111         return false;
112     } else {
113         float last = std::nanf("");
114         for (Json::Value::ArrayIndex i = 0; i < kThrottlingSeverityCount; ++i) {
115             ret[i] = getFloatFromValue(values[i]);
116             if (inc_check && !std::isnan(last) && !std::isnan(ret[i]) && ret[i] < last) {
117                 LOG(FATAL) << "Invalid array[" << i << "]" << ret[i] << " min=" << last;
118                 return false;
119             }
120             if (dec_check && !std::isnan(last) && !std::isnan(ret[i]) && ret[i] > last) {
121                 LOG(FATAL) << "Invalid array[" << i << "]" << ret[i] << " max=" << last;
122                 return false;
123             }
124             last = std::isnan(ret[i]) ? last : ret[i];
125             LOG(INFO) << "[" << i << "]: " << ret[i];
126         }
127     }
128 
129     *out = ret;
130     return true;
131 }
132 }  // namespace
133 
ParseThermalConfig(std::string_view config_path,Json::Value * config)134 bool ParseThermalConfig(std::string_view config_path, Json::Value *config) {
135     std::string json_doc;
136     if (!::android::base::ReadFileToString(config_path.data(), &json_doc)) {
137         LOG(ERROR) << "Failed to read JSON config from " << config_path;
138         return false;
139     }
140     Json::CharReaderBuilder builder;
141     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
142     std::string errorMessage;
143     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), config, &errorMessage)) {
144         LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
145         return false;
146     }
147     return true;
148 }
149 
ParseVirtualSensorInfo(const std::string_view name,const Json::Value & sensor,std::unique_ptr<VirtualSensorInfo> * virtual_sensor_info)150 bool ParseVirtualSensorInfo(const std::string_view name, const Json::Value &sensor,
151                             std::unique_ptr<VirtualSensorInfo> *virtual_sensor_info) {
152     if (sensor["VirtualSensor"].empty() || !sensor["VirtualSensor"].isBool()) {
153         LOG(INFO) << "Failed to read Sensor[" << name << "]'s VirtualSensor";
154         return true;
155     }
156     bool is_virtual_sensor = sensor["VirtualSensor"].asBool();
157     LOG(INFO) << "Sensor[" << name << "]'s' VirtualSensor: " << is_virtual_sensor;
158     if (!is_virtual_sensor) {
159         return true;
160     }
161     float offset = 0;
162     std::vector<std::string> linked_sensors;
163     std::vector<SensorFusionType> linked_sensors_type;
164     std::vector<std::string> trigger_sensors;
165     std::vector<std::string> coefficients;
166     std::vector<SensorFusionType> coefficients_type;
167     FormulaOption formula = FormulaOption::COUNT_THRESHOLD;
168 
169     Json::Value values = sensor["Combination"];
170     if (values.size()) {
171         linked_sensors.reserve(values.size());
172         for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
173             linked_sensors.emplace_back(values[j].asString());
174             LOG(INFO) << "Sensor[" << name << "]'s Combination[" << j << "]: " << linked_sensors[j];
175         }
176     } else {
177         LOG(ERROR) << "Sensor[" << name << "] has no Combination setting";
178         return false;
179     }
180 
181     values = sensor["CombinationType"];
182     if (!values.size()) {
183         linked_sensors_type.reserve(linked_sensors.size());
184         for (size_t j = 0; j < linked_sensors.size(); ++j) {
185             linked_sensors_type.emplace_back(SensorFusionType::SENSOR);
186         }
187     } else if (values.size() != linked_sensors.size()) {
188         LOG(ERROR) << "Sensor[" << name << "] has invalid CombinationType size";
189         return false;
190     } else {
191         for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
192             if (values[j].asString().compare("SENSOR") == 0) {
193                 linked_sensors_type.emplace_back(SensorFusionType::SENSOR);
194             } else if (values[j].asString().compare("ODPM") == 0) {
195                 linked_sensors_type.emplace_back(SensorFusionType::ODPM);
196             } else if (values[j].asString().compare("CONSTANT") == 0) {
197                 linked_sensors_type.emplace_back(SensorFusionType::CONSTANT);
198             } else {
199                 LOG(ERROR) << "Sensor[" << name << "] has invalid CombinationType settings "
200                            << values[j].asString();
201                 return false;
202             }
203             LOG(INFO) << "Sensor[" << name << "]'s CombinationType[" << j
204                       << "]: " << linked_sensors_type[j];
205         }
206     }
207 
208     values = sensor["Coefficient"];
209     if (values.size()) {
210         coefficients.reserve(values.size());
211         for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
212             coefficients.emplace_back(values[j].asString());
213             LOG(INFO) << "Sensor[" << name << "]'s coefficient[" << j << "]: " << coefficients[j];
214         }
215     } else {
216         LOG(ERROR) << "Sensor[" << name << "] has no Coefficient setting";
217         return false;
218     }
219     if (linked_sensors.size() != coefficients.size()) {
220         LOG(ERROR) << "Sensor[" << name << "] has invalid Coefficient size";
221         return false;
222     }
223 
224     values = sensor["CoefficientType"];
225     if (!values.size()) {
226         coefficients_type.reserve(linked_sensors.size());
227         for (size_t j = 0; j < linked_sensors.size(); ++j) {
228             coefficients_type.emplace_back(SensorFusionType::CONSTANT);
229         }
230     } else if (values.size() != coefficients.size()) {
231         LOG(ERROR) << "Sensor[" << name << "] has invalid coefficient type size";
232         return false;
233     } else {
234         for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
235             if (values[j].asString().compare("CONSTANT") == 0) {
236                 coefficients_type.emplace_back(SensorFusionType::CONSTANT);
237             } else if (values[j].asString().compare("SENSOR") == 0) {
238                 coefficients_type.emplace_back(SensorFusionType::SENSOR);
239             } else if (values[j].asString().compare("ODPM") == 0) {
240                 coefficients_type.emplace_back(SensorFusionType::ODPM);
241             } else {
242                 LOG(ERROR) << "Sensor[" << name << "] has invalid coefficient options "
243                            << values[j].asString();
244                 return false;
245             }
246             LOG(INFO) << "Sensor[" << name << "]'s coefficient type[" << j
247                       << "]: " << coefficients_type[j];
248         }
249     }
250 
251     if (linked_sensors.size() != coefficients_type.size()) {
252         LOG(ERROR) << "Sensor[" << name
253                    << "]'s combination size is not matched with coefficient type size";
254         return false;
255     }
256 
257     if (!sensor["Offset"].empty()) {
258         offset = sensor["Offset"].asFloat();
259     }
260 
261     values = sensor["TriggerSensor"];
262     if (!values.empty()) {
263         if (values.isString()) {
264             trigger_sensors.emplace_back(values.asString());
265             LOG(INFO) << "Sensor[" << name << "]'s TriggerSensor: " << values.asString();
266         } else if (values.size()) {
267             trigger_sensors.reserve(values.size());
268             for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
269                 if (!values[j].isString()) {
270                     LOG(ERROR) << name << " TriggerSensor should be an array of string";
271                     return false;
272                 }
273                 trigger_sensors.emplace_back(values[j].asString());
274                 LOG(INFO) << "Sensor[" << name << "]'s TriggerSensor[" << j
275                           << "]: " << trigger_sensors[j];
276             }
277         } else {
278             LOG(ERROR) << "Sensor[" << name << "]'s TriggerSensor should be a string";
279             return false;
280         }
281     }
282 
283     if (sensor["Formula"].asString().compare("COUNT_THRESHOLD") == 0) {
284         formula = FormulaOption::COUNT_THRESHOLD;
285     } else if (sensor["Formula"].asString().compare("WEIGHTED_AVG") == 0) {
286         formula = FormulaOption::WEIGHTED_AVG;
287     } else if (sensor["Formula"].asString().compare("MAXIMUM") == 0) {
288         formula = FormulaOption::MAXIMUM;
289     } else if (sensor["Formula"].asString().compare("MINIMUM") == 0) {
290         formula = FormulaOption::MINIMUM;
291     } else {
292         LOG(ERROR) << "Sensor[" << name << "]'s Formula is invalid";
293         return false;
294     }
295     virtual_sensor_info->reset(new VirtualSensorInfo{linked_sensors, linked_sensors_type,
296                                                      coefficients, coefficients_type, offset,
297                                                      trigger_sensors, formula});
298     return true;
299 }
300 
ParseBindedCdevInfo(const Json::Value & values,std::unordered_map<std::string,BindedCdevInfo> * binded_cdev_info_map,const bool support_pid,bool * support_hard_limit)301 bool ParseBindedCdevInfo(const Json::Value &values,
302                          std::unordered_map<std::string, BindedCdevInfo> *binded_cdev_info_map,
303                          const bool support_pid, bool *support_hard_limit) {
304     for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
305         Json::Value sub_values;
306         const std::string &cdev_name = values[j]["CdevRequest"].asString();
307         ThrottlingArray cdev_weight_for_pid;
308         cdev_weight_for_pid.fill(NAN);
309         CdevArray cdev_ceiling;
310         cdev_ceiling.fill(std::numeric_limits<int>::max());
311         int max_release_step = std::numeric_limits<int>::max();
312         int max_throttle_step = std::numeric_limits<int>::max();
313         if (support_pid) {
314             if (!values[j]["CdevWeightForPID"].empty()) {
315                 LOG(INFO) << "Star to parse " << cdev_name << "'s CdevWeightForPID";
316                 if (!getFloatFromJsonValues(values[j]["CdevWeightForPID"], &cdev_weight_for_pid,
317                                             false, false)) {
318                     LOG(ERROR) << "Failed to parse CdevWeightForPID";
319                     binded_cdev_info_map->clear();
320                     return false;
321                 }
322             }
323             if (!values[j]["CdevCeiling"].empty()) {
324                 LOG(INFO) << "Start to parse CdevCeiling: " << cdev_name;
325                 if (!getIntFromJsonValues(values[j]["CdevCeiling"], &cdev_ceiling, false, false)) {
326                     LOG(ERROR) << "Failed to parse CdevCeiling";
327                     binded_cdev_info_map->clear();
328                     return false;
329                 }
330             }
331 
332             if (!values[j]["MaxReleaseStep"].empty()) {
333                 max_release_step = getIntFromValue(values[j]["MaxReleaseStep"]);
334                 if (max_release_step < 0) {
335                     LOG(ERROR) << cdev_name << " MaxReleaseStep: " << max_release_step;
336                     binded_cdev_info_map->clear();
337                     return false;
338                 } else {
339                     LOG(INFO) << cdev_name << " MaxReleaseStep: " << max_release_step;
340                 }
341             }
342             if (!values[j]["MaxThrottleStep"].empty()) {
343                 max_throttle_step = getIntFromValue(values[j]["MaxThrottleStep"]);
344                 if (max_throttle_step < 0) {
345                     LOG(ERROR) << cdev_name << " MaxThrottleStep: " << max_throttle_step;
346                     binded_cdev_info_map->clear();
347                     return false;
348                 } else {
349                     LOG(INFO) << cdev_name << " MaxThrottleStep: " << max_throttle_step;
350                 }
351             }
352         }
353         CdevArray limit_info;
354         limit_info.fill(0);
355         ThrottlingArray power_thresholds;
356         power_thresholds.fill(NAN);
357         ReleaseLogic release_logic = ReleaseLogic::NONE;
358 
359         sub_values = values[j]["LimitInfo"];
360         if (sub_values.size()) {
361             LOG(INFO) << "Start to parse LimitInfo: " << cdev_name;
362             if (!getIntFromJsonValues(sub_values, &limit_info, false, false)) {
363                 LOG(ERROR) << "Failed to parse LimitInfo";
364                 binded_cdev_info_map->clear();
365                 return false;
366             }
367             *support_hard_limit = true;
368         }
369         // Parse linked power info
370         std::string power_rail;
371         bool high_power_check = false;
372         bool throttling_with_power_link = false;
373         bool enabled = true;
374         CdevArray cdev_floor_with_power_link;
375         cdev_floor_with_power_link.fill(0);
376 
377         const bool power_link_disabled =
378                 ::android::base::GetBoolProperty(kPowerLinkDisabledProperty.data(), false);
379         if (!power_link_disabled) {
380             power_rail = values[j]["BindedPowerRail"].asString();
381 
382             if (values[j]["HighPowerCheck"].asBool()) {
383                 high_power_check = true;
384             }
385             LOG(INFO) << "Highpowercheck: " << std::boolalpha << high_power_check;
386 
387             if (values[j]["ThrottlingWithPowerLink"].asBool()) {
388                 throttling_with_power_link = true;
389             }
390             LOG(INFO) << "ThrottlingwithPowerLink: " << std::boolalpha
391                       << throttling_with_power_link;
392 
393             sub_values = values[j]["CdevFloorWithPowerLink"];
394             if (sub_values.size()) {
395                 LOG(INFO) << "Start to parse " << cdev_name << "'s CdevFloorWithPowerLink";
396                 if (!getIntFromJsonValues(sub_values, &cdev_floor_with_power_link, false, false)) {
397                     LOG(ERROR) << "Failed to parse CdevFloor";
398                     binded_cdev_info_map->clear();
399                     return false;
400                 }
401             }
402             sub_values = values[j]["PowerThreshold"];
403             if (sub_values.size()) {
404                 LOG(INFO) << "Start to parse " << cdev_name << "'s PowerThreshold";
405                 if (!getFloatFromJsonValues(sub_values, &power_thresholds, false, false)) {
406                     LOG(ERROR) << "Failed to parse power thresholds";
407                     binded_cdev_info_map->clear();
408                     return false;
409                 }
410                 if (values[j]["ReleaseLogic"].asString() == "INCREASE") {
411                     release_logic = ReleaseLogic::INCREASE;
412                     LOG(INFO) << "Release logic: INCREASE";
413                 } else if (values[j]["ReleaseLogic"].asString() == "DECREASE") {
414                     release_logic = ReleaseLogic::DECREASE;
415                     LOG(INFO) << "Release logic: DECREASE";
416                 } else if (values[j]["ReleaseLogic"].asString() == "STEPWISE") {
417                     release_logic = ReleaseLogic::STEPWISE;
418                     LOG(INFO) << "Release logic: STEPWISE";
419                 } else if (values[j]["ReleaseLogic"].asString() == "RELEASE_TO_FLOOR") {
420                     release_logic = ReleaseLogic::RELEASE_TO_FLOOR;
421                     LOG(INFO) << "Release logic: RELEASE_TO_FLOOR";
422                 } else {
423                     LOG(ERROR) << "Release logic is invalid";
424                     binded_cdev_info_map->clear();
425                     return false;
426                 }
427             }
428         }
429         if (values[j]["Disabled"].asBool()) {
430             enabled = false;
431         }
432 
433         (*binded_cdev_info_map)[cdev_name] = {
434                 .limit_info = limit_info,
435                 .power_thresholds = power_thresholds,
436                 .release_logic = release_logic,
437                 .high_power_check = high_power_check,
438                 .throttling_with_power_link = throttling_with_power_link,
439                 .cdev_weight_for_pid = cdev_weight_for_pid,
440                 .cdev_ceiling = cdev_ceiling,
441                 .max_release_step = max_release_step,
442                 .max_throttle_step = max_throttle_step,
443                 .cdev_floor_with_power_link = cdev_floor_with_power_link,
444                 .power_rail = power_rail,
445                 .enabled = enabled,
446         };
447     }
448     return true;
449 }
450 
ParseSensorThrottlingInfo(const std::string_view name,const Json::Value & sensor,bool * support_throttling,std::shared_ptr<ThrottlingInfo> * throttling_info)451 bool ParseSensorThrottlingInfo(const std::string_view name, const Json::Value &sensor,
452                                bool *support_throttling,
453                                std::shared_ptr<ThrottlingInfo> *throttling_info) {
454     std::array<float, kThrottlingSeverityCount> k_po;
455     k_po.fill(0.0);
456     std::array<float, kThrottlingSeverityCount> k_pu;
457     k_pu.fill(0.0);
458     std::array<float, kThrottlingSeverityCount> k_i;
459     k_i.fill(0.0);
460     std::array<float, kThrottlingSeverityCount> k_d;
461     k_d.fill(0.0);
462     std::array<float, kThrottlingSeverityCount> i_max;
463     i_max.fill(NAN);
464     std::array<float, kThrottlingSeverityCount> max_alloc_power;
465     max_alloc_power.fill(NAN);
466     std::array<float, kThrottlingSeverityCount> min_alloc_power;
467     min_alloc_power.fill(NAN);
468     std::array<float, kThrottlingSeverityCount> s_power;
469     s_power.fill(NAN);
470     std::array<float, kThrottlingSeverityCount> i_cutoff;
471     i_cutoff.fill(NAN);
472     float i_default = 0.0;
473     int tran_cycle = 0;
474     bool support_pid = false;
475     bool support_hard_limit = false;
476 
477     // Parse PID parameters
478     if (!sensor["PIDInfo"].empty()) {
479         LOG(INFO) << "Start to parse"
480                   << " Sensor[" << name << "]'s K_Po";
481         if (sensor["PIDInfo"]["K_Po"].empty() ||
482             !getFloatFromJsonValues(sensor["PIDInfo"]["K_Po"], &k_po, false, false)) {
483             LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_Po";
484             return false;
485         }
486         LOG(INFO) << "Start to parse"
487                   << " Sensor[" << name << "]'s  K_Pu";
488         if (sensor["PIDInfo"]["K_Pu"].empty() ||
489             !getFloatFromJsonValues(sensor["PIDInfo"]["K_Pu"], &k_pu, false, false)) {
490             LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_Pu";
491             return false;
492         }
493         LOG(INFO) << "Start to parse"
494                   << " Sensor[" << name << "]'s K_I";
495         if (sensor["PIDInfo"]["K_I"].empty() ||
496             !getFloatFromJsonValues(sensor["PIDInfo"]["K_I"], &k_i, false, false)) {
497             LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_I";
498             return false;
499         }
500         LOG(INFO) << "Start to parse"
501                   << " Sensor[" << name << "]'s K_D";
502         if (sensor["PIDInfo"]["K_D"].empty() ||
503             !getFloatFromJsonValues(sensor["PIDInfo"]["K_D"], &k_d, false, false)) {
504             LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_D";
505             return false;
506         }
507         LOG(INFO) << "Start to parse"
508                   << " Sensor[" << name << "]'s I_Max";
509         if (sensor["PIDInfo"]["I_Max"].empty() ||
510             !getFloatFromJsonValues(sensor["PIDInfo"]["I_Max"], &i_max, false, false)) {
511             LOG(ERROR) << "Sensor[" << name << "]: Failed to parse I_Max";
512             return false;
513         }
514         LOG(INFO) << "Start to parse"
515                   << " Sensor[" << name << "]'s MaxAllocPower";
516         if (sensor["PIDInfo"]["MaxAllocPower"].empty() ||
517             !getFloatFromJsonValues(sensor["PIDInfo"]["MaxAllocPower"], &max_alloc_power, false,
518                                     true)) {
519             LOG(ERROR) << "Sensor[" << name << "]: Failed to parse MaxAllocPower";
520             return false;
521         }
522         LOG(INFO) << "Start to parse"
523                   << " Sensor[" << name << "]'s MinAllocPower";
524         if (sensor["PIDInfo"]["MinAllocPower"].empty() ||
525             !getFloatFromJsonValues(sensor["PIDInfo"]["MinAllocPower"], &min_alloc_power, false,
526                                     true)) {
527             LOG(ERROR) << "Sensor[" << name << "]: Failed to parse MinAllocPower";
528             return false;
529         }
530         LOG(INFO) << "Start to parse Sensor[" << name << "]'s S_Power";
531         if (sensor["PIDInfo"]["S_Power"].empty() ||
532             !getFloatFromJsonValues(sensor["PIDInfo"]["S_Power"], &s_power, false, true)) {
533             LOG(ERROR) << "Sensor[" << name << "]: Failed to parse S_Power";
534             return false;
535         }
536         LOG(INFO) << "Start to parse Sensor[" << name << "]'s I_Cutoff";
537         if (sensor["PIDInfo"]["I_Cutoff"].empty() ||
538             !getFloatFromJsonValues(sensor["PIDInfo"]["I_Cutoff"], &i_cutoff, false, false)) {
539             LOG(ERROR) << "Sensor[" << name << "]: Failed to parse I_Cutoff";
540             return false;
541         }
542         i_default = getFloatFromValue(sensor["PIDInfo"]["I_Default"]);
543         LOG(INFO) << "Sensor[" << name << "]'s I_Default: " << i_default;
544 
545         tran_cycle = getFloatFromValue(sensor["PIDInfo"]["TranCycle"]);
546         LOG(INFO) << "Sensor[" << name << "]'s TranCycle: " << tran_cycle;
547 
548         // Confirm we have at least one valid PID combination
549         bool valid_pid_combination = false;
550         for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
551             if (!std::isnan(s_power[j])) {
552                 if (std::isnan(k_po[j]) || std::isnan(k_pu[j]) || std::isnan(k_i[j]) ||
553                     std::isnan(k_d[j]) || std::isnan(i_max[j]) || std::isnan(max_alloc_power[j]) ||
554                     std::isnan(min_alloc_power[j]) || std::isnan(i_cutoff[j])) {
555                     valid_pid_combination = false;
556                     break;
557                 } else {
558                     valid_pid_combination = true;
559                 }
560             }
561         }
562         if (!valid_pid_combination) {
563             LOG(ERROR) << "Sensor[" << name << "]: Invalid PID parameters combinations";
564             return false;
565         } else {
566             support_pid = true;
567         }
568     }
569 
570     // Parse binded cooling device
571     std::unordered_map<std::string, BindedCdevInfo> binded_cdev_info_map;
572     if (!ParseBindedCdevInfo(sensor["BindedCdevInfo"], &binded_cdev_info_map, support_pid,
573                              &support_hard_limit)) {
574         LOG(ERROR) << "Sensor[" << name << "]: failed to parse BindedCdevInfo";
575         return false;
576     }
577     Json::Value values;
578     ProfileMap profile_map;
579 
580     values = sensor["Profile"];
581     for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
582         Json::Value sub_values;
583         const std::string &mode = values[j]["Mode"].asString();
584         std::unordered_map<std::string, BindedCdevInfo> binded_cdev_info_map_profile;
585         if (!ParseBindedCdevInfo(values[j]["BindedCdevInfo"], &binded_cdev_info_map_profile,
586                                  support_pid, &support_hard_limit)) {
587             LOG(ERROR) << "Sensor[" << name << " failed to parse BindedCdevInfo profile";
588         }
589         // Check if the binded_cdev_info_map_profile is valid
590         if (binded_cdev_info_map.size() != binded_cdev_info_map_profile.size()) {
591             LOG(ERROR) << "Sensor[" << name << "]:'s profile map size should not be changed";
592             return false;
593         } else {
594             for (const auto &binded_cdev_info_pair : binded_cdev_info_map_profile) {
595                 if (binded_cdev_info_map.count(binded_cdev_info_pair.first)) {
596                     if (binded_cdev_info_pair.second.power_rail !=
597                         binded_cdev_info_map.at(binded_cdev_info_pair.first).power_rail) {
598                         LOG(ERROR) << "Sensor[" << name << "]:'s profile " << mode << " binded "
599                                    << binded_cdev_info_pair.first
600                                    << "'s power rail is not included in default rules";
601                         return false;
602                     } else {
603                         LOG(INFO) << "Sensor[" << name << "]:'s profile " << mode
604                                   << " is parsed successfully";
605                     }
606                 } else {
607                     LOG(ERROR) << "Sensor[" << name << "]'s profile " << mode << " binded "
608                                << binded_cdev_info_pair.first
609                                << " is not included in default rules";
610                     return false;
611                 }
612             }
613         }
614         profile_map[mode] = binded_cdev_info_map_profile;
615     }
616 
617     std::unordered_map<std::string, ThrottlingArray> excluded_power_info_map;
618     values = sensor["ExcludedPowerInfo"];
619     for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
620         Json::Value sub_values;
621         const std::string &power_rail = values[j]["PowerRail"].asString();
622         if (power_rail.empty()) {
623             LOG(ERROR) << "Sensor[" << name << "] failed to parse excluded PowerRail";
624             return false;
625         }
626         ThrottlingArray power_weight;
627         power_weight.fill(1);
628         if (!values[j]["PowerWeight"].empty()) {
629             LOG(INFO) << "Sensor[" << name << "]: Start to parse " << power_rail
630                       << "'s PowerWeight";
631             if (!getFloatFromJsonValues(values[j]["PowerWeight"], &power_weight, false, false)) {
632                 LOG(ERROR) << "Failed to parse PowerWeight";
633                 return false;
634             }
635         }
636         excluded_power_info_map[power_rail] = power_weight;
637     }
638     throttling_info->reset(new ThrottlingInfo{
639             k_po, k_pu, k_i, k_d, i_max, max_alloc_power, min_alloc_power, s_power, i_cutoff,
640             i_default, tran_cycle, excluded_power_info_map, binded_cdev_info_map, profile_map});
641     *support_throttling = support_pid | support_hard_limit;
642     return true;
643 }
644 
ParseSensorInfo(const Json::Value & config,std::unordered_map<std::string,SensorInfo> * sensors_parsed)645 bool ParseSensorInfo(const Json::Value &config,
646                      std::unordered_map<std::string, SensorInfo> *sensors_parsed) {
647     Json::Value sensors = config["Sensors"];
648     std::size_t total_parsed = 0;
649     std::unordered_set<std::string> sensors_name_parsed;
650 
651     for (Json::Value::ArrayIndex i = 0; i < sensors.size(); ++i) {
652         const std::string &name = sensors[i]["Name"].asString();
653         LOG(INFO) << "Sensor[" << i << "]'s Name: " << name;
654         if (name.empty()) {
655             LOG(ERROR) << "Failed to read Sensor[" << i << "]'s Name";
656             sensors_parsed->clear();
657             return false;
658         }
659 
660         auto result = sensors_name_parsed.insert(name);
661         if (!result.second) {
662             LOG(ERROR) << "Duplicate Sensor[" << i << "]'s Name";
663             sensors_parsed->clear();
664             return false;
665         }
666 
667         std::string sensor_type_str = sensors[i]["Type"].asString();
668         LOG(INFO) << "Sensor[" << name << "]'s Type: " << sensor_type_str;
669         TemperatureType sensor_type;
670 
671         if (!getTypeFromString(sensor_type_str, &sensor_type)) {
672             LOG(ERROR) << "Invalid Sensor[" << name << "]'s Type: " << sensor_type_str;
673             sensors_parsed->clear();
674             return false;
675         }
676 
677         bool send_cb = false;
678         if (!sensors[i]["Monitor"].empty() && sensors[i]["Monitor"].isBool()) {
679             send_cb = sensors[i]["Monitor"].asBool();
680         } else if (!sensors[i]["SendCallback"].empty() && sensors[i]["SendCallback"].isBool()) {
681             send_cb = sensors[i]["SendCallback"].asBool();
682         }
683         LOG(INFO) << "Sensor[" << name << "]'s SendCallback: " << std::boolalpha << send_cb
684                   << std::noboolalpha;
685 
686         bool send_powerhint = false;
687         if (sensors[i]["SendPowerHint"].empty() || !sensors[i]["SendPowerHint"].isBool()) {
688             LOG(INFO) << "Failed to read Sensor[" << name << "]'s SendPowerHint, set to 'false'";
689         } else if (sensors[i]["SendPowerHint"].asBool()) {
690             send_powerhint = true;
691         }
692         LOG(INFO) << "Sensor[" << name << "]'s SendPowerHint: " << std::boolalpha << send_powerhint
693                   << std::noboolalpha;
694 
695         bool is_hidden = false;
696         if (sensors[i]["Hidden"].empty() || !sensors[i]["Hidden"].isBool()) {
697             LOG(INFO) << "Failed to read Sensor[" << name << "]'s Hidden, set to 'false'";
698         } else if (sensors[i]["Hidden"].asBool()) {
699             is_hidden = true;
700         }
701         LOG(INFO) << "Sensor[" << name << "]'s Hidden: " << std::boolalpha << is_hidden
702                   << std::noboolalpha;
703 
704         std::array<float, kThrottlingSeverityCount> hot_thresholds;
705         hot_thresholds.fill(NAN);
706         std::array<float, kThrottlingSeverityCount> cold_thresholds;
707         cold_thresholds.fill(NAN);
708         std::array<float, kThrottlingSeverityCount> hot_hysteresis;
709         hot_hysteresis.fill(0.0);
710         std::array<float, kThrottlingSeverityCount> cold_hysteresis;
711         cold_hysteresis.fill(0.0);
712 
713         Json::Value values = sensors[i]["HotThreshold"];
714         if (!values.size()) {
715             LOG(INFO) << "Sensor[" << name << "]'s HotThreshold, default all to NAN";
716         } else if (values.size() != kThrottlingSeverityCount) {
717             LOG(ERROR) << "Invalid Sensor[" << name << "]'s HotThreshold count:" << values.size();
718             sensors_parsed->clear();
719             return false;
720         } else {
721             float min = std::numeric_limits<float>::min();
722             for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
723                 hot_thresholds[j] = getFloatFromValue(values[j]);
724                 if (!std::isnan(hot_thresholds[j])) {
725                     if (hot_thresholds[j] < min) {
726                         LOG(ERROR) << "Invalid "
727                                    << "Sensor[" << name << "]'s HotThreshold[j" << j
728                                    << "]: " << hot_thresholds[j] << " < " << min;
729                         sensors_parsed->clear();
730                         return false;
731                     }
732                     min = hot_thresholds[j];
733                 }
734                 LOG(INFO) << "Sensor[" << name << "]'s HotThreshold[" << j
735                           << "]: " << hot_thresholds[j];
736             }
737         }
738 
739         values = sensors[i]["HotHysteresis"];
740         if (!values.size()) {
741             LOG(INFO) << "Sensor[" << name << "]'s HotHysteresis, default all to 0.0";
742         } else if (values.size() != kThrottlingSeverityCount) {
743             LOG(ERROR) << "Invalid Sensor[" << name << "]'s HotHysteresis, count:" << values.size();
744             sensors_parsed->clear();
745             return false;
746         } else {
747             for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
748                 hot_hysteresis[j] = getFloatFromValue(values[j]);
749                 if (std::isnan(hot_hysteresis[j])) {
750                     LOG(ERROR) << "Invalid Sensor[" << name
751                                << "]'s HotHysteresis: " << hot_hysteresis[j];
752                     sensors_parsed->clear();
753                     return false;
754                 }
755                 LOG(INFO) << "Sensor[" << name << "]'s HotHysteresis[" << j
756                           << "]: " << hot_hysteresis[j];
757             }
758         }
759 
760         for (Json::Value::ArrayIndex j = 0; j < (kThrottlingSeverityCount - 1); ++j) {
761             if (std::isnan(hot_thresholds[j])) {
762                 continue;
763             }
764             for (auto k = j + 1; k < kThrottlingSeverityCount; ++k) {
765                 if (std::isnan(hot_thresholds[k])) {
766                     continue;
767                 } else if (hot_thresholds[j] > (hot_thresholds[k] - hot_hysteresis[k])) {
768                     LOG(ERROR) << "Sensor[" << name << "]'s hot threshold " << j
769                                << " is overlapped";
770                     sensors_parsed->clear();
771                     return false;
772                 } else {
773                     break;
774                 }
775             }
776         }
777 
778         values = sensors[i]["ColdThreshold"];
779         if (!values.size()) {
780             LOG(INFO) << "Sensor[" << name << "]'s ColdThreshold, default all to NAN";
781         } else if (values.size() != kThrottlingSeverityCount) {
782             LOG(ERROR) << "Invalid Sensor[" << name << "]'s ColdThreshold count:" << values.size();
783             sensors_parsed->clear();
784             return false;
785         } else {
786             float max = std::numeric_limits<float>::max();
787             for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
788                 cold_thresholds[j] = getFloatFromValue(values[j]);
789                 if (!std::isnan(cold_thresholds[j])) {
790                     if (cold_thresholds[j] > max) {
791                         LOG(ERROR) << "Invalid "
792                                    << "Sensor[" << name << "]'s ColdThreshold[j" << j
793                                    << "]: " << cold_thresholds[j] << " > " << max;
794                         sensors_parsed->clear();
795                         return false;
796                     }
797                     max = cold_thresholds[j];
798                 }
799                 LOG(INFO) << "Sensor[" << name << "]'s ColdThreshold[" << j
800                           << "]: " << cold_thresholds[j];
801             }
802         }
803 
804         values = sensors[i]["ColdHysteresis"];
805         if (!values.size()) {
806             LOG(INFO) << "Sensor[" << name << "]'s ColdHysteresis, default all to 0.0";
807         } else if (values.size() != kThrottlingSeverityCount) {
808             LOG(ERROR) << "Invalid Sensor[" << name << "]'s ColdHysteresis count:" << values.size();
809             sensors_parsed->clear();
810             return false;
811         } else {
812             for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
813                 cold_hysteresis[j] = getFloatFromValue(values[j]);
814                 if (std::isnan(cold_hysteresis[j])) {
815                     LOG(ERROR) << "Invalid Sensor[" << name
816                                << "]'s ColdHysteresis: " << cold_hysteresis[j];
817                     sensors_parsed->clear();
818                     return false;
819                 }
820                 LOG(INFO) << "Sensor[" << name << "]'s ColdHysteresis[" << j
821                           << "]: " << cold_hysteresis[j];
822             }
823         }
824 
825         for (Json::Value::ArrayIndex j = 0; j < (kThrottlingSeverityCount - 1); ++j) {
826             if (std::isnan(cold_thresholds[j])) {
827                 continue;
828             }
829             for (auto k = j + 1; k < kThrottlingSeverityCount; ++k) {
830                 if (std::isnan(cold_thresholds[k])) {
831                     continue;
832                 } else if (cold_thresholds[j] < (cold_thresholds[k] + cold_hysteresis[k])) {
833                     LOG(ERROR) << "Sensor[" << name << "]'s cold threshold " << j
834                                << " is overlapped";
835                     sensors_parsed->clear();
836                     return false;
837                 } else {
838                     break;
839                 }
840             }
841         }
842 
843         std::string temp_path;
844         if (!sensors[i]["TempPath"].empty()) {
845             temp_path = sensors[i]["TempPath"].asString();
846             LOG(INFO) << "Sensor[" << name << "]'s TempPath: " << temp_path;
847         }
848 
849         float vr_threshold = NAN;
850         if (!sensors[i]["VrThreshold"].empty()) {
851             vr_threshold = getFloatFromValue(sensors[i]["VrThreshold"]);
852             LOG(INFO) << "Sensor[" << name << "]'s VrThreshold: " << vr_threshold;
853         }
854         float multiplier = sensors[i]["Multiplier"].asFloat();
855         LOG(INFO) << "Sensor[" << name << "]'s Multiplier: " << multiplier;
856 
857         std::chrono::milliseconds polling_delay = kUeventPollTimeoutMs;
858         if (!sensors[i]["PollingDelay"].empty()) {
859             const auto value = getIntFromValue(sensors[i]["PollingDelay"]);
860             polling_delay = (value > 0) ? std::chrono::milliseconds(value)
861                                         : std::chrono::milliseconds::max();
862         }
863         LOG(INFO) << "Sensor[" << name << "]'s Polling delay: " << polling_delay.count();
864 
865         std::chrono::milliseconds passive_delay = kMinPollIntervalMs;
866         if (!sensors[i]["PassiveDelay"].empty()) {
867             const auto value = getIntFromValue(sensors[i]["PassiveDelay"]);
868             passive_delay = (value > 0) ? std::chrono::milliseconds(value)
869                                         : std::chrono::milliseconds::max();
870         }
871         LOG(INFO) << "Sensor[" << name << "]'s Passive delay: " << passive_delay.count();
872 
873         std::chrono::milliseconds time_resolution;
874         if (sensors[i]["TimeResolution"].empty()) {
875             time_resolution = kMinPollIntervalMs;
876         } else {
877             time_resolution =
878                     std::chrono::milliseconds(getIntFromValue(sensors[i]["TimeResolution"]));
879         }
880         LOG(INFO) << "Sensor[" << name << "]'s Time resolution: " << time_resolution.count();
881 
882         float step_ratio = NAN;
883         if (!sensors[i]["StepRatio"].empty()) {
884             step_ratio = sensors[i]["StepRatio"].asFloat();
885             if (step_ratio < 0 || step_ratio > 1) {
886                 LOG(ERROR) << "Sensor[" << name << "]'s StepRatio should be set 0 ~ 1";
887                 sensors_parsed->clear();
888                 return false;
889             }
890         }
891 
892         if (is_hidden && send_cb) {
893             LOG(ERROR) << "is_hidden and send_cb cannot be enabled together";
894             sensors_parsed->clear();
895             return false;
896         }
897 
898         std::unique_ptr<VirtualSensorInfo> virtual_sensor_info;
899         if (!ParseVirtualSensorInfo(name, sensors[i], &virtual_sensor_info)) {
900             LOG(ERROR) << "Sensor[" << name << "]: failed to parse virtual sensor info";
901             sensors_parsed->clear();
902             return false;
903         }
904 
905         bool support_throttling = false;  // support pid or hard limit
906         std::shared_ptr<ThrottlingInfo> throttling_info;
907         if (!ParseSensorThrottlingInfo(name, sensors[i], &support_throttling, &throttling_info)) {
908             LOG(ERROR) << "Sensor[" << name << "]: failed to parse throttling info";
909             sensors_parsed->clear();
910             return false;
911         }
912 
913         bool is_watch = (send_cb | send_powerhint | support_throttling);
914         LOG(INFO) << "Sensor[" << name << "]'s is_watch: " << std::boolalpha << is_watch;
915 
916         (*sensors_parsed)[name] = {
917                 .type = sensor_type,
918                 .hot_thresholds = hot_thresholds,
919                 .cold_thresholds = cold_thresholds,
920                 .hot_hysteresis = hot_hysteresis,
921                 .cold_hysteresis = cold_hysteresis,
922                 .temp_path = temp_path,
923                 .vr_threshold = vr_threshold,
924                 .multiplier = multiplier,
925                 .polling_delay = polling_delay,
926                 .passive_delay = passive_delay,
927                 .time_resolution = time_resolution,
928                 .step_ratio = step_ratio,
929                 .send_cb = send_cb,
930                 .send_powerhint = send_powerhint,
931                 .is_watch = is_watch,
932                 .is_hidden = is_hidden,
933                 .virtual_sensor_info = std::move(virtual_sensor_info),
934                 .throttling_info = std::move(throttling_info),
935         };
936 
937         ++total_parsed;
938     }
939     LOG(INFO) << total_parsed << " Sensors parsed successfully";
940     return true;
941 }
942 
ParseCoolingDevice(const Json::Value & config,std::unordered_map<std::string,CdevInfo> * cooling_devices_parsed)943 bool ParseCoolingDevice(const Json::Value &config,
944                         std::unordered_map<std::string, CdevInfo> *cooling_devices_parsed) {
945     Json::Value cooling_devices = config["CoolingDevices"];
946     std::size_t total_parsed = 0;
947     std::unordered_set<std::string> cooling_devices_name_parsed;
948 
949     for (Json::Value::ArrayIndex i = 0; i < cooling_devices.size(); ++i) {
950         const std::string &name = cooling_devices[i]["Name"].asString();
951         LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name;
952         if (name.empty()) {
953             LOG(ERROR) << "Failed to read CoolingDevice[" << i << "]'s Name";
954             cooling_devices_parsed->clear();
955             return false;
956         }
957 
958         auto result = cooling_devices_name_parsed.insert(name.data());
959         if (!result.second) {
960             LOG(ERROR) << "Duplicate CoolingDevice[" << i << "]'s Name";
961             cooling_devices_parsed->clear();
962             return false;
963         }
964 
965         std::string cooling_device_type_str = cooling_devices[i]["Type"].asString();
966         LOG(INFO) << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str;
967         CoolingType cooling_device_type;
968 
969         if (!getTypeFromString(cooling_device_type_str, &cooling_device_type)) {
970             LOG(ERROR) << "Invalid CoolingDevice[" << name
971                        << "]'s Type: " << cooling_device_type_str;
972             cooling_devices_parsed->clear();
973             return false;
974         }
975 
976         const std::string &read_path = cooling_devices[i]["ReadPath"].asString();
977         LOG(INFO) << "Cdev Read Path: " << (read_path.empty() ? "default" : read_path);
978 
979         const std::string &write_path = cooling_devices[i]["WritePath"].asString();
980         LOG(INFO) << "Cdev Write Path: " << (write_path.empty() ? "default" : write_path);
981 
982         std::vector<float> state2power;
983         Json::Value values = cooling_devices[i]["State2Power"];
984         if (values.size()) {
985             state2power.reserve(values.size());
986             for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
987                 state2power.emplace_back(getFloatFromValue(values[j]));
988                 LOG(INFO) << "Cooling device[" << name << "]'s Power2State[" << j
989                           << "]: " << state2power[j];
990             }
991         } else {
992             LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name
993                       << " does not support State2Power";
994         }
995 
996         const std::string &power_rail = cooling_devices[i]["PowerRail"].asString();
997         LOG(INFO) << "Cooling device power rail : " << power_rail;
998 
999         (*cooling_devices_parsed)[name] = {
1000                 .type = cooling_device_type,
1001                 .read_path = read_path,
1002                 .write_path = write_path,
1003                 .state2power = state2power,
1004         };
1005         ++total_parsed;
1006     }
1007     LOG(INFO) << total_parsed << " CoolingDevices parsed successfully";
1008     return true;
1009 }
1010 
ParsePowerRailInfo(const Json::Value & config,std::unordered_map<std::string,PowerRailInfo> * power_rails_parsed)1011 bool ParsePowerRailInfo(const Json::Value &config,
1012                         std::unordered_map<std::string, PowerRailInfo> *power_rails_parsed) {
1013     Json::Value power_rails = config["PowerRails"];
1014     std::size_t total_parsed = 0;
1015     std::unordered_set<std::string> power_rails_name_parsed;
1016 
1017     for (Json::Value::ArrayIndex i = 0; i < power_rails.size(); ++i) {
1018         const std::string &name = power_rails[i]["Name"].asString();
1019         LOG(INFO) << "PowerRail[" << i << "]'s Name: " << name;
1020         if (name.empty()) {
1021             LOG(ERROR) << "Failed to read PowerRail[" << i << "]'s Name";
1022             power_rails_parsed->clear();
1023             return false;
1024         }
1025 
1026         std::string rail;
1027         if (power_rails[i]["Rail"].empty()) {
1028             rail = name;
1029         } else {
1030             rail = power_rails[i]["Rail"].asString();
1031         }
1032         LOG(INFO) << "PowerRail[" << i << "]'s Rail: " << rail;
1033 
1034         std::vector<std::string> linked_power_rails;
1035         std::vector<float> coefficient;
1036         float offset = 0;
1037         FormulaOption formula = FormulaOption::COUNT_THRESHOLD;
1038         bool is_virtual_power_rail = false;
1039         Json::Value values;
1040         int power_sample_count = 0;
1041         std::chrono::milliseconds power_sample_delay;
1042 
1043         if (!power_rails[i]["VirtualRails"].empty() && power_rails[i]["VirtualRails"].isBool()) {
1044             is_virtual_power_rail = power_rails[i]["VirtualRails"].asBool();
1045             LOG(INFO) << "PowerRails[" << name << "]'s VirtualRail, set to 'true'";
1046         }
1047 
1048         if (is_virtual_power_rail) {
1049             values = power_rails[i]["Combination"];
1050             if (values.size()) {
1051                 linked_power_rails.reserve(values.size());
1052                 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
1053                     linked_power_rails.emplace_back(values[j].asString());
1054                     LOG(INFO) << "PowerRail[" << name << "]'s combination[" << j
1055                               << "]: " << linked_power_rails[j];
1056                 }
1057             } else {
1058                 LOG(ERROR) << "PowerRails[" << name << "] has no combination for VirtualRail";
1059                 power_rails_parsed->clear();
1060                 return false;
1061             }
1062 
1063             values = power_rails[i]["Coefficient"];
1064             if (values.size()) {
1065                 coefficient.reserve(values.size());
1066                 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
1067                     coefficient.emplace_back(getFloatFromValue(values[j]));
1068                     LOG(INFO) << "PowerRail[" << name << "]'s coefficient[" << j
1069                               << "]: " << coefficient[j];
1070                 }
1071             } else {
1072                 LOG(ERROR) << "PowerRails[" << name << "] has no coefficient for VirtualRail";
1073                 power_rails_parsed->clear();
1074                 return false;
1075             }
1076 
1077             if (linked_power_rails.size() != coefficient.size()) {
1078                 LOG(ERROR) << "PowerRails[" << name
1079                            << "]'s combination size is not matched with coefficient size";
1080                 power_rails_parsed->clear();
1081                 return false;
1082             }
1083 
1084             if (!power_rails[i]["Offset"].empty()) {
1085                 offset = power_rails[i]["Offset"].asFloat();
1086             }
1087 
1088             if (linked_power_rails.size() != coefficient.size()) {
1089                 LOG(ERROR) << "PowerRails[" << name
1090                            << "]'s combination size is not matched with coefficient size";
1091                 power_rails_parsed->clear();
1092                 return false;
1093             }
1094 
1095             if (power_rails[i]["Formula"].asString().compare("COUNT_THRESHOLD") == 0) {
1096                 formula = FormulaOption::COUNT_THRESHOLD;
1097             } else if (power_rails[i]["Formula"].asString().compare("WEIGHTED_AVG") == 0) {
1098                 formula = FormulaOption::WEIGHTED_AVG;
1099             } else if (power_rails[i]["Formula"].asString().compare("MAXIMUM") == 0) {
1100                 formula = FormulaOption::MAXIMUM;
1101             } else if (power_rails[i]["Formula"].asString().compare("MINIMUM") == 0) {
1102                 formula = FormulaOption::MINIMUM;
1103             } else {
1104                 LOG(ERROR) << "PowerRails[" << name << "]'s Formula is invalid";
1105                 power_rails_parsed->clear();
1106                 return false;
1107             }
1108         }
1109 
1110         std::unique_ptr<VirtualPowerRailInfo> virtual_power_rail_info;
1111         if (is_virtual_power_rail) {
1112             virtual_power_rail_info.reset(
1113                     new VirtualPowerRailInfo{linked_power_rails, coefficient, offset, formula});
1114         }
1115 
1116         power_sample_count = power_rails[i]["PowerSampleCount"].asInt();
1117         LOG(INFO) << "Power sample Count: " << power_sample_count;
1118 
1119         if (!power_rails[i]["PowerSampleDelay"]) {
1120             power_sample_delay = std::chrono::milliseconds::max();
1121         } else {
1122             power_sample_delay =
1123                     std::chrono::milliseconds(getIntFromValue(power_rails[i]["PowerSampleDelay"]));
1124         }
1125 
1126         (*power_rails_parsed)[name] = {
1127                 .rail = rail,
1128                 .power_sample_count = power_sample_count,
1129                 .power_sample_delay = power_sample_delay,
1130                 .virtual_power_rail_info = std::move(virtual_power_rail_info),
1131         };
1132         ++total_parsed;
1133     }
1134     LOG(INFO) << total_parsed << " PowerRails parsed successfully";
1135     return true;
1136 }
1137 
1138 template <typename T, typename U>
ParseStatsInfo(const Json::Value & stats_config,const std::unordered_map<std::string,U> & entity_info,StatsInfo<T> * stats_info,T min_value)1139 bool ParseStatsInfo(const Json::Value &stats_config,
1140                     const std::unordered_map<std::string, U> &entity_info, StatsInfo<T> *stats_info,
1141                     T min_value) {
1142     if (stats_config.empty()) {
1143         LOG(INFO) << "No stats config";
1144         return true;
1145     }
1146     std::variant<bool, std::unordered_set<std::string>>
1147             record_by_default_threshold_all_or_name_set_ = false;
1148     if (stats_config["DefaultThresholdEnableAll"].empty() ||
1149         !stats_config["DefaultThresholdEnableAll"].isBool()) {
1150         LOG(INFO) << "Failed to read stats DefaultThresholdEnableAll, set to 'false'";
1151     } else if (stats_config["DefaultThresholdEnableAll"].asBool()) {
1152         record_by_default_threshold_all_or_name_set_ = true;
1153     }
1154     LOG(INFO) << "DefaultThresholdEnableAll " << std::boolalpha
1155               << std::get<bool>(record_by_default_threshold_all_or_name_set_) << std::noboolalpha;
1156 
1157     Json::Value values = stats_config["RecordWithDefaultThreshold"];
1158     if (values.size()) {
1159         if (std::get<bool>(record_by_default_threshold_all_or_name_set_)) {
1160             LOG(ERROR) << "Cannot enable record with default threshold when "
1161                           "DefaultThresholdEnableAll true.";
1162             return false;
1163         }
1164         record_by_default_threshold_all_or_name_set_ = std::unordered_set<std::string>();
1165         for (Json::Value::ArrayIndex i = 0; i < values.size(); ++i) {
1166             std::string name = values[i].asString();
1167             if (!entity_info.count(name)) {
1168                 LOG(ERROR) << "Unknown name [" << name << "] not present in entity_info.";
1169                 return false;
1170             }
1171             std::get<std::unordered_set<std::string>>(record_by_default_threshold_all_or_name_set_)
1172                     .insert(name);
1173         }
1174     } else {
1175         LOG(INFO) << "No stat by default threshold enabled.";
1176     }
1177 
1178     std::unordered_map<std::string, std::vector<ThresholdList<T>>> record_by_threshold;
1179     values = stats_config["RecordWithThreshold"];
1180     if (values.size()) {
1181         Json::Value threshold_values;
1182         for (Json::Value::ArrayIndex i = 0; i < values.size(); i++) {
1183             const std::string &name = values[i]["Name"].asString();
1184             if (!entity_info.count(name)) {
1185                 LOG(ERROR) << "Unknown name [" << name << "] not present in entity_info.";
1186                 return false;
1187             }
1188 
1189             std::optional<std::string> logging_name;
1190             if (!values[i]["LoggingName"].empty()) {
1191                 logging_name = values[i]["LoggingName"].asString();
1192                 LOG(INFO) << "For [" << name << "]"
1193                           << ", stats logging name is [" << logging_name.value() << "]";
1194             }
1195 
1196             LOG(INFO) << "Start to parse stats threshold for [" << name << "]";
1197             threshold_values = values[i]["Thresholds"];
1198             if (threshold_values.empty()) {
1199                 LOG(ERROR) << "Empty stats threshold not valid.";
1200                 return false;
1201             }
1202             const auto &threshold_values_count = threshold_values.size();
1203             if (threshold_values_count > kMaxStatsThresholdCount) {
1204                 LOG(ERROR) << "Number of stats threshold " << threshold_values_count
1205                            << " greater than max " << kMaxStatsThresholdCount;
1206                 return false;
1207             }
1208             std::vector<T> stats_threshold(threshold_values_count);
1209             T prev_value = min_value;
1210             LOG(INFO) << "Thresholds:";
1211             for (Json::Value::ArrayIndex i = 0; i < threshold_values_count; ++i) {
1212                 stats_threshold[i] = std::is_floating_point_v<T>
1213                                              ? getFloatFromValue(threshold_values[i])
1214                                              : getIntFromValue(threshold_values[i]);
1215                 if (stats_threshold[i] <= prev_value) {
1216                     LOG(ERROR) << "Invalid array[" << i << "]" << stats_threshold[i]
1217                                << " is <=" << prev_value;
1218                     return false;
1219                 }
1220                 prev_value = stats_threshold[i];
1221                 LOG(INFO) << "[" << i << "]: " << stats_threshold[i];
1222             }
1223             record_by_threshold[name].emplace_back(logging_name, stats_threshold);
1224         }
1225     } else {
1226         LOG(INFO) << "No stat by threshold enabled.";
1227     }
1228 
1229     (*stats_info) = {.record_by_default_threshold_all_or_name_set_ =
1230                              record_by_default_threshold_all_or_name_set_,
1231                      .record_by_threshold = record_by_threshold};
1232     return true;
1233 }
1234 
ParseStatsConfig(const Json::Value & config,const std::unordered_map<std::string,SensorInfo> & sensor_info_map_,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map_,StatsConfig * stats_config_parsed)1235 bool ParseStatsConfig(const Json::Value &config,
1236                       const std::unordered_map<std::string, SensorInfo> &sensor_info_map_,
1237                       const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map_,
1238                       StatsConfig *stats_config_parsed) {
1239     Json::Value stats_config = config["Stats"];
1240 
1241     if (stats_config.empty()) {
1242         LOG(INFO) << "No Stats Config present.";
1243         return true;
1244     }
1245 
1246     LOG(INFO) << "Parse Stats Config for Sensor Temp.";
1247     // Parse sensor stats config
1248     if (!ParseStatsInfo(stats_config["Sensors"], sensor_info_map_,
1249                         &stats_config_parsed->sensor_stats_info,
1250                         std::numeric_limits<float>::lowest())) {
1251         LOG(ERROR) << "Failed to parse sensor temp stats info.";
1252         stats_config_parsed->clear();
1253         return false;
1254     }
1255 
1256     // Parse cooling device user vote
1257     if (stats_config["CoolingDevices"].empty()) {
1258         LOG(INFO) << "No cooling device stats present.";
1259         return true;
1260     }
1261 
1262     LOG(INFO) << "Parse Stats Config for Sensor CDev Request.";
1263     if (!ParseStatsInfo(stats_config["CoolingDevices"]["RecordVotePerSensor"],
1264                         cooling_device_info_map_, &stats_config_parsed->cooling_device_request_info,
1265                         -1)) {
1266         LOG(ERROR) << "Failed to parse cooling device user vote stats info.";
1267         stats_config_parsed->clear();
1268         return false;
1269     }
1270     return true;
1271 }
1272 
1273 }  // namespace implementation
1274 }  // namespace thermal
1275 }  // namespace hardware
1276 }  // namespace android
1277 }  // namespace aidl
1278