1 /*
2 * Copyright (C) 2018 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 <android-base/file.h>
17 #include <android-base/logging.h>
18 #include <android-base/properties.h>
19 #include <android-base/strings.h>
20 #include <cmath>
21 #include <unordered_set>
22
23 #include <json/reader.h>
24 #include <json/value.h>
25
26 #include "config_parser.h"
27
28 namespace android {
29 namespace hardware {
30 namespace thermal {
31 namespace V2_0 {
32 namespace implementation {
33
34 constexpr std::string_view kPowerLinkDisabledProperty("vendor.disable.thermal.powerlink");
35
36 using ::android::hardware::hidl_enum_range;
37 using ::android::hardware::thermal::V2_0::toString;
38 using TemperatureType_2_0 = ::android::hardware::thermal::V2_0::TemperatureType;
39
40 namespace {
41
42 template <typename T>
43 // Return false when failed parsing
getTypeFromString(std::string_view str,T * out)44 bool getTypeFromString(std::string_view str, T *out) {
45 auto types = hidl_enum_range<T>();
46 for (const auto &type : types) {
47 if (toString(type) == str) {
48 *out = type;
49 return true;
50 }
51 }
52 return false;
53 }
54
getFloatFromValue(const Json::Value & value)55 float getFloatFromValue(const Json::Value &value) {
56 if (value.isString()) {
57 return std::stof(value.asString());
58 } else {
59 return value.asFloat();
60 }
61 }
62
getIntFromValue(const Json::Value & value)63 int getIntFromValue(const Json::Value &value) {
64 if (value.isString()) {
65 return (value.asString() == "max") ? std::numeric_limits<int>::max()
66 : std::stoul(value.asString());
67 } else {
68 return value.asInt();
69 }
70 }
71
getIntFromJsonValues(const Json::Value & values,CdevArray * out,bool inc_check,bool dec_check)72 bool getIntFromJsonValues(const Json::Value &values, CdevArray *out, bool inc_check,
73 bool dec_check) {
74 CdevArray ret;
75
76 if (inc_check && dec_check) {
77 LOG(ERROR) << "Cannot enable inc_check and dec_check at the same time";
78 return false;
79 }
80
81 if (values.size() != kThrottlingSeverityCount) {
82 LOG(ERROR) << "Values size is invalid";
83 return false;
84 } else {
85 int last;
86 for (Json::Value::ArrayIndex i = 0; i < kThrottlingSeverityCount; ++i) {
87 ret[i] = getIntFromValue(values[i]);
88 if (inc_check && ret[i] < last) {
89 LOG(FATAL) << "Invalid array[" << i << "]" << ret[i] << " min=" << last;
90 return false;
91 }
92 if (dec_check && ret[i] > last) {
93 LOG(FATAL) << "Invalid array[" << i << "]" << ret[i] << " max=" << last;
94 return false;
95 }
96 last = ret[i];
97 LOG(INFO) << "[" << i << "]: " << ret[i];
98 }
99 }
100
101 *out = ret;
102 return true;
103 }
104
getFloatFromJsonValues(const Json::Value & values,ThrottlingArray * out,bool inc_check,bool dec_check)105 bool getFloatFromJsonValues(const Json::Value &values, ThrottlingArray *out, bool inc_check,
106 bool dec_check) {
107 ThrottlingArray ret;
108
109 if (inc_check && dec_check) {
110 LOG(ERROR) << "Cannot enable inc_check and dec_check at the same time";
111 return false;
112 }
113
114 if (values.size() != kThrottlingSeverityCount) {
115 LOG(ERROR) << "Values size is invalid";
116 return false;
117 } else {
118 float last = std::nanf("");
119 for (Json::Value::ArrayIndex i = 0; i < kThrottlingSeverityCount; ++i) {
120 ret[i] = getFloatFromValue(values[i]);
121 if (inc_check && !std::isnan(last) && !std::isnan(ret[i]) && ret[i] < last) {
122 LOG(FATAL) << "Invalid array[" << i << "]" << ret[i] << " min=" << last;
123 return false;
124 }
125 if (dec_check && !std::isnan(last) && !std::isnan(ret[i]) && ret[i] > last) {
126 LOG(FATAL) << "Invalid array[" << i << "]" << ret[i] << " max=" << last;
127 return false;
128 }
129 last = std::isnan(ret[i]) ? last : ret[i];
130 LOG(INFO) << "[" << i << "]: " << ret[i];
131 }
132 }
133
134 *out = ret;
135 return true;
136 }
137 } // namespace
138
ParseSensorInfo(std::string_view config_path)139 std::unordered_map<std::string, SensorInfo> ParseSensorInfo(std::string_view config_path) {
140 std::string json_doc;
141 std::unordered_map<std::string, SensorInfo> sensors_parsed;
142 if (!android::base::ReadFileToString(config_path.data(), &json_doc)) {
143 LOG(ERROR) << "Failed to read JSON config from " << config_path;
144 return sensors_parsed;
145 }
146
147 Json::Value root;
148 Json::CharReaderBuilder builder;
149 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
150 std::string errorMessage;
151
152 if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
153 LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
154 return sensors_parsed;
155 }
156
157 Json::Value sensors = root["Sensors"];
158 std::size_t total_parsed = 0;
159 std::unordered_set<std::string> sensors_name_parsed;
160
161 for (Json::Value::ArrayIndex i = 0; i < sensors.size(); ++i) {
162 const std::string &name = sensors[i]["Name"].asString();
163 LOG(INFO) << "Sensor[" << i << "]'s Name: " << name;
164 if (name.empty()) {
165 LOG(ERROR) << "Failed to read "
166 << "Sensor[" << i << "]'s Name";
167 sensors_parsed.clear();
168 return sensors_parsed;
169 }
170
171 auto result = sensors_name_parsed.insert(name);
172 if (!result.second) {
173 LOG(ERROR) << "Duplicate Sensor[" << i << "]'s Name";
174 sensors_parsed.clear();
175 return sensors_parsed;
176 }
177
178 std::string sensor_type_str = sensors[i]["Type"].asString();
179 LOG(INFO) << "Sensor[" << name << "]'s Type: " << sensor_type_str;
180 TemperatureType_2_0 sensor_type;
181
182 if (!getTypeFromString(sensor_type_str, &sensor_type)) {
183 LOG(ERROR) << "Invalid "
184 << "Sensor[" << name << "]'s Type: " << sensor_type_str;
185 sensors_parsed.clear();
186 return sensors_parsed;
187 }
188
189 bool send_cb = false;
190 if (sensors[i]["Monitor"].empty() || !sensors[i]["Monitor"].isBool()) {
191 LOG(INFO) << "Failed to read Sensor[" << name << "]'s Monitor, set to 'false'";
192 } else if (sensors[i]["Monitor"].asBool()) {
193 send_cb = true;
194 }
195 LOG(INFO) << "Sensor[" << name << "]'s SendCallback: " << std::boolalpha << send_cb
196 << std::noboolalpha;
197
198 bool send_powerhint = false;
199 if (sensors[i]["SendPowerHint"].empty() || !sensors[i]["SendPowerHint"].isBool()) {
200 LOG(INFO) << "Failed to read Sensor[" << name << "]'s SendPowerHint, set to 'false'";
201 } else if (sensors[i]["SendPowerHint"].asBool()) {
202 send_powerhint = true;
203 }
204 LOG(INFO) << "Sensor[" << name << "]'s SendPowerHint: " << std::boolalpha << send_powerhint
205 << std::noboolalpha;
206
207 std::array<float, kThrottlingSeverityCount> hot_thresholds;
208 hot_thresholds.fill(NAN);
209 std::array<float, kThrottlingSeverityCount> cold_thresholds;
210 cold_thresholds.fill(NAN);
211 std::array<float, kThrottlingSeverityCount> hot_hysteresis;
212 hot_hysteresis.fill(0.0);
213 std::array<float, kThrottlingSeverityCount> cold_hysteresis;
214 cold_hysteresis.fill(0.0);
215 std::vector<std::string> linked_sensors;
216 std::vector<float> coefficients;
217 float offset = 0;
218 std::string trigger_sensor;
219
220 FormulaOption formula = FormulaOption::COUNT_THRESHOLD;
221 bool is_virtual_sensor = false;
222 if (sensors[i]["VirtualSensor"].empty() || !sensors[i]["VirtualSensor"].isBool()) {
223 LOG(INFO) << "Failed to read Sensor[" << name << "]'s VirtualSensor, set to 'false'";
224 } else {
225 is_virtual_sensor = sensors[i]["VirtualSensor"].asBool();
226 }
227 Json::Value values = sensors[i]["HotThreshold"];
228 if (values.size() != kThrottlingSeverityCount) {
229 LOG(ERROR) << "Invalid "
230 << "Sensor[" << name << "]'s HotThreshold count" << values.size();
231 sensors_parsed.clear();
232 return sensors_parsed;
233 } else {
234 float min = std::numeric_limits<float>::min();
235 for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
236 hot_thresholds[j] = getFloatFromValue(values[j]);
237 if (!std::isnan(hot_thresholds[j])) {
238 if (hot_thresholds[j] < min) {
239 LOG(ERROR) << "Invalid "
240 << "Sensor[" << name << "]'s HotThreshold[j" << j
241 << "]: " << hot_thresholds[j] << " < " << min;
242 sensors_parsed.clear();
243 return sensors_parsed;
244 }
245 min = hot_thresholds[j];
246 }
247 LOG(INFO) << "Sensor[" << name << "]'s HotThreshold[" << j
248 << "]: " << hot_thresholds[j];
249 }
250 }
251
252 values = sensors[i]["HotHysteresis"];
253 if (values.size() != kThrottlingSeverityCount) {
254 LOG(INFO) << "Cannot find valid "
255 << "Sensor[" << name << "]'s HotHysteresis, default all to 0.0";
256 } else {
257 for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
258 hot_hysteresis[j] = getFloatFromValue(values[j]);
259 if (std::isnan(hot_hysteresis[j])) {
260 LOG(ERROR) << "Invalid "
261 << "Sensor[" << name << "]'s HotHysteresis: " << hot_hysteresis[j];
262 sensors_parsed.clear();
263 return sensors_parsed;
264 }
265 LOG(INFO) << "Sensor[" << name << "]'s HotHysteresis[" << j
266 << "]: " << hot_hysteresis[j];
267 }
268 }
269
270 values = sensors[i]["ColdThreshold"];
271 if (values.size() != kThrottlingSeverityCount) {
272 LOG(INFO) << "Cannot find valid "
273 << "Sensor[" << name << "]'s ColdThreshold, default all to NAN";
274 } else {
275 float max = std::numeric_limits<float>::max();
276 for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
277 cold_thresholds[j] = getFloatFromValue(values[j]);
278 if (!std::isnan(cold_thresholds[j])) {
279 if (cold_thresholds[j] > max) {
280 LOG(ERROR) << "Invalid "
281 << "Sensor[" << name << "]'s ColdThreshold[j" << j
282 << "]: " << cold_thresholds[j] << " > " << max;
283 sensors_parsed.clear();
284 return sensors_parsed;
285 }
286 max = cold_thresholds[j];
287 }
288 LOG(INFO) << "Sensor[" << name << "]'s ColdThreshold[" << j
289 << "]: " << cold_thresholds[j];
290 }
291 }
292
293 values = sensors[i]["ColdHysteresis"];
294 if (values.size() != kThrottlingSeverityCount) {
295 LOG(INFO) << "Cannot find valid "
296 << "Sensor[" << name << "]'s ColdHysteresis, default all to 0.0";
297 } else {
298 for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
299 cold_hysteresis[j] = getFloatFromValue(values[j]);
300 if (std::isnan(cold_hysteresis[j])) {
301 LOG(ERROR) << "Invalid "
302 << "Sensor[" << name
303 << "]'s ColdHysteresis: " << cold_hysteresis[j];
304 sensors_parsed.clear();
305 return sensors_parsed;
306 }
307 LOG(INFO) << "Sensor[" << name << "]'s ColdHysteresis[" << j
308 << "]: " << cold_hysteresis[j];
309 }
310 }
311
312 if (is_virtual_sensor) {
313 values = sensors[i]["Combination"];
314 if (values.size()) {
315 linked_sensors.reserve(values.size());
316 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
317 linked_sensors.emplace_back(values[j].asString());
318 LOG(INFO) << "Sensor[" << name << "]'s combination[" << j
319 << "]: " << linked_sensors[j];
320 }
321 } else {
322 sensors_parsed.clear();
323 return sensors_parsed;
324 }
325
326 values = sensors[i]["Coefficient"];
327 if (values.size()) {
328 coefficients.reserve(values.size());
329 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
330 coefficients.emplace_back(getFloatFromValue(values[j]));
331 LOG(INFO) << "Sensor[" << name << "]'s coefficient[" << j
332 << "]: " << coefficients[j];
333 }
334 } else {
335 sensors_parsed.clear();
336 return sensors_parsed;
337 }
338
339 if (!sensors[i]["Offset"].empty()) {
340 offset = sensors[i]["Offset"].asFloat();
341 }
342
343 if (linked_sensors.size() != coefficients.size()) {
344 sensors_parsed.clear();
345 return sensors_parsed;
346 }
347
348 trigger_sensor = sensors[i]["TriggerSensor"].asString();
349 if (sensors[i]["Formula"].asString().compare("COUNT_THRESHOLD") == 0) {
350 formula = FormulaOption::COUNT_THRESHOLD;
351 } else if (sensors[i]["Formula"].asString().compare("WEIGHTED_AVG") == 0) {
352 formula = FormulaOption::WEIGHTED_AVG;
353 } else if (sensors[i]["Formula"].asString().compare("MAXIMUM") == 0) {
354 formula = FormulaOption::MAXIMUM;
355 } else if (sensors[i]["Formula"].asString().compare("MINIMUM") == 0) {
356 formula = FormulaOption::MINIMUM;
357 } else {
358 sensors_parsed.clear();
359 return sensors_parsed;
360 }
361 }
362
363 std::string temp_path;
364 if (!sensors[i]["TempPath"].empty()) {
365 temp_path = sensors[i]["TempPath"].asString();
366 LOG(INFO) << "Sensor[" << name << "]'s TempPath: " << temp_path;
367 }
368
369 float vr_threshold = NAN;
370 vr_threshold = getFloatFromValue(sensors[i]["VrThreshold"]);
371 LOG(INFO) << "Sensor[" << name << "]'s VrThreshold: " << vr_threshold;
372
373 float multiplier = sensors[i]["Multiplier"].asFloat();
374 LOG(INFO) << "Sensor[" << name << "]'s Multiplier: " << multiplier;
375
376 std::chrono::milliseconds polling_delay;
377 if (sensors[i]["PollingDelay"].empty()) {
378 polling_delay = kUeventPollTimeoutMs;
379 } else {
380 polling_delay = std::chrono::milliseconds(getIntFromValue(sensors[i]["PollingDelay"]));
381 }
382 LOG(INFO) << "Sensor[" << name << "]'s Polling delay: " << polling_delay.count();
383
384 std::chrono::milliseconds passive_delay;
385 if (sensors[i]["PassiveDelay"].empty()) {
386 passive_delay = kMinPollIntervalMs;
387 } else {
388 passive_delay = std::chrono::milliseconds(getIntFromValue(sensors[i]["PassiveDelay"]));
389 }
390 LOG(INFO) << "Sensor[" << name << "]'s Passive delay: " << passive_delay.count();
391
392 bool support_pid = false;
393 std::array<float, kThrottlingSeverityCount> k_po;
394 k_po.fill(0.0);
395 std::array<float, kThrottlingSeverityCount> k_pu;
396 k_pu.fill(0.0);
397 std::array<float, kThrottlingSeverityCount> k_i;
398 k_i.fill(0.0);
399 std::array<float, kThrottlingSeverityCount> k_d;
400 k_d.fill(0.0);
401 std::array<float, kThrottlingSeverityCount> i_max;
402 i_max.fill(NAN);
403 std::array<float, kThrottlingSeverityCount> max_alloc_power;
404 max_alloc_power.fill(NAN);
405 std::array<float, kThrottlingSeverityCount> min_alloc_power;
406 min_alloc_power.fill(NAN);
407 std::array<float, kThrottlingSeverityCount> s_power;
408 s_power.fill(NAN);
409 std::array<float, kThrottlingSeverityCount> i_cutoff;
410 i_cutoff.fill(NAN);
411
412 // Parse PID parameters
413 if (!sensors[i]["PIDInfo"].empty()) {
414 LOG(INFO) << "Start to parse"
415 << " Sensor[" << name << "]'s K_Po";
416 if (sensors[i]["PIDInfo"]["K_Po"].empty() ||
417 !getFloatFromJsonValues(sensors[i]["PIDInfo"]["K_Po"], &k_po, false, false)) {
418 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_Po";
419 sensors_parsed.clear();
420 return sensors_parsed;
421 }
422 LOG(INFO) << "Start to parse"
423 << " Sensor[" << name << "]'s K_Pu";
424 if (sensors[i]["PIDInfo"]["K_Pu"].empty() ||
425 !getFloatFromJsonValues(sensors[i]["PIDInfo"]["K_Pu"], &k_pu, false, false)) {
426 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_Pu";
427 sensors_parsed.clear();
428 return sensors_parsed;
429 }
430 LOG(INFO) << "Start to parse"
431 << " Sensor[" << name << "]'s K_I";
432 if (sensors[i]["PIDInfo"]["K_I"].empty() ||
433 !getFloatFromJsonValues(sensors[i]["PIDInfo"]["K_I"], &k_i, false, false)) {
434 LOG(INFO) << "Sensor[" << name << "]: Failed to parse K_I";
435 sensors_parsed.clear();
436 return sensors_parsed;
437 }
438 LOG(INFO) << "Start to parse"
439 << " Sensor[" << name << "]'s K_D";
440 if (sensors[i]["PIDInfo"]["K_D"].empty() ||
441 !getFloatFromJsonValues(sensors[i]["PIDInfo"]["K_D"], &k_d, false, false)) {
442 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse K_D";
443 sensors_parsed.clear();
444 return sensors_parsed;
445 }
446 LOG(INFO) << "Start to parse"
447 << " Sensor[" << name << "]'s I_Max";
448 if (sensors[i]["PIDInfo"]["I_Max"].empty() ||
449 !getFloatFromJsonValues(sensors[i]["PIDInfo"]["I_Max"], &i_max, false, false)) {
450 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse I_Max";
451 sensors_parsed.clear();
452 return sensors_parsed;
453 }
454 LOG(INFO) << "Start to parse"
455 << " Sensor[" << name << "]'s MaxAllocPower";
456 if (sensors[i]["PIDInfo"]["MaxAllocPower"].empty() ||
457 !getFloatFromJsonValues(sensors[i]["PIDInfo"]["MaxAllocPower"], &max_alloc_power,
458 false, true)) {
459 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse MaxAllocPower";
460 sensors_parsed.clear();
461 return sensors_parsed;
462 }
463 LOG(INFO) << "Start to parse"
464 << " Sensor[" << name << "]'s MinAllocPower";
465 if (sensors[i]["PIDInfo"]["MinAllocPower"].empty() ||
466 !getFloatFromJsonValues(sensors[i]["PIDInfo"]["MinAllocPower"], &min_alloc_power,
467 false, true)) {
468 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse MinAllocPower";
469 sensors_parsed.clear();
470 return sensors_parsed;
471 }
472 LOG(INFO) << "Start to parse"
473 << " Sensor[" << name << "]'s S_Power";
474 if (sensors[i]["PIDInfo"]["S_Power"].empty() ||
475 !getFloatFromJsonValues(sensors[i]["PIDInfo"]["S_Power"], &s_power, false, true)) {
476 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse S_Power";
477 sensors_parsed.clear();
478 return sensors_parsed;
479 }
480 LOG(INFO) << "Start to parse"
481 << " Sensor[" << name << "]'s I_Cutoff";
482 if (sensors[i]["PIDInfo"]["I_Cutoff"].empty() ||
483 !getFloatFromJsonValues(sensors[i]["PIDInfo"]["I_Cutoff"], &i_cutoff, false,
484 false)) {
485 LOG(ERROR) << "Sensor[" << name << "]: Failed to parse I_Cutoff";
486 sensors_parsed.clear();
487 return sensors_parsed;
488 }
489 // Confirm we have at least one valid PID combination
490 bool valid_pid_combination = false;
491 for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
492 if (!std::isnan(s_power[j])) {
493 if (std::isnan(k_po[j]) || std::isnan(k_pu[j]) || std::isnan(k_i[j]) ||
494 std::isnan(k_d[j]) || std::isnan(i_max[j]) ||
495 std::isnan(max_alloc_power[j]) || std::isnan(min_alloc_power[j]) ||
496 std::isnan(i_cutoff[j])) {
497 valid_pid_combination = false;
498 break;
499 } else {
500 valid_pid_combination = true;
501 }
502 }
503 }
504 if (!valid_pid_combination) {
505 LOG(ERROR) << "Sensor[" << name << "]: Invalid PID parameters combinations";
506 sensors_parsed.clear();
507 return sensors_parsed;
508 } else {
509 support_pid = true;
510 }
511 }
512
513 // Parse binded cooling device
514 bool support_hard_limit = false;
515 std::unordered_map<std::string, BindedCdevInfo> binded_cdev_info_map;
516 values = sensors[i]["BindedCdevInfo"];
517 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
518 Json::Value sub_values;
519 const std::string &cdev_name = values[j]["CdevRequest"].asString();
520 ThrottlingArray cdev_weight_for_pid;
521 cdev_weight_for_pid.fill(NAN);
522 CdevArray cdev_ceiling;
523 cdev_ceiling.fill(std::numeric_limits<int>::max());
524 if (support_pid) {
525 if (!values[j]["CdevWeightForPID"].empty()) {
526 LOG(INFO) << "Sensor[" << name << "]: Star to parse " << cdev_name
527 << "'s CdevWeightForPID";
528 if (!getFloatFromJsonValues(values[j]["CdevWeightForPID"], &cdev_weight_for_pid,
529 false, false)) {
530 LOG(ERROR) << "Failed to parse CdevWeightForPID";
531 sensors_parsed.clear();
532 return sensors_parsed;
533 }
534 }
535 if (!values[j]["CdevCeiling"].empty()) {
536 LOG(INFO) << "Sensor[" << name
537 << "]: Start to parse CdevCeiling: " << cdev_name;
538 if (!getIntFromJsonValues(values[j]["CdevCeiling"], &cdev_ceiling, false,
539 false)) {
540 LOG(ERROR) << "Failed to parse CdevCeiling";
541 sensors_parsed.clear();
542 return sensors_parsed;
543 }
544 }
545 }
546 CdevArray limit_info;
547 limit_info.fill(0);
548 ThrottlingArray power_thresholds;
549 power_thresholds.fill(NAN);
550
551 ReleaseLogic release_logic = ReleaseLogic::NONE;
552
553 sub_values = values[j]["LimitInfo"];
554 if (sub_values.size()) {
555 LOG(INFO) << "Sensor[" << name << "]: Start to parse LimitInfo: " << cdev_name;
556 if (!getIntFromJsonValues(sub_values, &limit_info, false, false)) {
557 LOG(ERROR) << "Failed to parse LimitInfo";
558 sensors_parsed.clear();
559 return sensors_parsed;
560 }
561 support_hard_limit = true;
562 }
563
564 // Parse linked power info
565 bool is_power_data_invalid = false;
566 std::string power_rail;
567 bool high_power_check = false;
568 bool throttling_with_power_link = false;
569 CdevArray cdev_floor_with_power_link;
570 cdev_floor_with_power_link.fill(0);
571
572 const bool power_link_disabled =
573 android::base::GetBoolProperty(kPowerLinkDisabledProperty.data(), false);
574 if (!power_link_disabled) {
575 power_rail = values[j]["BindedPowerRail"].asString();
576
577 if (values[j]["HighPowerCheck"].asBool()) {
578 high_power_check = true;
579 }
580 LOG(INFO) << "Highpowercheck: " << std::boolalpha << high_power_check;
581
582 if (values[j]["ThrottlingWithPowerLink"].asBool()) {
583 throttling_with_power_link = true;
584 }
585 LOG(INFO) << "ThrottlingwithPowerLink: " << std::boolalpha
586 << throttling_with_power_link;
587
588 sub_values = values[j]["CdevFloorWithPowerLink"];
589 if (sub_values.size()) {
590 LOG(INFO) << "Sensor[" << name << "]: Start to parse " << cdev_name
591 << "'s CdevFloorWithPowerLink";
592 if (!getIntFromJsonValues(sub_values, &cdev_floor_with_power_link, false,
593 false)) {
594 LOG(ERROR) << "Failed to parse CdevFloor";
595 is_power_data_invalid = true;
596 }
597 }
598 sub_values = values[j]["PowerThreshold"];
599 if (sub_values.size()) {
600 LOG(INFO) << "Sensor[" << name << "]: Start to parse " << cdev_name
601 << "'s PowerThreshold";
602 if (!getFloatFromJsonValues(sub_values, &power_thresholds, false, false)) {
603 LOG(ERROR) << "Failed to parse power thresholds";
604 is_power_data_invalid = true;
605 }
606
607 if (values[j]["ReleaseLogic"].asString() == "INCREASE") {
608 release_logic = ReleaseLogic::INCREASE;
609 LOG(INFO) << "Release logic: INCREASE";
610 } else if (values[j]["ReleaseLogic"].asString() == "DECREASE") {
611 release_logic = ReleaseLogic::DECREASE;
612 LOG(INFO) << "Release logic: DECREASE";
613 } else if (values[j]["ReleaseLogic"].asString() == "STEPWISE") {
614 release_logic = ReleaseLogic::STEPWISE;
615 LOG(INFO) << "Release logic: STEPWISE";
616 } else if (values[j]["ReleaseLogic"].asString() == "RELEASE_TO_FLOOR") {
617 release_logic = ReleaseLogic::RELEASE_TO_FLOOR;
618 LOG(INFO) << "Release logic: RELEASE_TO_FLOOR";
619 } else {
620 LOG(ERROR) << "Release logic is invalid";
621 is_power_data_invalid = true;
622 }
623
624 if (is_power_data_invalid) {
625 LOG(ERROR) << cdev_name << "'s power rail " << power_rail << " is invalid";
626 sensors_parsed.clear();
627 return sensors_parsed;
628 }
629 }
630 }
631
632 binded_cdev_info_map[cdev_name] = {
633 .limit_info = limit_info,
634 .power_thresholds = power_thresholds,
635 .release_logic = release_logic,
636 .high_power_check = high_power_check,
637 .throttling_with_power_link = throttling_with_power_link,
638 .cdev_weight_for_pid = cdev_weight_for_pid,
639 .cdev_ceiling = cdev_ceiling,
640 .cdev_floor_with_power_link = cdev_floor_with_power_link,
641 .power_rail = power_rail,
642 };
643 }
644
645 bool is_monitor = (send_cb | send_powerhint | support_pid | support_hard_limit);
646 LOG(INFO) << "Sensor[" << name << "]'s Monitor: " << std::boolalpha << is_monitor;
647
648 std::unique_ptr<VirtualSensorInfo> virtual_sensor_info;
649 if (is_virtual_sensor) {
650 virtual_sensor_info.reset(new VirtualSensorInfo{linked_sensors, coefficients, offset,
651 trigger_sensor, formula});
652 }
653
654 std::unique_ptr<ThrottlingInfo> throttling_info(
655 new ThrottlingInfo{k_po, k_pu, k_i, k_d, i_max, max_alloc_power, min_alloc_power,
656 s_power, i_cutoff, binded_cdev_info_map});
657
658 sensors_parsed[name] = {
659 .type = sensor_type,
660 .hot_thresholds = hot_thresholds,
661 .cold_thresholds = cold_thresholds,
662 .hot_hysteresis = hot_hysteresis,
663 .cold_hysteresis = cold_hysteresis,
664 .temp_path = temp_path,
665 .vr_threshold = vr_threshold,
666 .multiplier = multiplier,
667 .polling_delay = polling_delay,
668 .passive_delay = passive_delay,
669 .send_cb = send_cb,
670 .send_powerhint = send_powerhint,
671 .is_monitor = is_monitor,
672 .virtual_sensor_info = std::move(virtual_sensor_info),
673 .throttling_info = std::move(throttling_info),
674 };
675
676 ++total_parsed;
677 }
678
679 LOG(INFO) << total_parsed << " Sensors parsed successfully";
680 return sensors_parsed;
681 }
682
ParseCoolingDevice(std::string_view config_path)683 std::unordered_map<std::string, CdevInfo> ParseCoolingDevice(std::string_view config_path) {
684 std::string json_doc;
685 std::unordered_map<std::string, CdevInfo> cooling_devices_parsed;
686 if (!android::base::ReadFileToString(config_path.data(), &json_doc)) {
687 LOG(ERROR) << "Failed to read JSON config from " << config_path;
688 return cooling_devices_parsed;
689 }
690
691 Json::Value root;
692 Json::CharReaderBuilder builder;
693 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
694 std::string errorMessage;
695
696 if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
697 LOG(ERROR) << "Failed to parse JSON config";
698 return cooling_devices_parsed;
699 }
700
701 Json::Value cooling_devices = root["CoolingDevices"];
702 std::size_t total_parsed = 0;
703 std::unordered_set<std::string> cooling_devices_name_parsed;
704
705 for (Json::Value::ArrayIndex i = 0; i < cooling_devices.size(); ++i) {
706 const std::string &name = cooling_devices[i]["Name"].asString();
707 LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name;
708 if (name.empty()) {
709 LOG(ERROR) << "Failed to read "
710 << "CoolingDevice[" << i << "]'s Name";
711 cooling_devices_parsed.clear();
712 return cooling_devices_parsed;
713 }
714
715 auto result = cooling_devices_name_parsed.insert(name.data());
716 if (!result.second) {
717 LOG(ERROR) << "Duplicate CoolingDevice[" << i << "]'s Name";
718 cooling_devices_parsed.clear();
719 return cooling_devices_parsed;
720 }
721
722 std::string cooling_device_type_str = cooling_devices[i]["Type"].asString();
723 LOG(INFO) << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str;
724 CoolingType cooling_device_type;
725
726 if (!getTypeFromString(cooling_device_type_str, &cooling_device_type)) {
727 LOG(ERROR) << "Invalid "
728 << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str;
729 cooling_devices_parsed.clear();
730 return cooling_devices_parsed;
731 }
732
733 const std::string &read_path = cooling_devices[i]["ReadPath"].asString();
734 LOG(INFO) << "Cdev Read Path: " << (read_path.empty() ? "default" : read_path);
735
736 const std::string &write_path = cooling_devices[i]["WritePath"].asString();
737 LOG(INFO) << "Cdev Write Path: " << (write_path.empty() ? "default" : write_path);
738
739 std::vector<float> state2power;
740 Json::Value values = cooling_devices[i]["State2Power"];
741 if (values.size()) {
742 state2power.reserve(values.size());
743 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
744 state2power.emplace_back(getFloatFromValue(values[j]));
745 LOG(INFO) << "Cooling device[" << name << "]'s Power2State[" << j
746 << "]: " << state2power[j];
747 }
748 } else {
749 LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name
750 << " does not support Power2State";
751 }
752
753 const std::string &power_rail = cooling_devices[i]["PowerRail"].asString();
754 LOG(INFO) << "Cooling device power rail : " << power_rail;
755
756 cooling_devices_parsed[name] = {
757 .type = cooling_device_type,
758 .read_path = read_path,
759 .write_path = write_path,
760 .state2power = state2power,
761 };
762 ++total_parsed;
763 }
764
765 LOG(INFO) << total_parsed << " CoolingDevices parsed successfully";
766 return cooling_devices_parsed;
767 }
768
ParsePowerRailInfo(std::string_view config_path)769 std::unordered_map<std::string, PowerRailInfo> ParsePowerRailInfo(std::string_view config_path) {
770 std::string json_doc;
771 std::unordered_map<std::string, PowerRailInfo> power_rails_parsed;
772 if (!android::base::ReadFileToString(config_path.data(), &json_doc)) {
773 LOG(ERROR) << "Failed to read JSON config from " << config_path;
774 return power_rails_parsed;
775 }
776
777 Json::Value root;
778 Json::CharReaderBuilder builder;
779 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
780 std::string errorMessage;
781
782 if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
783 LOG(ERROR) << "Failed to parse JSON config";
784 return power_rails_parsed;
785 }
786
787 Json::Value power_rails = root["PowerRails"];
788 std::size_t total_parsed = 0;
789 std::unordered_set<std::string> power_rails_name_parsed;
790
791 for (Json::Value::ArrayIndex i = 0; i < power_rails.size(); ++i) {
792 const std::string &name = power_rails[i]["Name"].asString();
793 LOG(INFO) << "PowerRail[" << i << "]'s Name: " << name;
794 if (name.empty()) {
795 LOG(ERROR) << "Failed to read "
796 << "PowerRail[" << i << "]'s Name";
797 power_rails_parsed.clear();
798 return power_rails_parsed;
799 }
800
801 std::string rail;
802 if (power_rails[i]["Rail"].empty()) {
803 rail = name;
804 } else {
805 rail = power_rails[i]["Rail"].asString();
806 }
807 LOG(INFO) << "PowerRail[" << i << "]'s Rail: " << rail;
808
809 std::vector<std::string> linked_power_rails;
810 std::vector<float> coefficients;
811 float offset = 0;
812 FormulaOption formula = FormulaOption::COUNT_THRESHOLD;
813 bool is_virtual_power_rail = false;
814 Json::Value values;
815 int power_sample_count = 0;
816 std::chrono::milliseconds power_sample_delay;
817
818 if (!power_rails[i]["VirtualRails"].empty() && power_rails[i]["VirtualRails"].isBool()) {
819 is_virtual_power_rail = power_rails[i]["VirtualRails"].asBool();
820 LOG(INFO) << "PowerRails[" << name << "]'s VirtualRail, set to 'true'";
821 }
822
823 if (is_virtual_power_rail) {
824 values = power_rails[i]["Combination"];
825 if (values.size()) {
826 linked_power_rails.reserve(values.size());
827 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
828 linked_power_rails.emplace_back(values[j].asString());
829 LOG(INFO) << "PowerRail[" << name << "]'s combination[" << j
830 << "]: " << linked_power_rails[j];
831 }
832 } else {
833 power_rails_parsed.clear();
834 return power_rails_parsed;
835 }
836
837 values = power_rails[i]["Coefficient"];
838 if (values.size()) {
839 coefficients.reserve(values.size());
840 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
841 coefficients.emplace_back(getFloatFromValue(values[j]));
842 LOG(INFO) << "PowerRail[" << name << "]'s coefficient[" << j
843 << "]: " << coefficients[j];
844 }
845 } else {
846 power_rails_parsed.clear();
847 return power_rails_parsed;
848 }
849
850 if (!power_rails[i]["Offset"].empty()) {
851 offset = power_rails[i]["Offset"].asFloat();
852 }
853
854 if (linked_power_rails.size() != coefficients.size()) {
855 power_rails_parsed.clear();
856 return power_rails_parsed;
857 }
858
859 if (power_rails[i]["Formula"].asString().compare("COUNT_THRESHOLD") == 0) {
860 formula = FormulaOption::COUNT_THRESHOLD;
861 } else if (power_rails[i]["Formula"].asString().compare("WEIGHTED_AVG") == 0) {
862 formula = FormulaOption::WEIGHTED_AVG;
863 } else if (power_rails[i]["Formula"].asString().compare("MAXIMUM") == 0) {
864 formula = FormulaOption::MAXIMUM;
865 } else if (power_rails[i]["Formula"].asString().compare("MINIMUM") == 0) {
866 formula = FormulaOption::MINIMUM;
867 } else {
868 power_rails_parsed.clear();
869 return power_rails_parsed;
870 }
871 }
872
873 std::unique_ptr<VirtualPowerRailInfo> virtual_power_rail_info;
874 if (is_virtual_power_rail) {
875 virtual_power_rail_info.reset(
876 new VirtualPowerRailInfo{linked_power_rails, coefficients, offset, formula});
877 }
878
879 power_sample_count = power_rails[i]["PowerSampleCount"].asInt();
880 LOG(INFO) << "Power sample Count: " << power_sample_count;
881
882 if (!power_rails[i]["PowerSampleDelay"]) {
883 power_sample_delay = std::chrono::milliseconds::max();
884 } else {
885 power_sample_delay =
886 std::chrono::milliseconds(getIntFromValue(power_rails[i]["PowerSampleDelay"]));
887 }
888
889 power_rails_parsed[name] = {
890 .rail = rail,
891 .power_sample_count = power_sample_count,
892 .power_sample_delay = power_sample_delay,
893 .virtual_power_rail_info = std::move(virtual_power_rail_info),
894 };
895 ++total_parsed;
896 }
897
898 LOG(INFO) << total_parsed << " PowerRails parsed successfully";
899 return power_rails_parsed;
900 }
901
902 } // namespace implementation
903 } // namespace V2_0
904 } // namespace thermal
905 } // namespace hardware
906 } // namespace android
907