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