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 = (inc_check) ? std::numeric_limits<int>::min() : std::numeric_limits<int>::max();
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
getTempRangeInfoFromJsonValues(const Json::Value & values,TempRangeInfo * temp_range_info)133 bool getTempRangeInfoFromJsonValues(const Json::Value &values, TempRangeInfo *temp_range_info) {
134 if (values.size() != 2) {
135 LOG(ERROR) << "Temp Range Values size: " << values.size() << "is invalid.";
136 return false;
137 }
138
139 float min_temp = getFloatFromValue(values[0]);
140 float max_temp = getFloatFromValue(values[1]);
141
142 if (std::isnan(min_temp) || std::isnan(max_temp)) {
143 LOG(ERROR) << "Illegal temp range: thresholds not defined properly " << min_temp << " : "
144 << max_temp;
145 return false;
146 }
147
148 if (min_temp > max_temp) {
149 LOG(ERROR) << "Illegal temp range: temp_min_threshold(" << min_temp
150 << ") > temp_max_threshold(" << max_temp << ")";
151 return false;
152 }
153 temp_range_info->min_temp_threshold = min_temp;
154 temp_range_info->max_temp_threshold = max_temp;
155 LOG(INFO) << "Temp Range Info: " << temp_range_info->min_temp_threshold
156 << " <= t <= " << temp_range_info->max_temp_threshold;
157 return true;
158 }
159
getTempStuckInfoFromJsonValue(const Json::Value & values,TempStuckInfo * temp_stuck_info)160 bool getTempStuckInfoFromJsonValue(const Json::Value &values, TempStuckInfo *temp_stuck_info) {
161 if (values["MinStuckDuration"].empty()) {
162 LOG(ERROR) << "Minimum stuck duration not present.";
163 return false;
164 }
165 int min_stuck_duration_int = getIntFromValue(values["MinStuckDuration"]);
166 if (min_stuck_duration_int <= 0) {
167 LOG(ERROR) << "Invalid Minimum stuck duration " << min_stuck_duration_int;
168 return false;
169 }
170
171 if (values["MinPollingCount"].empty()) {
172 LOG(ERROR) << "Minimum polling count not present.";
173 return false;
174 }
175 int min_polling_count = getIntFromValue(values["MinPollingCount"]);
176 if (min_polling_count <= 0) {
177 LOG(ERROR) << "Invalid Minimum stuck duration " << min_polling_count;
178 return false;
179 }
180 temp_stuck_info->min_stuck_duration = std::chrono::milliseconds(min_stuck_duration_int);
181 temp_stuck_info->min_polling_count = min_polling_count;
182 LOG(INFO) << "Temp Stuck Info: polling_count=" << temp_stuck_info->min_polling_count
183 << " stuck_duration=" << temp_stuck_info->min_stuck_duration.count();
184 return true;
185 }
186 } // namespace
187
operator <<(std::ostream & stream,const SensorFusionType & sensor_fusion_type)188 std::ostream &operator<<(std::ostream &stream, const SensorFusionType &sensor_fusion_type) {
189 switch (sensor_fusion_type) {
190 case SensorFusionType::SENSOR:
191 return stream << "SENSOR";
192 case SensorFusionType::ODPM:
193 return stream << "ODPM";
194 case SensorFusionType::CONSTANT:
195 return stream << "CONSTANT";
196 default:
197 return stream << "UNDEFINED";
198 }
199 }
200
ParseThermalConfig(std::string_view config_path,Json::Value * config)201 bool ParseThermalConfig(std::string_view config_path, Json::Value *config) {
202 std::string json_doc;
203 if (!::android::base::ReadFileToString(config_path.data(), &json_doc)) {
204 LOG(ERROR) << "Failed to read JSON config from " << config_path;
205 return false;
206 }
207 Json::CharReaderBuilder builder;
208 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
209 std::string errorMessage;
210 if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), config, &errorMessage)) {
211 LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
212 return false;
213 }
214 return true;
215 }
216
ParseOffsetThresholds(const std::string_view name,const Json::Value & sensor,std::vector<float> * offset_thresholds,std::vector<float> * offset_values)217 bool ParseOffsetThresholds(const std::string_view name, const Json::Value &sensor,
218 std::vector<float> *offset_thresholds,
219 std::vector<float> *offset_values) {
220 Json::Value config_offset_thresholds = sensor["OffsetThresholds"];
221 Json::Value config_offset_values = sensor["OffsetValues"];
222
223 if (config_offset_thresholds.empty()) {
224 return true;
225 }
226
227 if (config_offset_thresholds.size() != config_offset_values.size()) {
228 LOG(ERROR) << "Sensor[" << name
229 << "]'s offset_thresholds size does not match with offset_values size";
230 return false;
231 }
232
233 for (Json::Value::ArrayIndex i = 0; i < config_offset_thresholds.size(); ++i) {
234 float offset_threshold = config_offset_thresholds[i].asFloat();
235 float offset_value = config_offset_values[i].asFloat();
236 if (std::isnan(offset_threshold) || std::isnan(offset_value)) {
237 LOG(ERROR) << "Nan offset_threshold or offset_value unexpected for sensor " << name;
238 return false;
239 }
240
241 if ((i != 0) && (offset_threshold < (*offset_thresholds).back())) {
242 LOG(ERROR) << "offset_thresholds are not in increasing order for sensor " << name;
243 return false;
244 }
245
246 (*offset_thresholds).emplace_back(offset_threshold);
247 (*offset_values).emplace_back(offset_value);
248
249 LOG(INFO) << "Sensor[" << name << "]'s offset_thresholds[" << i
250 << "]: " << (*offset_thresholds)[i] << " offset_values[" << i
251 << "]: " << (*offset_values)[i];
252 }
253
254 return true;
255 }
256
ParseVirtualSensorInfo(const std::string_view name,const Json::Value & sensor,std::unique_ptr<VirtualSensorInfo> * virtual_sensor_info)257 bool ParseVirtualSensorInfo(const std::string_view name, const Json::Value &sensor,
258 std::unique_ptr<VirtualSensorInfo> *virtual_sensor_info) {
259 if (sensor["VirtualSensor"].empty() || !sensor["VirtualSensor"].isBool()) {
260 LOG(INFO) << "Failed to read Sensor[" << name << "]'s VirtualSensor";
261 return true;
262 }
263 bool is_virtual_sensor = sensor["VirtualSensor"].asBool();
264 LOG(INFO) << "Sensor[" << name << "]'s' VirtualSensor: " << is_virtual_sensor;
265 if (!is_virtual_sensor) {
266 return true;
267 }
268 float offset = 0;
269 std::vector<std::string> linked_sensors;
270 std::vector<SensorFusionType> linked_sensors_type;
271 std::vector<std::string> trigger_sensors;
272 std::vector<std::string> coefficients;
273 std::vector<SensorFusionType> coefficients_type;
274 FormulaOption formula = FormulaOption::COUNT_THRESHOLD;
275 std::string vt_estimator_model_file;
276 std::unique_ptr<::thermal::vtestimator::VirtualTempEstimator> vt_estimator;
277 std::string backup_sensor;
278
279 Json::Value values = sensor["Combination"];
280 if (values.size()) {
281 linked_sensors.reserve(values.size());
282 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
283 linked_sensors.emplace_back(values[j].asString());
284 LOG(INFO) << "Sensor[" << name << "]'s Combination[" << j << "]: " << linked_sensors[j];
285 }
286 } else {
287 LOG(ERROR) << "Sensor[" << name << "] has no Combination setting";
288 return false;
289 }
290
291 if (sensor["Formula"].asString().compare("COUNT_THRESHOLD") == 0) {
292 formula = FormulaOption::COUNT_THRESHOLD;
293 } else if (sensor["Formula"].asString().compare("WEIGHTED_AVG") == 0) {
294 formula = FormulaOption::WEIGHTED_AVG;
295 } else if (sensor["Formula"].asString().compare("MAXIMUM") == 0) {
296 formula = FormulaOption::MAXIMUM;
297 } else if (sensor["Formula"].asString().compare("MINIMUM") == 0) {
298 formula = FormulaOption::MINIMUM;
299 } else if (sensor["Formula"].asString().compare("USE_ML_MODEL") == 0) {
300 formula = FormulaOption::USE_ML_MODEL;
301 } else if (sensor["Formula"].asString().compare("USE_LINEAR_MODEL") == 0) {
302 formula = FormulaOption::USE_LINEAR_MODEL;
303 } else {
304 LOG(ERROR) << "Sensor[" << name << "]'s Formula is invalid";
305 return false;
306 }
307
308 values = sensor["CombinationType"];
309 if (!values.size()) {
310 linked_sensors_type.reserve(linked_sensors.size());
311 for (size_t j = 0; j < linked_sensors.size(); ++j) {
312 linked_sensors_type.emplace_back(SensorFusionType::SENSOR);
313 }
314 } else if (values.size() != linked_sensors.size()) {
315 LOG(ERROR) << "Sensor[" << name << "] has invalid CombinationType size";
316 return false;
317 } else {
318 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
319 if (values[j].asString().compare("SENSOR") == 0) {
320 linked_sensors_type.emplace_back(SensorFusionType::SENSOR);
321 } else if (values[j].asString().compare("ODPM") == 0) {
322 linked_sensors_type.emplace_back(SensorFusionType::ODPM);
323 } else if (values[j].asString().compare("CONSTANT") == 0) {
324 linked_sensors_type.emplace_back(SensorFusionType::CONSTANT);
325 } else {
326 LOG(ERROR) << "Sensor[" << name << "] has invalid CombinationType settings "
327 << values[j].asString();
328 return false;
329 }
330 LOG(INFO) << "Sensor[" << name << "]'s CombinationType[" << j
331 << "]: " << linked_sensors_type[j];
332 }
333 }
334
335 values = sensor["Coefficient"];
336 if (values.size()) {
337 coefficients.reserve(values.size());
338 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
339 coefficients.emplace_back(values[j].asString());
340 LOG(INFO) << "Sensor[" << name << "]'s coefficient[" << j << "]: " << coefficients[j];
341 }
342 } else if ((formula != FormulaOption::USE_ML_MODEL)) {
343 LOG(ERROR) << "Sensor[" << name << "] has no Coefficient setting";
344 return false;
345 }
346 if ((linked_sensors.size() != coefficients.size()) &&
347 (formula != FormulaOption::USE_ML_MODEL) && (formula != FormulaOption::USE_LINEAR_MODEL)) {
348 LOG(ERROR) << "Sensor[" << name << "] has invalid Coefficient size";
349 return false;
350 }
351
352 values = sensor["CoefficientType"];
353 if (!values.size()) {
354 coefficients_type.reserve(linked_sensors.size());
355 for (size_t j = 0; j < linked_sensors.size(); ++j) {
356 coefficients_type.emplace_back(SensorFusionType::CONSTANT);
357 }
358 } else if (values.size() != coefficients.size()) {
359 LOG(ERROR) << "Sensor[" << name << "] has invalid coefficient type size";
360 return false;
361 } else {
362 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
363 if (values[j].asString().compare("CONSTANT") == 0) {
364 coefficients_type.emplace_back(SensorFusionType::CONSTANT);
365 } else if (values[j].asString().compare("SENSOR") == 0) {
366 coefficients_type.emplace_back(SensorFusionType::SENSOR);
367 } else if (values[j].asString().compare("ODPM") == 0) {
368 coefficients_type.emplace_back(SensorFusionType::ODPM);
369 } else {
370 LOG(ERROR) << "Sensor[" << name << "] has invalid coefficient options "
371 << values[j].asString();
372 return false;
373 }
374 LOG(INFO) << "Sensor[" << name << "]'s coefficient type[" << j
375 << "]: " << coefficients_type[j];
376 }
377 }
378
379 if (linked_sensors.size() != coefficients_type.size()) {
380 LOG(ERROR) << "Sensor[" << name
381 << "]'s combination size is not matched with coefficient type size";
382 return false;
383 }
384
385 if (!sensor["Offset"].empty()) {
386 offset = sensor["Offset"].asFloat();
387 }
388
389 if (!sensor["BackupSensor"].empty()) {
390 backup_sensor = sensor["BackupSensor"].asString();
391 }
392
393 values = sensor["TriggerSensor"];
394 if (!values.empty()) {
395 if (values.isString()) {
396 trigger_sensors.emplace_back(values.asString());
397 LOG(INFO) << "Sensor[" << name << "]'s TriggerSensor: " << values.asString();
398 } else if (values.size()) {
399 trigger_sensors.reserve(values.size());
400 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
401 if (!values[j].isString()) {
402 LOG(ERROR) << name << " TriggerSensor should be an array of string";
403 return false;
404 }
405 trigger_sensors.emplace_back(values[j].asString());
406 LOG(INFO) << "Sensor[" << name << "]'s TriggerSensor[" << j
407 << "]: " << trigger_sensors[j];
408 }
409 } else {
410 LOG(ERROR) << "Sensor[" << name << "]'s TriggerSensor should be a string";
411 return false;
412 }
413 }
414
415 if (formula == FormulaOption::USE_ML_MODEL) {
416 ::thermal::vtestimator::VtEstimationInitData init_data(::thermal::vtestimator::kUseMLModel);
417 if (sensor["ModelPath"].empty()) {
418 LOG(ERROR) << "Sensor[" << name << "] has no ModelPath";
419 return false;
420 }
421
422 if (!linked_sensors.size()) {
423 LOG(ERROR) << "Sensor[" << name << "] uses USE_ML_MODEL and has zero linked_sensors";
424 return false;
425 }
426
427 vt_estimator = std::make_unique<::thermal::vtestimator::VirtualTempEstimator>(
428 name, ::thermal::vtestimator::kUseMLModel, linked_sensors.size());
429 if (!vt_estimator) {
430 LOG(ERROR) << "Failed to create vt estimator for Sensor[" << name
431 << "] with linked sensor size : " << linked_sensors.size();
432 return false;
433 }
434
435 vt_estimator_model_file = "vendor/etc/" + sensor["ModelPath"].asString();
436 init_data.ml_model_init_data.model_path = vt_estimator_model_file;
437
438 if (!ParseOffsetThresholds(name, sensor, &init_data.ml_model_init_data.offset_thresholds,
439 &init_data.ml_model_init_data.offset_values)) {
440 LOG(ERROR) << "Failed to parse offset thresholds and values for Sensor[" << name << "]";
441 return false;
442 }
443
444 if (!sensor["PreviousSampleCount"].empty()) {
445 init_data.ml_model_init_data.use_prev_samples = true;
446 init_data.ml_model_init_data.prev_samples_order = sensor["PreviousSampleCount"].asInt();
447 LOG(INFO) << "Sensor[" << name << "] takes "
448 << init_data.ml_model_init_data.prev_samples_order << " historic samples";
449 }
450
451 if (!sensor["OutputLabelCount"].empty()) {
452 init_data.ml_model_init_data.output_label_count = sensor["OutputLabelCount"].asInt();
453 LOG(INFO) << "Sensor[" << name << "] outputs "
454 << init_data.ml_model_init_data.output_label_count << " labels";
455 }
456
457 if (!sensor["PredictHotSpotCount"].empty()) {
458 init_data.ml_model_init_data.num_hot_spots = sensor["PredictHotSpotCount"].asInt();
459 LOG(INFO) << "Sensor[" << name << "] predicts temperature at "
460 << init_data.ml_model_init_data.num_hot_spots << " hot spots";
461 }
462
463 if (sensor["ValidateInput"].asBool()) {
464 init_data.ml_model_init_data.enable_input_validation = true;
465 LOG(INFO) << "Sensor[" << name << "] enable input validation.";
466 }
467
468 if (sensor["SupportUnderSampling"].asBool()) {
469 init_data.ml_model_init_data.support_under_sampling = true;
470 LOG(INFO) << "Sensor[" << name << "] supports under sampling estimation.";
471 }
472
473 ::thermal::vtestimator::VtEstimatorStatus ret = vt_estimator->Initialize(init_data);
474 if (ret != ::thermal::vtestimator::kVtEstimatorOk) {
475 LOG(ERROR) << "Failed to initialize vt estimator for Sensor[" << name
476 << "] with ModelPath: " << vt_estimator_model_file
477 << " with ret code : " << ret;
478 return false;
479 }
480
481 LOG(INFO) << "Successfully created vt_estimator for Sensor[" << name
482 << "] with input samples: " << linked_sensors.size();
483
484 } else if (formula == FormulaOption::USE_LINEAR_MODEL) {
485 ::thermal::vtestimator::VtEstimationInitData init_data(
486 ::thermal::vtestimator::kUseLinearModel);
487
488 if ((!linked_sensors.size()) || (linked_sensors.size() > coefficients.size())) {
489 LOG(ERROR) << "Sensor[" << name
490 << "] uses USE_LINEAR_MODEL and has invalid linked_sensors size["
491 << linked_sensors.size() << "] or coefficients size[" << coefficients.size()
492 << "]";
493 return false;
494 }
495
496 vt_estimator = std::make_unique<::thermal::vtestimator::VirtualTempEstimator>(
497 name, ::thermal::vtestimator::kUseLinearModel, linked_sensors.size());
498 if (!vt_estimator) {
499 LOG(ERROR) << "Failed to create vt estimator for Sensor[" << name
500 << "] with linked sensor size : " << linked_sensors.size();
501 return false;
502 }
503
504 init_data.linear_model_init_data.prev_samples_order =
505 coefficients.size() / linked_sensors.size();
506
507 if (!ParseOffsetThresholds(name, sensor,
508 &init_data.linear_model_init_data.offset_thresholds,
509 &init_data.linear_model_init_data.offset_values)) {
510 LOG(ERROR) << "Failed to parse offset thresholds and values for Sensor[" << name << "]";
511 return false;
512 }
513
514 for (size_t i = 0; i < coefficients.size(); ++i) {
515 float coefficient = getFloatFromValue(coefficients[i]);
516 if (std::isnan(coefficient)) {
517 LOG(ERROR) << "Nan coefficient unexpected for sensor " << name;
518 return false;
519 }
520 init_data.linear_model_init_data.coefficients.emplace_back(coefficient);
521 }
522 if (coefficients.size() > linked_sensors.size()) {
523 init_data.linear_model_init_data.use_prev_samples = true;
524 }
525
526 ::thermal::vtestimator::VtEstimatorStatus ret = vt_estimator->Initialize(init_data);
527 if (ret != ::thermal::vtestimator::kVtEstimatorOk) {
528 LOG(ERROR) << "Failed to initialize vt estimator for Sensor[" << name
529 << "] with ret code : " << ret;
530 return false;
531 }
532
533 LOG(INFO) << "Successfully created vt_estimator for Sensor[" << name
534 << "] with input samples: " << linked_sensors.size();
535 }
536
537 virtual_sensor_info->reset(
538 new VirtualSensorInfo{linked_sensors, linked_sensors_type, coefficients,
539 coefficients_type, offset, trigger_sensors, formula,
540 vt_estimator_model_file, std::move(vt_estimator), backup_sensor});
541 return true;
542 }
543
ParsePredictorInfo(const std::string_view name,const Json::Value & sensor,std::unique_ptr<PredictorInfo> * predictor_info)544 bool ParsePredictorInfo(const std::string_view name, const Json::Value &sensor,
545 std::unique_ptr<PredictorInfo> *predictor_info) {
546 Json::Value predictor = sensor["PredictorInfo"];
547 if (predictor.empty()) {
548 return true;
549 }
550
551 LOG(INFO) << "Start to parse Sensor[" << name << "]'s PredictorInfo";
552 if (predictor["Sensor"].empty()) {
553 LOG(ERROR) << "Failed to parse Sensor [" << name << "]'s PredictorInfo";
554 return false;
555 }
556
557 std::string predict_sensor;
558 bool support_pid_compensation = false;
559 std::vector<float> prediction_weights;
560 ThrottlingArray k_p_compensate;
561 predict_sensor = predictor["Sensor"].asString();
562 LOG(INFO) << "Sensor [" << name << "]'s predictor name is " << predict_sensor;
563 // parse pid compensation configuration
564 if ((!predictor["PredictionWeight"].empty()) && (!predictor["KPCompensate"].empty())) {
565 support_pid_compensation = true;
566 if (!predictor["PredictionWeight"].size()) {
567 LOG(ERROR) << "Failed to parse PredictionWeight";
568 return false;
569 }
570 prediction_weights.reserve(predictor["PredictionWeight"].size());
571 for (Json::Value::ArrayIndex i = 0; i < predictor["PredictionWeight"].size(); ++i) {
572 float weight = predictor["PredictionWeight"][i].asFloat();
573 if (std::isnan(weight)) {
574 LOG(ERROR) << "Unexpected NAN prediction weight for sensor [" << name << "]";
575 }
576 prediction_weights.emplace_back(weight);
577 LOG(INFO) << "Sensor[" << name << "]'s prediction weights [" << i << "]: " << weight;
578 }
579 if (!getFloatFromJsonValues(predictor["KPCompensate"], &k_p_compensate, false, false)) {
580 LOG(ERROR) << "Failed to parse KPCompensate";
581 return false;
582 }
583 }
584
585 LOG(INFO) << "Successfully created PredictorInfo for Sensor[" << name << "]";
586 predictor_info->reset(new PredictorInfo{predict_sensor, support_pid_compensation,
587 prediction_weights, k_p_compensate});
588
589 return true;
590 }
591
ParseBindedCdevInfo(const Json::Value & values,std::unordered_map<std::string,BindedCdevInfo> * binded_cdev_info_map,const bool support_pid,bool * support_hard_limit,const std::unordered_map<std::string,std::vector<int>> & scaling_frequency_map)592 bool ParseBindedCdevInfo(
593 const Json::Value &values,
594 std::unordered_map<std::string, BindedCdevInfo> *binded_cdev_info_map,
595 const bool support_pid, bool *support_hard_limit,
596 const std::unordered_map<std::string, std::vector<int>> &scaling_frequency_map) {
597 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
598 Json::Value sub_values;
599 const std::string &cdev_name = values[j]["CdevRequest"].asString();
600 ThrottlingArray cdev_weight_for_pid;
601 cdev_weight_for_pid.fill(NAN);
602 CdevArray cdev_ceiling;
603 cdev_ceiling.fill(std::numeric_limits<int>::max());
604 int max_release_step = std::numeric_limits<int>::max();
605 int max_throttle_step = std::numeric_limits<int>::max();
606 if (support_pid) {
607 if (!values[j]["CdevWeightForPID"].empty()) {
608 LOG(INFO) << "Star to parse " << cdev_name << "'s CdevWeightForPID";
609 if (!getFloatFromJsonValues(values[j]["CdevWeightForPID"], &cdev_weight_for_pid,
610 false, false)) {
611 LOG(ERROR) << "Failed to parse CdevWeightForPID";
612 binded_cdev_info_map->clear();
613 return false;
614 }
615 }
616
617 if (!values[j]["CdevCeiling"].empty() && !values[j]["CdevCeilingFrequency"].empty()) {
618 LOG(ERROR) << "Both CdevCeiling and CdevCeilingFrequency are configured for "
619 << cdev_name << ", please remove one of them";
620 binded_cdev_info_map->clear();
621 return false;
622 }
623
624 if (!values[j]["CdevCeiling"].empty()) {
625 LOG(INFO) << "Start to parse CdevCeiling: " << cdev_name;
626 if (!getIntFromJsonValues(values[j]["CdevCeiling"], &cdev_ceiling, false, false)) {
627 LOG(ERROR) << "Failed to parse CdevCeiling for " << cdev_name;
628 binded_cdev_info_map->clear();
629 return false;
630 }
631 }
632
633 if (!values[j]["CdevCeilingFrequency"].empty()) {
634 LOG(INFO) << "Start to parse CdevCeilingFrequency: " << cdev_name;
635 CdevArray cdev_ceiling_frequency;
636 if (scaling_frequency_map.find(cdev_name) == scaling_frequency_map.end()) {
637 LOG(ERROR) << "Scaling frequency path is not found in config for " << cdev_name;
638 binded_cdev_info_map->clear();
639 return false;
640 }
641 const std::vector<int> &cdev_scaling_frequency =
642 scaling_frequency_map.find(cdev_name)->second;
643 if (!getIntFromJsonValues(values[j]["CdevCeilingFrequency"],
644 &cdev_ceiling_frequency, false, true)) {
645 LOG(ERROR) << "Failed to parse CdevCeilingFrequency";
646 binded_cdev_info_map->clear();
647 return false;
648 }
649
650 LOG(INFO) << "Start to search CdevCeiling based on frequency: " << cdev_name;
651 // Find the max frequency level that is lower than or equal to CdevCeilingFrequency
652 // value
653 for (size_t cdev_scaling_idx = 0, cdev_ceiling_idx = 0;
654 cdev_scaling_idx < cdev_scaling_frequency.size() &&
655 cdev_ceiling_idx < cdev_ceiling.size();) {
656 if (cdev_scaling_frequency.at(cdev_scaling_idx) <=
657 cdev_ceiling_frequency.at(cdev_ceiling_idx)) {
658 cdev_ceiling[cdev_ceiling_idx] = cdev_scaling_idx;
659 LOG(INFO) << "[" << cdev_ceiling_idx
660 << "]: " << cdev_ceiling[cdev_ceiling_idx];
661 cdev_ceiling_idx += 1;
662 } else {
663 cdev_scaling_idx += 1;
664 }
665 }
666 }
667
668 if (!values[j]["MaxReleaseStep"].empty()) {
669 max_release_step = getIntFromValue(values[j]["MaxReleaseStep"]);
670 if (max_release_step < 0) {
671 LOG(ERROR) << cdev_name << " MaxReleaseStep: " << max_release_step;
672 binded_cdev_info_map->clear();
673 return false;
674 } else {
675 LOG(INFO) << cdev_name << " MaxReleaseStep: " << max_release_step;
676 }
677 }
678 if (!values[j]["MaxThrottleStep"].empty()) {
679 max_throttle_step = getIntFromValue(values[j]["MaxThrottleStep"]);
680 if (max_throttle_step < 0) {
681 LOG(ERROR) << cdev_name << " MaxThrottleStep: " << max_throttle_step;
682 binded_cdev_info_map->clear();
683 return false;
684 } else {
685 LOG(INFO) << cdev_name << " MaxThrottleStep: " << max_throttle_step;
686 }
687 }
688 }
689 CdevArray limit_info;
690 limit_info.fill(0);
691 ThrottlingArray power_thresholds;
692 power_thresholds.fill(NAN);
693 ReleaseLogic release_logic = ReleaseLogic::NONE;
694
695 if (!values[j]["LimitInfo"].empty() && !values[j]["LimitInfoFrequency"].empty()) {
696 LOG(ERROR) << "Both LimitInfo and LimitInfoFrequency are configured for " << cdev_name
697 << ", please remove one of them";
698 binded_cdev_info_map->clear();
699 return false;
700 }
701
702 if (!values[j]["LimitInfo"].empty()) {
703 LOG(INFO) << "Start to parse LimitInfo: " << cdev_name;
704 if (!getIntFromJsonValues(values[j]["LimitInfo"], &limit_info, false, false)) {
705 LOG(ERROR) << "Failed to parse LimitInfo";
706 binded_cdev_info_map->clear();
707 return false;
708 }
709 *support_hard_limit = true;
710 }
711
712 if (!values[j]["LimitInfoFrequency"].empty()) {
713 LOG(INFO) << "Start to parse LimitInfoFrequency: " << cdev_name;
714 CdevArray limit_info_frequency;
715 if (scaling_frequency_map.find(cdev_name) == scaling_frequency_map.end()) {
716 LOG(ERROR) << "Scaling frequency path is not found for " << cdev_name;
717 binded_cdev_info_map->clear();
718 return false;
719 }
720
721 const std::vector<int> &cdev_scaling_frequency =
722 scaling_frequency_map.find(cdev_name)->second;
723 if (!getIntFromJsonValues(values[j]["LimitInfoFrequency"], &limit_info_frequency, false,
724 true)) {
725 LOG(ERROR) << "Failed to parse LimitInfoFrequency for " << cdev_name;
726 binded_cdev_info_map->clear();
727 return false;
728 }
729
730 LOG(INFO) << "Start to search LimitInfo based on frequency: " << cdev_name;
731 // Find the max frequency level that is lower than or equal to imitInfoFrequency value
732 for (size_t cdev_scaling_idx = 0, limit_info_idx = 0;
733 cdev_scaling_idx < cdev_scaling_frequency.size() &&
734 limit_info_idx < limit_info.size();) {
735 if (cdev_scaling_frequency.at(cdev_scaling_idx) <=
736 limit_info_frequency.at(limit_info_idx)) {
737 limit_info[limit_info_idx] = cdev_scaling_idx;
738 LOG(INFO) << "[" << limit_info_idx << "]: " << limit_info[limit_info_idx];
739 limit_info_idx += 1;
740 } else {
741 cdev_scaling_idx += 1;
742 }
743 }
744 *support_hard_limit = true;
745 }
746 // Parse linked power info
747 std::string power_rail;
748 bool high_power_check = false;
749 bool throttling_with_power_link = false;
750 bool enabled = true;
751 CdevArray cdev_floor_with_power_link;
752 cdev_floor_with_power_link.fill(0);
753
754 const bool power_link_disabled =
755 ::android::base::GetBoolProperty(kPowerLinkDisabledProperty.data(), false);
756 if (!power_link_disabled) {
757 power_rail = values[j]["BindedPowerRail"].asString();
758
759 if (values[j]["HighPowerCheck"].asBool()) {
760 high_power_check = true;
761 }
762 LOG(INFO) << "Highpowercheck: " << std::boolalpha << high_power_check;
763
764 if (values[j]["ThrottlingWithPowerLink"].asBool()) {
765 throttling_with_power_link = true;
766 }
767 LOG(INFO) << "ThrottlingwithPowerLink: " << std::boolalpha
768 << throttling_with_power_link;
769
770 sub_values = values[j]["CdevFloorWithPowerLink"];
771 if (sub_values.size()) {
772 LOG(INFO) << "Start to parse " << cdev_name << "'s CdevFloorWithPowerLink";
773 if (!getIntFromJsonValues(sub_values, &cdev_floor_with_power_link, false, false)) {
774 LOG(ERROR) << "Failed to parse CdevFloor";
775 binded_cdev_info_map->clear();
776 return false;
777 }
778 }
779 sub_values = values[j]["PowerThreshold"];
780 if (sub_values.size()) {
781 LOG(INFO) << "Start to parse " << cdev_name << "'s PowerThreshold";
782 if (!getFloatFromJsonValues(sub_values, &power_thresholds, false, false)) {
783 LOG(ERROR) << "Failed to parse power thresholds";
784 binded_cdev_info_map->clear();
785 return false;
786 }
787 if (values[j]["ReleaseLogic"].asString() == "INCREASE") {
788 release_logic = ReleaseLogic::INCREASE;
789 LOG(INFO) << "Release logic: INCREASE";
790 } else if (values[j]["ReleaseLogic"].asString() == "DECREASE") {
791 release_logic = ReleaseLogic::DECREASE;
792 LOG(INFO) << "Release logic: DECREASE";
793 } else if (values[j]["ReleaseLogic"].asString() == "STEPWISE") {
794 release_logic = ReleaseLogic::STEPWISE;
795 LOG(INFO) << "Release logic: STEPWISE";
796 } else if (values[j]["ReleaseLogic"].asString() == "RELEASE_TO_FLOOR") {
797 release_logic = ReleaseLogic::RELEASE_TO_FLOOR;
798 LOG(INFO) << "Release logic: RELEASE_TO_FLOOR";
799 } else {
800 LOG(ERROR) << "Release logic is invalid";
801 binded_cdev_info_map->clear();
802 return false;
803 }
804 }
805 }
806 if (values[j]["Disabled"].asBool()) {
807 enabled = false;
808 }
809
810 (*binded_cdev_info_map)[cdev_name] = {
811 .limit_info = limit_info,
812 .power_thresholds = power_thresholds,
813 .release_logic = release_logic,
814 .cdev_weight_for_pid = cdev_weight_for_pid,
815 .cdev_ceiling = cdev_ceiling,
816 .max_release_step = max_release_step,
817 .max_throttle_step = max_throttle_step,
818 .cdev_floor_with_power_link = cdev_floor_with_power_link,
819 .power_rail = power_rail,
820 .high_power_check = high_power_check,
821 .throttling_with_power_link = throttling_with_power_link,
822 .enabled = enabled,
823 };
824 }
825 return true;
826 }
827
ParseSensorThrottlingInfo(const std::string_view name,const Json::Value & sensor,bool * support_throttling,std::shared_ptr<ThrottlingInfo> * throttling_info,const std::unordered_map<std::string,std::vector<int>> & scaling_frequency_map)828 bool ParseSensorThrottlingInfo(
829 const std::string_view name, const Json::Value &sensor, bool *support_throttling,
830 std::shared_ptr<ThrottlingInfo> *throttling_info,
831 const std::unordered_map<std::string, std::vector<int>> &scaling_frequency_map) {
832 std::array<float, kThrottlingSeverityCount> k_po;
833 k_po.fill(0.0);
834 std::array<float, kThrottlingSeverityCount> k_pu;
835 k_pu.fill(0.0);
836 std::array<float, kThrottlingSeverityCount> k_i;
837 k_i.fill(0.0);
838 std::array<float, kThrottlingSeverityCount> k_d;
839 k_d.fill(0.0);
840 std::array<float, kThrottlingSeverityCount> i_max;
841 i_max.fill(NAN);
842 std::array<float, kThrottlingSeverityCount> max_alloc_power;
843 max_alloc_power.fill(NAN);
844 std::array<float, kThrottlingSeverityCount> min_alloc_power;
845 min_alloc_power.fill(NAN);
846 std::array<float, kThrottlingSeverityCount> s_power;
847 s_power.fill(NAN);
848 std::array<float, kThrottlingSeverityCount> i_cutoff;
849 i_cutoff.fill(NAN);
850 float i_default = 0.0;
851 float i_default_pct = NAN;
852 int tran_cycle = 0;
853 bool support_pid = false;
854 bool support_hard_limit = false;
855
856 // Parse PID parameters
857 if (!sensor["PIDInfo"].empty()) {
858 LOG(INFO) << "Start to parse"
859 << " Sensor[" << name << "]'s K_Po";
860 if (sensor["PIDInfo"]["K_Po"].empty() ||
861 !getFloatFromJsonValues(sensor["PIDInfo"]["K_Po"], &k_po, false, false)) {
862 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_Po";
863 return false;
864 }
865 LOG(INFO) << "Start to parse"
866 << " Sensor[" << name << "]'s K_Pu";
867 if (sensor["PIDInfo"]["K_Pu"].empty() ||
868 !getFloatFromJsonValues(sensor["PIDInfo"]["K_Pu"], &k_pu, false, false)) {
869 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_Pu";
870 return false;
871 }
872 LOG(INFO) << "Start to parse"
873 << " Sensor[" << name << "]'s K_I";
874 if (sensor["PIDInfo"]["K_I"].empty() ||
875 !getFloatFromJsonValues(sensor["PIDInfo"]["K_I"], &k_i, false, false)) {
876 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_I";
877 return false;
878 }
879 LOG(INFO) << "Start to parse"
880 << " Sensor[" << name << "]'s K_D";
881 if (sensor["PIDInfo"]["K_D"].empty() ||
882 !getFloatFromJsonValues(sensor["PIDInfo"]["K_D"], &k_d, false, false)) {
883 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_D";
884 return false;
885 }
886 LOG(INFO) << "Start to parse"
887 << " Sensor[" << name << "]'s I_Max";
888 if (sensor["PIDInfo"]["I_Max"].empty() ||
889 !getFloatFromJsonValues(sensor["PIDInfo"]["I_Max"], &i_max, false, false)) {
890 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse I_Max";
891 return false;
892 }
893 LOG(INFO) << "Start to parse"
894 << " Sensor[" << name << "]'s MaxAllocPower";
895 if (sensor["PIDInfo"]["MaxAllocPower"].empty() ||
896 !getFloatFromJsonValues(sensor["PIDInfo"]["MaxAllocPower"], &max_alloc_power, false,
897 true)) {
898 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse MaxAllocPower";
899 return false;
900 }
901 LOG(INFO) << "Start to parse"
902 << " Sensor[" << name << "]'s MinAllocPower";
903 if (sensor["PIDInfo"]["MinAllocPower"].empty() ||
904 !getFloatFromJsonValues(sensor["PIDInfo"]["MinAllocPower"], &min_alloc_power, false,
905 true)) {
906 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse MinAllocPower";
907 return false;
908 }
909 LOG(INFO) << "Start to parse Sensor[" << name << "]'s S_Power";
910 if (sensor["PIDInfo"]["S_Power"].empty() ||
911 !getFloatFromJsonValues(sensor["PIDInfo"]["S_Power"], &s_power, false, true)) {
912 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse S_Power";
913 return false;
914 }
915 LOG(INFO) << "Start to parse Sensor[" << name << "]'s I_Cutoff";
916 if (sensor["PIDInfo"]["I_Cutoff"].empty() ||
917 !getFloatFromJsonValues(sensor["PIDInfo"]["I_Cutoff"], &i_cutoff, false, false)) {
918 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse I_Cutoff";
919 return false;
920 }
921
922 if (!sensor["PIDInfo"]["I_Default"].empty() &&
923 !sensor["PIDInfo"]["I_Default_Pct"].empty()) {
924 LOG(ERROR) << "I_Default and I_Default_P cannot be applied together";
925 return false;
926 }
927
928 if (!sensor["PIDInfo"]["I_Default"].empty()) {
929 i_default = getFloatFromValue(sensor["PIDInfo"]["I_Default"]);
930 LOG(INFO) << "Sensor[" << name << "]'s I_Default: " << i_default;
931 } else if (!sensor["PIDInfo"]["I_Default_Pct"].empty()) {
932 i_default_pct = getFloatFromValue(sensor["PIDInfo"]["I_Default_Pct"]);
933 LOG(INFO) << "Sensor[" << name << "]'s I_Default_Pct: " << i_default_pct;
934 }
935 tran_cycle = getFloatFromValue(sensor["PIDInfo"]["TranCycle"]);
936 LOG(INFO) << "Sensor[" << name << "]'s TranCycle: " << tran_cycle;
937
938 // Confirm we have at least one valid PID combination
939 bool valid_pid_combination = false;
940 for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
941 if (!std::isnan(s_power[j])) {
942 if (std::isnan(k_po[j]) || std::isnan(k_pu[j]) || std::isnan(k_i[j]) ||
943 std::isnan(k_d[j]) || std::isnan(i_max[j]) || std::isnan(max_alloc_power[j]) ||
944 std::isnan(min_alloc_power[j]) || std::isnan(i_cutoff[j])) {
945 valid_pid_combination = false;
946 break;
947 } else {
948 valid_pid_combination = true;
949 }
950 }
951 }
952 if (!valid_pid_combination) {
953 LOG(ERROR) << "Sensor[" << name << "]: Invalid PID parameters combinations";
954 return false;
955 } else {
956 support_pid = true;
957 }
958 }
959
960 // Parse binded cooling device
961 std::unordered_map<std::string, BindedCdevInfo> binded_cdev_info_map;
962 if (!ParseBindedCdevInfo(sensor["BindedCdevInfo"], &binded_cdev_info_map, support_pid,
963 &support_hard_limit, scaling_frequency_map)) {
964 LOG(ERROR) << "Sensor[" << name << "]: failed to parse BindedCdevInfo";
965 return false;
966 }
967
968 Json::Value values;
969 ProfileMap profile_map;
970 values = sensor["Profile"];
971 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
972 Json::Value sub_values;
973 const std::string &mode = values[j]["Mode"].asString();
974 std::unordered_map<std::string, BindedCdevInfo> binded_cdev_info_map_profile;
975 if (!ParseBindedCdevInfo(values[j]["BindedCdevInfo"], &binded_cdev_info_map_profile,
976 support_pid, &support_hard_limit, scaling_frequency_map)) {
977 LOG(ERROR) << "Sensor[" << name << " failed to parse BindedCdevInfo profile";
978 }
979 // Check if the binded_cdev_info_map_profile is valid
980 if (binded_cdev_info_map.size() != binded_cdev_info_map_profile.size()) {
981 LOG(ERROR) << "Sensor[" << name << "]:'s profile map size should not be changed";
982 return false;
983 } else {
984 for (const auto &binded_cdev_info_pair : binded_cdev_info_map_profile) {
985 if (binded_cdev_info_map.count(binded_cdev_info_pair.first)) {
986 if (binded_cdev_info_pair.second.power_rail !=
987 binded_cdev_info_map.at(binded_cdev_info_pair.first).power_rail) {
988 LOG(ERROR) << "Sensor[" << name << "]:'s profile " << mode << " binded "
989 << binded_cdev_info_pair.first
990 << "'s power rail is not included in default rules";
991 return false;
992 } else {
993 LOG(INFO) << "Sensor[" << name << "]:'s profile " << mode
994 << " is parsed successfully";
995 }
996 } else {
997 LOG(ERROR) << "Sensor[" << name << "]'s profile " << mode << " binded "
998 << binded_cdev_info_pair.first
999 << " is not included in default rules";
1000 return false;
1001 }
1002 }
1003 }
1004 profile_map[mode] = binded_cdev_info_map_profile;
1005 }
1006
1007 std::unordered_map<std::string, ThrottlingArray> excluded_power_info_map;
1008 values = sensor["ExcludedPowerInfo"];
1009 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
1010 Json::Value sub_values;
1011 const std::string &power_rail = values[j]["PowerRail"].asString();
1012 if (power_rail.empty()) {
1013 LOG(ERROR) << "Sensor[" << name << "] failed to parse excluded PowerRail";
1014 return false;
1015 }
1016 ThrottlingArray power_weight;
1017 power_weight.fill(1);
1018 if (!values[j]["PowerWeight"].empty()) {
1019 LOG(INFO) << "Sensor[" << name << "]: Start to parse " << power_rail
1020 << "'s PowerWeight";
1021 if (!getFloatFromJsonValues(values[j]["PowerWeight"], &power_weight, false, false)) {
1022 LOG(ERROR) << "Failed to parse PowerWeight";
1023 return false;
1024 }
1025 }
1026 excluded_power_info_map[power_rail] = power_weight;
1027 }
1028 throttling_info->reset(new ThrottlingInfo{k_po, k_pu, k_i, k_d, i_max, max_alloc_power,
1029 min_alloc_power, s_power, i_cutoff, i_default,
1030 i_default_pct, tran_cycle, excluded_power_info_map,
1031 binded_cdev_info_map, profile_map});
1032 *support_throttling = support_pid | support_hard_limit;
1033 return true;
1034 }
1035
ParseSensorInfo(const Json::Value & config,std::unordered_map<std::string,SensorInfo> * sensors_parsed)1036 bool ParseSensorInfo(const Json::Value &config,
1037 std::unordered_map<std::string, SensorInfo> *sensors_parsed) {
1038 Json::Value sensors = config["Sensors"];
1039 Json::Value cdevs = config["CoolingDevices"];
1040 std::unordered_map<std::string, std::vector<int>> scaling_frequency_map;
1041
1042 LOG(INFO) << "Start reading ScalingAvailableFrequenciesPath from config";
1043 for (Json::Value::ArrayIndex i = 0; i < cdevs.size(); ++i) {
1044 if (cdevs[i]["ScalingAvailableFrequenciesPath"].empty()) {
1045 continue;
1046 }
1047
1048 const std::string &path = cdevs[i]["ScalingAvailableFrequenciesPath"].asString();
1049 const std::string &name = cdevs[i]["Name"].asString();
1050 LOG(INFO) << "Cdev[" << name << "]'s scaling frequency path: " << path;
1051 std::string scaling_frequency_str;
1052 if (::android::base::ReadFileToString(path, &scaling_frequency_str)) {
1053 std::istringstream frequencies(scaling_frequency_str);
1054 int frequency;
1055 while (frequencies >> frequency) {
1056 LOG(INFO) << "Cdev[" << name << "]'s available frequency: " << frequency;
1057 scaling_frequency_map[name].push_back(frequency);
1058 }
1059
1060 // Reverse the vector if it starts from small value
1061 if (scaling_frequency_map[name].front() < scaling_frequency_map[name].back()) {
1062 std::reverse(scaling_frequency_map[name].begin(),
1063 scaling_frequency_map[name].end());
1064 }
1065
1066 // Make sure the scaling frequencies strictly decreasing
1067 if (std::adjacent_find(scaling_frequency_map[name].begin(),
1068 scaling_frequency_map[name].end(),
1069 std::less_equal<int>()) != scaling_frequency_map[name].end()) {
1070 LOG(ERROR) << "Cdev[" << name << "]'s scaling frequencies is not monotonic";
1071 sensors_parsed->clear();
1072 return false;
1073 }
1074 } else {
1075 LOG(ERROR) << "Cdev[" << name << "]'s scaling frequency path is invalid.";
1076 sensors_parsed->clear();
1077 return false;
1078 }
1079 }
1080
1081 std::size_t total_parsed = 0;
1082 std::unordered_set<std::string> sensors_name_parsed;
1083
1084 for (Json::Value::ArrayIndex i = 0; i < sensors.size(); ++i) {
1085 const std::string &name = sensors[i]["Name"].asString();
1086 LOG(INFO) << "Sensor[" << i << "]'s Name: " << name;
1087 if (name.empty()) {
1088 LOG(ERROR) << "Failed to read Sensor[" << i << "]'s Name";
1089 sensors_parsed->clear();
1090 return false;
1091 }
1092
1093 auto result = sensors_name_parsed.insert(name);
1094 if (!result.second) {
1095 LOG(ERROR) << "Duplicate Sensor[" << i << "]'s Name";
1096 sensors_parsed->clear();
1097 return false;
1098 }
1099
1100 std::string sensor_type_str = sensors[i]["Type"].asString();
1101 LOG(INFO) << "Sensor[" << name << "]'s Type: " << sensor_type_str;
1102 TemperatureType sensor_type;
1103
1104 if (!getTypeFromString(sensor_type_str, &sensor_type)) {
1105 LOG(ERROR) << "Invalid Sensor[" << name << "]'s Type: " << sensor_type_str;
1106 sensors_parsed->clear();
1107 return false;
1108 }
1109
1110 bool send_cb = false;
1111 if (!sensors[i]["Monitor"].empty() && sensors[i]["Monitor"].isBool()) {
1112 send_cb = sensors[i]["Monitor"].asBool();
1113 } else if (!sensors[i]["SendCallback"].empty() && sensors[i]["SendCallback"].isBool()) {
1114 send_cb = sensors[i]["SendCallback"].asBool();
1115 }
1116 LOG(INFO) << "Sensor[" << name << "]'s SendCallback: " << std::boolalpha << send_cb
1117 << std::noboolalpha;
1118
1119 bool send_powerhint = false;
1120 if (sensors[i]["SendPowerHint"].empty() || !sensors[i]["SendPowerHint"].isBool()) {
1121 LOG(INFO) << "Failed to read Sensor[" << name << "]'s SendPowerHint, set to 'false'";
1122 } else if (sensors[i]["SendPowerHint"].asBool()) {
1123 send_powerhint = true;
1124 }
1125 LOG(INFO) << "Sensor[" << name << "]'s SendPowerHint: " << std::boolalpha << send_powerhint
1126 << std::noboolalpha;
1127
1128 bool is_hidden = false;
1129 if (sensors[i]["Hidden"].empty() || !sensors[i]["Hidden"].isBool()) {
1130 LOG(INFO) << "Failed to read Sensor[" << name << "]'s Hidden, set to 'false'";
1131 } else if (sensors[i]["Hidden"].asBool()) {
1132 is_hidden = true;
1133 }
1134 LOG(INFO) << "Sensor[" << name << "]'s Hidden: " << std::boolalpha << is_hidden
1135 << std::noboolalpha;
1136
1137 std::array<float, kThrottlingSeverityCount> hot_thresholds;
1138 hot_thresholds.fill(NAN);
1139 std::array<float, kThrottlingSeverityCount> cold_thresholds;
1140 cold_thresholds.fill(NAN);
1141 std::array<float, kThrottlingSeverityCount> hot_hysteresis;
1142 hot_hysteresis.fill(0.0);
1143 std::array<float, kThrottlingSeverityCount> cold_hysteresis;
1144 cold_hysteresis.fill(0.0);
1145
1146 Json::Value values = sensors[i]["HotThreshold"];
1147 if (!values.size()) {
1148 LOG(INFO) << "Sensor[" << name << "]'s HotThreshold, default all to NAN";
1149 } else if (values.size() != kThrottlingSeverityCount) {
1150 LOG(ERROR) << "Invalid Sensor[" << name << "]'s HotThreshold count:" << values.size();
1151 sensors_parsed->clear();
1152 return false;
1153 } else {
1154 float min = std::numeric_limits<float>::min();
1155 for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
1156 hot_thresholds[j] = getFloatFromValue(values[j]);
1157 if (!std::isnan(hot_thresholds[j])) {
1158 if (hot_thresholds[j] < min) {
1159 LOG(ERROR) << "Invalid "
1160 << "Sensor[" << name << "]'s HotThreshold[j" << j
1161 << "]: " << hot_thresholds[j] << " < " << min;
1162 sensors_parsed->clear();
1163 return false;
1164 }
1165 min = hot_thresholds[j];
1166 }
1167 LOG(INFO) << "Sensor[" << name << "]'s HotThreshold[" << j
1168 << "]: " << hot_thresholds[j];
1169 }
1170 }
1171
1172 values = sensors[i]["HotHysteresis"];
1173 if (!values.size()) {
1174 LOG(INFO) << "Sensor[" << name << "]'s HotHysteresis, default all to 0.0";
1175 } else if (values.size() != kThrottlingSeverityCount) {
1176 LOG(ERROR) << "Invalid Sensor[" << name << "]'s HotHysteresis, count:" << values.size();
1177 sensors_parsed->clear();
1178 return false;
1179 } else {
1180 for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
1181 hot_hysteresis[j] = getFloatFromValue(values[j]);
1182 if (std::isnan(hot_hysteresis[j])) {
1183 LOG(ERROR) << "Invalid Sensor[" << name
1184 << "]'s HotHysteresis: " << hot_hysteresis[j];
1185 sensors_parsed->clear();
1186 return false;
1187 }
1188 LOG(INFO) << "Sensor[" << name << "]'s HotHysteresis[" << j
1189 << "]: " << hot_hysteresis[j];
1190 }
1191 }
1192
1193 for (Json::Value::ArrayIndex j = 0; j < (kThrottlingSeverityCount - 1); ++j) {
1194 if (std::isnan(hot_thresholds[j])) {
1195 continue;
1196 }
1197 for (auto k = j + 1; k < kThrottlingSeverityCount; ++k) {
1198 if (std::isnan(hot_thresholds[k])) {
1199 continue;
1200 } else if (hot_thresholds[j] > (hot_thresholds[k] - hot_hysteresis[k])) {
1201 LOG(ERROR) << "Sensor[" << name << "]'s hot threshold " << j
1202 << " is overlapped";
1203 sensors_parsed->clear();
1204 return false;
1205 } else {
1206 break;
1207 }
1208 }
1209 }
1210
1211 values = sensors[i]["ColdThreshold"];
1212 if (!values.size()) {
1213 LOG(INFO) << "Sensor[" << name << "]'s ColdThreshold, default all to NAN";
1214 } else if (values.size() != kThrottlingSeverityCount) {
1215 LOG(ERROR) << "Invalid Sensor[" << name << "]'s ColdThreshold count:" << values.size();
1216 sensors_parsed->clear();
1217 return false;
1218 } else {
1219 float max = std::numeric_limits<float>::max();
1220 for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
1221 cold_thresholds[j] = getFloatFromValue(values[j]);
1222 if (!std::isnan(cold_thresholds[j])) {
1223 if (cold_thresholds[j] > max) {
1224 LOG(ERROR) << "Invalid "
1225 << "Sensor[" << name << "]'s ColdThreshold[j" << j
1226 << "]: " << cold_thresholds[j] << " > " << max;
1227 sensors_parsed->clear();
1228 return false;
1229 }
1230 max = cold_thresholds[j];
1231 }
1232 LOG(INFO) << "Sensor[" << name << "]'s ColdThreshold[" << j
1233 << "]: " << cold_thresholds[j];
1234 }
1235 }
1236
1237 values = sensors[i]["ColdHysteresis"];
1238 if (!values.size()) {
1239 LOG(INFO) << "Sensor[" << name << "]'s ColdHysteresis, default all to 0.0";
1240 } else if (values.size() != kThrottlingSeverityCount) {
1241 LOG(ERROR) << "Invalid Sensor[" << name << "]'s ColdHysteresis count:" << values.size();
1242 sensors_parsed->clear();
1243 return false;
1244 } else {
1245 for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
1246 cold_hysteresis[j] = getFloatFromValue(values[j]);
1247 if (std::isnan(cold_hysteresis[j])) {
1248 LOG(ERROR) << "Invalid Sensor[" << name
1249 << "]'s ColdHysteresis: " << cold_hysteresis[j];
1250 sensors_parsed->clear();
1251 return false;
1252 }
1253 LOG(INFO) << "Sensor[" << name << "]'s ColdHysteresis[" << j
1254 << "]: " << cold_hysteresis[j];
1255 }
1256 }
1257
1258 for (Json::Value::ArrayIndex j = 0; j < (kThrottlingSeverityCount - 1); ++j) {
1259 if (std::isnan(cold_thresholds[j])) {
1260 continue;
1261 }
1262 for (auto k = j + 1; k < kThrottlingSeverityCount; ++k) {
1263 if (std::isnan(cold_thresholds[k])) {
1264 continue;
1265 } else if (cold_thresholds[j] < (cold_thresholds[k] + cold_hysteresis[k])) {
1266 LOG(ERROR) << "Sensor[" << name << "]'s cold threshold " << j
1267 << " is overlapped";
1268 sensors_parsed->clear();
1269 return false;
1270 } else {
1271 break;
1272 }
1273 }
1274 }
1275
1276 std::string temp_path;
1277 if (!sensors[i]["TempPath"].empty()) {
1278 temp_path = sensors[i]["TempPath"].asString();
1279 LOG(INFO) << "Sensor[" << name << "]'s TempPath: " << temp_path;
1280 }
1281
1282 float vr_threshold = NAN;
1283 if (!sensors[i]["VrThreshold"].empty()) {
1284 vr_threshold = getFloatFromValue(sensors[i]["VrThreshold"]);
1285 LOG(INFO) << "Sensor[" << name << "]'s VrThreshold: " << vr_threshold;
1286 }
1287
1288 float multiplier = 1.0;
1289 if (!sensors[i]["Multiplier"].empty()) {
1290 multiplier = sensors[i]["Multiplier"].asFloat();
1291 }
1292 LOG(INFO) << "Sensor[" << name << "]'s Multiplier: " << multiplier;
1293
1294 std::chrono::milliseconds polling_delay = kUeventPollTimeoutMs;
1295 if (!sensors[i]["PollingDelay"].empty()) {
1296 const auto value = getIntFromValue(sensors[i]["PollingDelay"]);
1297 polling_delay = (value > 0) ? std::chrono::milliseconds(value)
1298 : std::chrono::milliseconds::max();
1299 }
1300 LOG(INFO) << "Sensor[" << name << "]'s Polling delay: " << polling_delay.count();
1301
1302 std::chrono::milliseconds passive_delay = kMinPollIntervalMs;
1303 if (!sensors[i]["PassiveDelay"].empty()) {
1304 const auto value = getIntFromValue(sensors[i]["PassiveDelay"]);
1305 passive_delay = (value > 0) ? std::chrono::milliseconds(value)
1306 : std::chrono::milliseconds::max();
1307 }
1308 LOG(INFO) << "Sensor[" << name << "]'s Passive delay: " << passive_delay.count();
1309
1310 std::chrono::milliseconds time_resolution;
1311 if (sensors[i]["TimeResolution"].empty()) {
1312 time_resolution = kMinPollIntervalMs;
1313 } else {
1314 time_resolution =
1315 std::chrono::milliseconds(getIntFromValue(sensors[i]["TimeResolution"]));
1316 }
1317 LOG(INFO) << "Sensor[" << name << "]'s Time resolution: " << time_resolution.count();
1318
1319 float step_ratio = NAN;
1320 if (!sensors[i]["StepRatio"].empty()) {
1321 step_ratio = sensors[i]["StepRatio"].asFloat();
1322 if (step_ratio < 0 || step_ratio > 1) {
1323 LOG(ERROR) << "Sensor[" << name << "]'s StepRatio should be set 0 ~ 1";
1324 sensors_parsed->clear();
1325 return false;
1326 }
1327
1328 if (sensors[i]["PassiveDelay"].empty()) {
1329 LOG(ERROR) << "Sensor[" << name << "] has StepRatio but no explicit PassiveDelay";
1330 sensors_parsed->clear();
1331 return false;
1332 }
1333 }
1334
1335 if (is_hidden && send_cb) {
1336 LOG(ERROR) << "is_hidden and send_cb cannot be enabled together";
1337 sensors_parsed->clear();
1338 return false;
1339 }
1340
1341 std::unique_ptr<VirtualSensorInfo> virtual_sensor_info;
1342 if (!ParseVirtualSensorInfo(name, sensors[i], &virtual_sensor_info)) {
1343 LOG(ERROR) << "Sensor[" << name << "]: failed to parse virtual sensor info";
1344 sensors_parsed->clear();
1345 return false;
1346 }
1347
1348 std::unique_ptr<PredictorInfo> predictor_info;
1349 if (!ParsePredictorInfo(name, sensors[i], &predictor_info)) {
1350 LOG(ERROR) << "Sensor[" << name << "]: failed to parse virtual sensor info";
1351 sensors_parsed->clear();
1352 return false;
1353 }
1354
1355 bool support_throttling = false; // support pid or hard limit
1356 std::shared_ptr<ThrottlingInfo> throttling_info;
1357 if (!ParseSensorThrottlingInfo(name, sensors[i], &support_throttling, &throttling_info,
1358 scaling_frequency_map)) {
1359 LOG(ERROR) << "Sensor[" << name << "]: failed to parse throttling info";
1360 sensors_parsed->clear();
1361 return false;
1362 }
1363
1364 bool is_watch = (send_cb | send_powerhint | support_throttling);
1365 LOG(INFO) << "Sensor[" << name << "]'s is_watch: " << std::boolalpha << is_watch;
1366
1367 (*sensors_parsed)[name] = {
1368 .type = sensor_type,
1369 .hot_thresholds = hot_thresholds,
1370 .cold_thresholds = cold_thresholds,
1371 .hot_hysteresis = hot_hysteresis,
1372 .cold_hysteresis = cold_hysteresis,
1373 .temp_path = temp_path,
1374 .vr_threshold = vr_threshold,
1375 .multiplier = multiplier,
1376 .polling_delay = polling_delay,
1377 .passive_delay = passive_delay,
1378 .time_resolution = time_resolution,
1379 .step_ratio = step_ratio,
1380 .send_cb = send_cb,
1381 .send_powerhint = send_powerhint,
1382 .is_watch = is_watch,
1383 .is_hidden = is_hidden,
1384 .virtual_sensor_info = std::move(virtual_sensor_info),
1385 .throttling_info = std::move(throttling_info),
1386 .predictor_info = std::move(predictor_info),
1387 };
1388
1389 ++total_parsed;
1390 }
1391 LOG(INFO) << total_parsed << " Sensors parsed successfully";
1392 return true;
1393 }
1394
ParseCoolingDevice(const Json::Value & config,std::unordered_map<std::string,CdevInfo> * cooling_devices_parsed)1395 bool ParseCoolingDevice(const Json::Value &config,
1396 std::unordered_map<std::string, CdevInfo> *cooling_devices_parsed) {
1397 Json::Value cooling_devices = config["CoolingDevices"];
1398 std::size_t total_parsed = 0;
1399 std::unordered_set<std::string> cooling_devices_name_parsed;
1400
1401 for (Json::Value::ArrayIndex i = 0; i < cooling_devices.size(); ++i) {
1402 const std::string &name = cooling_devices[i]["Name"].asString();
1403 LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name;
1404 if (name.empty()) {
1405 LOG(ERROR) << "Failed to read CoolingDevice[" << i << "]'s Name";
1406 cooling_devices_parsed->clear();
1407 return false;
1408 }
1409
1410 auto result = cooling_devices_name_parsed.insert(name.data());
1411 if (!result.second) {
1412 LOG(ERROR) << "Duplicate CoolingDevice[" << i << "]'s Name";
1413 cooling_devices_parsed->clear();
1414 return false;
1415 }
1416
1417 std::string cooling_device_type_str = cooling_devices[i]["Type"].asString();
1418 LOG(INFO) << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str;
1419 CoolingType cooling_device_type;
1420
1421 if (!getTypeFromString(cooling_device_type_str, &cooling_device_type)) {
1422 LOG(ERROR) << "Invalid CoolingDevice[" << name
1423 << "]'s Type: " << cooling_device_type_str;
1424 cooling_devices_parsed->clear();
1425 return false;
1426 }
1427
1428 const std::string &read_path = cooling_devices[i]["ReadPath"].asString();
1429 LOG(INFO) << "Cdev Read Path: " << (read_path.empty() ? "default" : read_path);
1430
1431 const std::string &write_path = cooling_devices[i]["WritePath"].asString();
1432 LOG(INFO) << "Cdev Write Path: " << (write_path.empty() ? "default" : write_path);
1433
1434 std::vector<float> state2power;
1435 Json::Value values = cooling_devices[i]["State2Power"];
1436 if (values.size()) {
1437 state2power.reserve(values.size());
1438 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
1439 state2power.emplace_back(getFloatFromValue(values[j]));
1440 LOG(INFO) << "Cooling device[" << name << "]'s Power2State[" << j
1441 << "]: " << state2power[j];
1442 if (j > 0 && state2power[j] < state2power[j - 1]) {
1443 LOG(ERROR) << "Higher power with higher state on cooling device " << name
1444 << "'s state" << j;
1445 }
1446 }
1447 } else {
1448 LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name
1449 << " does not support State2Power";
1450 }
1451
1452 const std::string &power_rail = cooling_devices[i]["PowerRail"].asString();
1453 LOG(INFO) << "Cooling device power rail : " << power_rail;
1454
1455 (*cooling_devices_parsed)[name] = {
1456 .type = cooling_device_type,
1457 .read_path = read_path,
1458 .write_path = write_path,
1459 .state2power = state2power,
1460 };
1461 ++total_parsed;
1462 }
1463 LOG(INFO) << total_parsed << " CoolingDevices parsed successfully";
1464 return true;
1465 }
1466
ParsePowerRailInfo(const Json::Value & config,std::unordered_map<std::string,PowerRailInfo> * power_rails_parsed)1467 bool ParsePowerRailInfo(const Json::Value &config,
1468 std::unordered_map<std::string, PowerRailInfo> *power_rails_parsed) {
1469 Json::Value power_rails = config["PowerRails"];
1470 std::size_t total_parsed = 0;
1471 std::unordered_set<std::string> power_rails_name_parsed;
1472
1473 for (Json::Value::ArrayIndex i = 0; i < power_rails.size(); ++i) {
1474 const std::string &name = power_rails[i]["Name"].asString();
1475 LOG(INFO) << "PowerRail[" << i << "]'s Name: " << name;
1476 if (name.empty()) {
1477 LOG(ERROR) << "Failed to read PowerRail[" << i << "]'s Name";
1478 power_rails_parsed->clear();
1479 return false;
1480 }
1481
1482 std::vector<std::string> linked_power_rails;
1483 std::vector<float> coefficient;
1484 float offset = 0;
1485 FormulaOption formula = FormulaOption::COUNT_THRESHOLD;
1486 bool is_virtual_power_rail = false;
1487 Json::Value values;
1488 int power_sample_count = 0;
1489 std::chrono::milliseconds power_sample_delay;
1490
1491 if (!power_rails[i]["VirtualRails"].empty() && power_rails[i]["VirtualRails"].isBool()) {
1492 is_virtual_power_rail = power_rails[i]["VirtualRails"].asBool();
1493 LOG(INFO) << "PowerRails[" << name << "]'s VirtualRail, set to 'true'";
1494 }
1495
1496 if (is_virtual_power_rail) {
1497 values = power_rails[i]["Combination"];
1498 if (values.size()) {
1499 linked_power_rails.reserve(values.size());
1500 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
1501 linked_power_rails.emplace_back(values[j].asString());
1502 LOG(INFO) << "PowerRail[" << name << "]'s combination[" << j
1503 << "]: " << linked_power_rails[j];
1504 }
1505 } else {
1506 LOG(ERROR) << "PowerRails[" << name << "] has no combination for VirtualRail";
1507 power_rails_parsed->clear();
1508 return false;
1509 }
1510
1511 values = power_rails[i]["Coefficient"];
1512 if (values.size()) {
1513 coefficient.reserve(values.size());
1514 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
1515 coefficient.emplace_back(getFloatFromValue(values[j]));
1516 LOG(INFO) << "PowerRail[" << name << "]'s coefficient[" << j
1517 << "]: " << coefficient[j];
1518 }
1519 } else {
1520 LOG(ERROR) << "PowerRails[" << name << "] has no coefficient for VirtualRail";
1521 power_rails_parsed->clear();
1522 return false;
1523 }
1524
1525 if (linked_power_rails.size() != coefficient.size()) {
1526 LOG(ERROR) << "PowerRails[" << name
1527 << "]'s combination size is not matched with coefficient size";
1528 power_rails_parsed->clear();
1529 return false;
1530 }
1531
1532 if (!power_rails[i]["Offset"].empty()) {
1533 offset = power_rails[i]["Offset"].asFloat();
1534 }
1535
1536 if (linked_power_rails.size() != coefficient.size()) {
1537 LOG(ERROR) << "PowerRails[" << name
1538 << "]'s combination size is not matched with coefficient size";
1539 power_rails_parsed->clear();
1540 return false;
1541 }
1542
1543 if (power_rails[i]["Formula"].asString().compare("COUNT_THRESHOLD") == 0) {
1544 formula = FormulaOption::COUNT_THRESHOLD;
1545 } else if (power_rails[i]["Formula"].asString().compare("WEIGHTED_AVG") == 0) {
1546 formula = FormulaOption::WEIGHTED_AVG;
1547 } else if (power_rails[i]["Formula"].asString().compare("MAXIMUM") == 0) {
1548 formula = FormulaOption::MAXIMUM;
1549 } else if (power_rails[i]["Formula"].asString().compare("MINIMUM") == 0) {
1550 formula = FormulaOption::MINIMUM;
1551 } else {
1552 LOG(ERROR) << "PowerRails[" << name << "]'s Formula is invalid";
1553 power_rails_parsed->clear();
1554 return false;
1555 }
1556 }
1557
1558 std::unique_ptr<VirtualPowerRailInfo> virtual_power_rail_info;
1559 if (is_virtual_power_rail) {
1560 virtual_power_rail_info.reset(
1561 new VirtualPowerRailInfo{linked_power_rails, coefficient, offset, formula});
1562 }
1563
1564 power_sample_count = power_rails[i]["PowerSampleCount"].asInt();
1565 LOG(INFO) << "Power sample Count: " << power_sample_count;
1566
1567 if (!power_rails[i]["PowerSampleDelay"]) {
1568 power_sample_delay = std::chrono::milliseconds::max();
1569 } else {
1570 power_sample_delay =
1571 std::chrono::milliseconds(getIntFromValue(power_rails[i]["PowerSampleDelay"]));
1572 }
1573
1574 (*power_rails_parsed)[name] = {
1575 .power_sample_count = power_sample_count,
1576 .power_sample_delay = power_sample_delay,
1577 .virtual_power_rail_info = std::move(virtual_power_rail_info),
1578 };
1579 ++total_parsed;
1580 }
1581 LOG(INFO) << total_parsed << " PowerRails parsed successfully";
1582 return true;
1583 }
1584
1585 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)1586 bool ParseStatsInfo(const Json::Value &stats_config,
1587 const std::unordered_map<std::string, U> &entity_info, StatsInfo<T> *stats_info,
1588 T min_value) {
1589 if (stats_config.empty()) {
1590 LOG(INFO) << "No stats config";
1591 return true;
1592 }
1593 std::variant<bool, std::unordered_set<std::string>>
1594 record_by_default_threshold_all_or_name_set_ = false;
1595 if (stats_config["DefaultThresholdEnableAll"].empty() ||
1596 !stats_config["DefaultThresholdEnableAll"].isBool()) {
1597 LOG(INFO) << "Failed to read stats DefaultThresholdEnableAll, set to 'false'";
1598 } else if (stats_config["DefaultThresholdEnableAll"].asBool()) {
1599 record_by_default_threshold_all_or_name_set_ = true;
1600 }
1601 LOG(INFO) << "DefaultThresholdEnableAll " << std::boolalpha
1602 << std::get<bool>(record_by_default_threshold_all_or_name_set_) << std::noboolalpha;
1603
1604 Json::Value values = stats_config["RecordWithDefaultThreshold"];
1605 if (values.size()) {
1606 if (std::get<bool>(record_by_default_threshold_all_or_name_set_)) {
1607 LOG(ERROR) << "Cannot enable record with default threshold when "
1608 "DefaultThresholdEnableAll true.";
1609 return false;
1610 }
1611 record_by_default_threshold_all_or_name_set_ = std::unordered_set<std::string>();
1612 for (Json::Value::ArrayIndex i = 0; i < values.size(); ++i) {
1613 std::string name = values[i].asString();
1614 if (!entity_info.count(name)) {
1615 LOG(ERROR) << "Unknown name [" << name << "] not present in entity_info.";
1616 return false;
1617 }
1618 std::get<std::unordered_set<std::string>>(record_by_default_threshold_all_or_name_set_)
1619 .insert(name);
1620 }
1621 } else {
1622 LOG(INFO) << "No stat by default threshold enabled.";
1623 }
1624
1625 std::unordered_map<std::string, std::vector<ThresholdList<T>>> record_by_threshold;
1626 values = stats_config["RecordWithThreshold"];
1627 if (values.size()) {
1628 Json::Value threshold_values;
1629 for (Json::Value::ArrayIndex i = 0; i < values.size(); i++) {
1630 const std::string &name = values[i]["Name"].asString();
1631 if (!entity_info.count(name)) {
1632 LOG(ERROR) << "Unknown name [" << name << "] not present in entity_info.";
1633 return false;
1634 }
1635
1636 std::optional<std::string> logging_name;
1637 if (!values[i]["LoggingName"].empty()) {
1638 logging_name = values[i]["LoggingName"].asString();
1639 LOG(INFO) << "For [" << name << "]"
1640 << ", stats logging name is [" << logging_name.value() << "]";
1641 }
1642
1643 LOG(INFO) << "Start to parse stats threshold for [" << name << "]";
1644 threshold_values = values[i]["Thresholds"];
1645 if (threshold_values.empty()) {
1646 LOG(ERROR) << "Empty stats threshold not valid.";
1647 return false;
1648 }
1649 const auto &threshold_values_count = threshold_values.size();
1650 if (threshold_values_count > kMaxStatsThresholdCount) {
1651 LOG(ERROR) << "Number of stats threshold " << threshold_values_count
1652 << " greater than max " << kMaxStatsThresholdCount;
1653 return false;
1654 }
1655 std::vector<T> stats_threshold(threshold_values_count);
1656 T prev_value = min_value;
1657 LOG(INFO) << "Thresholds:";
1658 for (Json::Value::ArrayIndex i = 0; i < threshold_values_count; ++i) {
1659 stats_threshold[i] = std::is_floating_point_v<T>
1660 ? getFloatFromValue(threshold_values[i])
1661 : getIntFromValue(threshold_values[i]);
1662 if (stats_threshold[i] <= prev_value) {
1663 LOG(ERROR) << "Invalid array[" << i << "]" << stats_threshold[i]
1664 << " is <=" << prev_value;
1665 return false;
1666 }
1667 prev_value = stats_threshold[i];
1668 LOG(INFO) << "[" << i << "]: " << stats_threshold[i];
1669 }
1670 record_by_threshold[name].emplace_back(logging_name, stats_threshold);
1671 }
1672 } else {
1673 LOG(INFO) << "No stat by threshold enabled.";
1674 }
1675
1676 (*stats_info) = {.record_by_default_threshold_all_or_name_set_ =
1677 record_by_default_threshold_all_or_name_set_,
1678 .record_by_threshold = record_by_threshold};
1679 return true;
1680 }
1681
ParseSensorAbnormalStatsConfig(const Json::Value & abnormal_stats_config,const std::unordered_map<std::string,SensorInfo> & sensor_info_map_,AbnormalStatsInfo * abnormal_stats_info_parsed)1682 bool ParseSensorAbnormalStatsConfig(
1683 const Json::Value &abnormal_stats_config,
1684 const std::unordered_map<std::string, SensorInfo> &sensor_info_map_,
1685 AbnormalStatsInfo *abnormal_stats_info_parsed) {
1686 if (abnormal_stats_config.empty()) {
1687 LOG(INFO) << "No sensors abnormality monitoring info present.";
1688 return true;
1689 }
1690
1691 Json::Value values;
1692
1693 std::optional<TempRangeInfo> default_temp_range_info;
1694 std::vector<AbnormalStatsInfo::SensorsTempRangeInfo> sensors_temp_range_infos;
1695 Json::Value outlier_temp_config = abnormal_stats_config["Outlier"];
1696 if (outlier_temp_config) {
1697 LOG(INFO) << "Start to parse outlier temp config.";
1698
1699 if (outlier_temp_config["Default"]) {
1700 LOG(INFO) << "Start to parse defaultTempRange.";
1701 if (!getTempRangeInfoFromJsonValues(outlier_temp_config["Default"],
1702 &default_temp_range_info.value())) {
1703 LOG(ERROR) << "Failed to parse default temp range config.";
1704 return false;
1705 }
1706 }
1707
1708 Json::Value configs = outlier_temp_config["Configs"];
1709 if (configs) {
1710 std::unordered_set<std::string> sensors_parsed;
1711 for (Json::Value::ArrayIndex i = 0; i < configs.size(); i++) {
1712 LOG(INFO) << "Start to parse temp range config[" << i << "]";
1713 AbnormalStatsInfo::SensorsTempRangeInfo sensors_temp_range_info;
1714 values = configs[i]["Monitor"];
1715 if (!values.size()) {
1716 LOG(ERROR) << "Invalid config no sensor list present for outlier temp "
1717 "config.";
1718 return false;
1719 }
1720 for (Json::Value::ArrayIndex j = 0; j < values.size(); j++) {
1721 const std::string &sensor = values[j].asString();
1722 if (!sensor_info_map_.count(sensor)) {
1723 LOG(ERROR) << "Unknown sensor " << sensor;
1724 return false;
1725 }
1726 auto result = sensors_parsed.insert(sensor);
1727 if (!result.second) {
1728 LOG(ERROR) << "Duplicate Sensor Temp Range Config: " << sensor;
1729 return false;
1730 }
1731 LOG(INFO) << "Monitored sensor [" << j << "]: " << sensor;
1732 sensors_temp_range_info.sensors.push_back(sensor);
1733 }
1734 if (!getTempRangeInfoFromJsonValues(configs[i]["TempRange"],
1735 &sensors_temp_range_info.temp_range_info)) {
1736 LOG(ERROR) << "Failed to parse temp range config.";
1737 return false;
1738 }
1739 sensors_temp_range_infos.push_back(sensors_temp_range_info);
1740 }
1741 }
1742 }
1743 std::optional<TempStuckInfo> default_temp_stuck_info;
1744 std::vector<AbnormalStatsInfo::SensorsTempStuckInfo> sensors_temp_stuck_infos;
1745 Json::Value stuck_temp_config = abnormal_stats_config["Stuck"];
1746 if (stuck_temp_config) {
1747 LOG(INFO) << "Start to parse stuck temp config.";
1748
1749 if (stuck_temp_config["Default"]) {
1750 LOG(INFO) << "Start to parse defaultTempStuck.";
1751 if (!getTempStuckInfoFromJsonValue(stuck_temp_config["Default"],
1752 &default_temp_stuck_info.value())) {
1753 LOG(ERROR) << "Failed to parse default temp stuck config.";
1754 return false;
1755 }
1756 }
1757
1758 Json::Value configs = stuck_temp_config["Configs"];
1759 if (configs) {
1760 std::unordered_set<std::string> sensors_parsed;
1761 for (Json::Value::ArrayIndex i = 0; i < configs.size(); i++) {
1762 LOG(INFO) << "Start to parse temp stuck config[" << i << "]";
1763 AbnormalStatsInfo::SensorsTempStuckInfo sensor_temp_stuck_info;
1764 values = configs[i]["Monitor"];
1765 if (!values.size()) {
1766 LOG(ERROR) << "Invalid config no sensor list present for stuck temp "
1767 "config.";
1768 return false;
1769 }
1770 for (Json::Value::ArrayIndex j = 0; j < values.size(); j++) {
1771 const std::string &sensor = values[j].asString();
1772 if (!sensor_info_map_.count(sensor)) {
1773 LOG(ERROR) << "Unknown sensor " << sensor;
1774 return false;
1775 }
1776 auto result = sensors_parsed.insert(sensor);
1777 if (!result.second) {
1778 LOG(ERROR) << "Duplicate Sensor Temp Stuck Config: " << sensor;
1779 return false;
1780 }
1781 LOG(INFO) << "Monitored sensor [" << j << "]: " << sensor;
1782 sensor_temp_stuck_info.sensors.push_back(sensor);
1783 }
1784 if (!getTempStuckInfoFromJsonValue(configs[i]["TempStuck"],
1785 &sensor_temp_stuck_info.temp_stuck_info)) {
1786 LOG(ERROR) << "Failed to parse temp stuck config.";
1787 return false;
1788 }
1789 sensors_temp_stuck_infos.push_back(sensor_temp_stuck_info);
1790 }
1791 }
1792 }
1793 *abnormal_stats_info_parsed = {
1794 .default_temp_range_info = default_temp_range_info,
1795 .sensors_temp_range_infos = sensors_temp_range_infos,
1796 .default_temp_stuck_info = default_temp_stuck_info,
1797 .sensors_temp_stuck_infos = sensors_temp_stuck_infos,
1798 };
1799 return true;
1800 }
1801
ParseSensorStatsConfig(const Json::Value & config,const std::unordered_map<std::string,SensorInfo> & sensor_info_map_,StatsInfo<float> * sensor_stats_info_parsed,AbnormalStatsInfo * abnormal_stats_info_parsed)1802 bool ParseSensorStatsConfig(const Json::Value &config,
1803 const std::unordered_map<std::string, SensorInfo> &sensor_info_map_,
1804 StatsInfo<float> *sensor_stats_info_parsed,
1805 AbnormalStatsInfo *abnormal_stats_info_parsed) {
1806 Json::Value stats_config = config["Stats"];
1807 if (stats_config.empty()) {
1808 LOG(INFO) << "No Stats Config present.";
1809 return true;
1810 }
1811 // Parse cooling device user vote
1812 Json::Value sensor_config = stats_config["Sensors"];
1813 if (sensor_config.empty()) {
1814 LOG(INFO) << "No Sensor Stats Config present.";
1815 return true;
1816 }
1817 LOG(INFO) << "Parse Stats Config for Sensor Temp.";
1818 // Parse sensor stats config
1819 if (!ParseStatsInfo(stats_config["Sensors"], sensor_info_map_, sensor_stats_info_parsed,
1820 std::numeric_limits<float>::lowest())) {
1821 LOG(ERROR) << "Failed to parse sensor temp stats info.";
1822 sensor_stats_info_parsed->clear();
1823 return false;
1824 }
1825 if (!ParseSensorAbnormalStatsConfig(sensor_config["Abnormality"], sensor_info_map_,
1826 abnormal_stats_info_parsed)) {
1827 LOG(ERROR) << "Failed to parse sensor abnormal stats config.";
1828 return false;
1829 }
1830 return true;
1831 }
1832
ParseCoolingDeviceStatsConfig(const Json::Value & config,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map_,StatsInfo<int> * cooling_device_request_info_parsed)1833 bool ParseCoolingDeviceStatsConfig(
1834 const Json::Value &config,
1835 const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map_,
1836 StatsInfo<int> *cooling_device_request_info_parsed) {
1837 Json::Value stats_config = config["Stats"];
1838 if (stats_config.empty()) {
1839 LOG(INFO) << "No Stats Config present.";
1840 return true;
1841 }
1842 // Parse cooling device user vote
1843 if (stats_config["CoolingDevices"].empty()) {
1844 LOG(INFO) << "No cooling device stats present.";
1845 return true;
1846 }
1847 LOG(INFO) << "Parse Stats Config for Sensor CDev Request.";
1848 if (!ParseStatsInfo(stats_config["CoolingDevices"]["RecordVotePerSensor"],
1849 cooling_device_info_map_, cooling_device_request_info_parsed, -1)) {
1850 LOG(ERROR) << "Failed to parse cooling device user vote stats info.";
1851 cooling_device_request_info_parsed->clear();
1852 return false;
1853 }
1854 return true;
1855 }
1856 } // namespace implementation
1857 } // namespace thermal
1858 } // namespace hardware
1859 } // namespace android
1860 } // namespace aidl
1861