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