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 #define ATRACE_TAG (ATRACE_TAG_THERMAL | ATRACE_TAG_HAL)
17
18 #include "thermal-helper.h"
19
20 #include <android-base/file.h>
21 #include <android-base/logging.h>
22 #include <android-base/properties.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/strings.h>
25 #include <utils/Trace.h>
26
27 #include <iterator>
28 #include <set>
29 #include <sstream>
30 #include <thread>
31 #include <vector>
32
33 namespace aidl {
34 namespace android {
35 namespace hardware {
36 namespace thermal {
37 namespace implementation {
38
39 constexpr std::string_view kThermalSensorsRoot("/sys/devices/virtual/thermal");
40 constexpr std::string_view kSensorPrefix("thermal_zone");
41 constexpr std::string_view kCoolingDevicePrefix("cooling_device");
42 constexpr std::string_view kThermalNameFile("type");
43 constexpr std::string_view kSensorPolicyFile("policy");
44 constexpr std::string_view kSensorTempSuffix("temp");
45 constexpr std::string_view kSensorTripPointTempZeroFile("trip_point_0_temp");
46 constexpr std::string_view kSensorTripPointHystZeroFile("trip_point_0_hyst");
47 constexpr std::string_view kUserSpaceSuffix("user_space");
48 constexpr std::string_view kCoolingDeviceCurStateSuffix("cur_state");
49 constexpr std::string_view kCoolingDeviceMaxStateSuffix("max_state");
50 constexpr std::string_view kCoolingDeviceState2powerSuffix("state2power_table");
51 constexpr std::string_view kConfigProperty("vendor.thermal.config");
52 constexpr std::string_view kConfigDefaultFileName("thermal_info_config.json");
53 constexpr std::string_view kThermalGenlProperty("persist.vendor.enable.thermal.genl");
54 constexpr std::string_view kThermalDisabledProperty("vendor.disable.thermalhal.control");
55
56 namespace {
57 using ::android::base::StringPrintf;
58
parseThermalPathMap(std::string_view prefix)59 std::unordered_map<std::string, std::string> parseThermalPathMap(std::string_view prefix) {
60 std::unordered_map<std::string, std::string> path_map;
61 std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(kThermalSensorsRoot.data()), closedir);
62 if (!dir) {
63 return path_map;
64 }
65
66 // std::filesystem is not available for vendor yet
67 // see discussion: aosp/894015
68 while (struct dirent *dp = readdir(dir.get())) {
69 if (dp->d_type != DT_DIR) {
70 continue;
71 }
72
73 if (!::android::base::StartsWith(dp->d_name, prefix.data())) {
74 continue;
75 }
76
77 std::string path = ::android::base::StringPrintf("%s/%s/%s", kThermalSensorsRoot.data(),
78 dp->d_name, kThermalNameFile.data());
79 std::string name;
80 if (!::android::base::ReadFileToString(path, &name)) {
81 PLOG(ERROR) << "Failed to read from " << path;
82 continue;
83 }
84
85 path_map.emplace(
86 ::android::base::Trim(name),
87 ::android::base::StringPrintf("%s/%s", kThermalSensorsRoot.data(), dp->d_name));
88 }
89
90 return path_map;
91 }
92
93 } // namespace
94
95 // dump additional traces for a given sensor
dumpTraces(std::string_view sensor_name)96 void ThermalHelperImpl::dumpTraces(std::string_view sensor_name) {
97 if (!(sensor_info_map_.count(sensor_name.data()) &&
98 sensor_status_map_.count(sensor_name.data()))) {
99 LOG(ERROR) << sensor_name << " not part of sensor_info_map_ or sensor_status_map_";
100 return;
101 }
102
103 // add trace for current sensor
104 const auto &sensor_status = sensor_status_map_.at(sensor_name.data());
105 ATRACE_INT((sensor_name.data() + std::string("-cached")).c_str(),
106 static_cast<int>(sensor_status.thermal_cached.temp));
107
108 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
109 if (!sensor_info.virtual_sensor_info) {
110 return;
111 }
112
113 if (sensor_info.virtual_sensor_info->vt_estimator) {
114 sensor_info.virtual_sensor_info->vt_estimator->DumpTraces();
115 }
116
117 // dump traces for all dependent/linked sensors
118 for (const auto &linked_sensor : sensor_info.virtual_sensor_info->linked_sensors) {
119 dumpTraces(linked_sensor);
120 }
121 }
122
123 // If the cdev_ceiling is higher than CDEV max_state, cap the cdev_ceiling to max_state.
maxCoolingRequestCheck(std::unordered_map<std::string,BindedCdevInfo> * binded_cdev_info_map)124 void ThermalHelperImpl::maxCoolingRequestCheck(
125 std::unordered_map<std::string, BindedCdevInfo> *binded_cdev_info_map) {
126 for (auto &binded_cdev_info_pair : *binded_cdev_info_map) {
127 const auto &cdev_info = cooling_device_info_map_.at(binded_cdev_info_pair.first);
128 for (auto &cdev_ceiling : binded_cdev_info_pair.second.cdev_ceiling) {
129 if (cdev_ceiling > cdev_info.max_state) {
130 if (cdev_ceiling != std::numeric_limits<int>::max()) {
131 LOG(ERROR) << binded_cdev_info_pair.first << " cdev_ceiling:" << cdev_ceiling
132 << " is higher than max state:" << cdev_info.max_state;
133 }
134 cdev_ceiling = cdev_info.max_state;
135 }
136 }
137 }
138 }
139
140 /*
141 * Populate the sensor_name_to_file_map_ map by walking through the file tree,
142 * reading the type file and assigning the temp file path to the map. If we do
143 * not succeed, abort.
144 */
ThermalHelperImpl(const NotificationCallback & cb)145 ThermalHelperImpl::ThermalHelperImpl(const NotificationCallback &cb)
146 : thermal_watcher_(new ThermalWatcher(std::bind(&ThermalHelperImpl::thermalWatcherCallbackFunc,
147 this, std::placeholders::_1))),
148 cb_(cb) {
149 const std::string config_path =
150 "/vendor/etc/" +
151 ::android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data());
152 bool thermal_throttling_disabled =
153 ::android::base::GetBoolProperty(kThermalDisabledProperty.data(), false);
154 bool ret = true;
155 Json::Value config;
156 std::unordered_set<std::string> loaded_config_paths;
157 if (!ParseThermalConfig(config_path, &config, &loaded_config_paths)) {
158 LOG(ERROR) << "Failed to read JSON config";
159 ret = false;
160 }
161
162 const std::string &comment = config["Comment"].asString();
163 LOG(INFO) << "Comment: " << comment;
164
165 if (!ParseCoolingDevice(config, &cooling_device_info_map_)) {
166 LOG(ERROR) << "Failed to parse cooling device info config";
167 ret = false;
168 }
169
170 if (!ParseSensorInfo(config, &sensor_info_map_)) {
171 LOG(ERROR) << "Failed to parse sensor info config";
172 ret = false;
173 }
174
175 auto tz_map = parseThermalPathMap(kSensorPrefix.data());
176 if (!initializeSensorMap(tz_map)) {
177 LOG(ERROR) << "Failed to initialize sensor map";
178 ret = false;
179 }
180
181 auto cdev_map = parseThermalPathMap(kCoolingDevicePrefix.data());
182 if (!initializeCoolingDevices(cdev_map)) {
183 LOG(ERROR) << "Failed to initialize cooling device map";
184 ret = false;
185 }
186
187 if (!power_files_.registerPowerRailsToWatch(config)) {
188 LOG(ERROR) << "Failed to register power rails";
189 ret = false;
190 }
191
192 if (!thermal_predictions_helper_.initializePredictionSensors(sensor_info_map_)) {
193 LOG(ERROR) << "Failed to initialize prediction sensors";
194 ret = false;
195 }
196
197 if (ret) {
198 if (!thermal_stats_helper_.initializeStats(config, sensor_info_map_,
199 cooling_device_info_map_, this)) {
200 LOG(FATAL) << "Failed to initialize thermal stats";
201 }
202 }
203
204 for (auto &name_status_pair : sensor_info_map_) {
205 sensor_status_map_[name_status_pair.first] = {
206 .severity = ThrottlingSeverity::NONE,
207 .prev_hot_severity = ThrottlingSeverity::NONE,
208 .prev_cold_severity = ThrottlingSeverity::NONE,
209 .last_update_time = boot_clock::time_point::min(),
210 .thermal_cached = {NAN, boot_clock::time_point::min()},
211 .pending_notification = false,
212 .override_status = {nullptr, false, false},
213 };
214
215 if (name_status_pair.second.throttling_info != nullptr) {
216 if (!thermal_throttling_.registerThermalThrottling(
217 name_status_pair.first, name_status_pair.second.throttling_info,
218 cooling_device_info_map_)) {
219 LOG(ERROR) << name_status_pair.first << " failed to register thermal throttling";
220 ret = false;
221 break;
222 }
223
224 // Update cooling device max state for default mode
225 maxCoolingRequestCheck(&name_status_pair.second.throttling_info->binded_cdev_info_map);
226
227 // Update cooling device max state for each profile mode
228 for (auto &cdev_throttling_profile_pair :
229 name_status_pair.second.throttling_info->profile_map) {
230 maxCoolingRequestCheck(&cdev_throttling_profile_pair.second);
231 }
232 }
233 // Check the virtual sensor settings are valid
234 if (name_status_pair.second.virtual_sensor_info != nullptr) {
235 // Check if sub sensor setting is valid
236 for (size_t i = 0;
237 i < name_status_pair.second.virtual_sensor_info->linked_sensors.size(); i++) {
238 if (!isSubSensorValid(
239 name_status_pair.second.virtual_sensor_info->linked_sensors[i],
240 name_status_pair.second.virtual_sensor_info->linked_sensors_type[i])) {
241 LOG(ERROR) << name_status_pair.first << "'s link sensor "
242 << name_status_pair.second.virtual_sensor_info->linked_sensors[i]
243 << " is invalid";
244 ret = false;
245 break;
246 }
247 }
248
249 // Check if the backup sensor is valid
250 if (!name_status_pair.second.virtual_sensor_info->backup_sensor.empty()) {
251 if (!isSubSensorValid(name_status_pair.second.virtual_sensor_info->backup_sensor,
252 SensorFusionType::SENSOR)) {
253 LOG(ERROR) << name_status_pair.first << "'s backup sensor "
254 << name_status_pair.second.virtual_sensor_info->backup_sensor
255 << " is invalid";
256 ret = false;
257 break;
258 }
259 }
260
261 // Check if the trigger sensor is valid
262 if (!name_status_pair.second.virtual_sensor_info->trigger_sensors.empty() &&
263 name_status_pair.second.is_watch) {
264 for (size_t i = 0;
265 i < name_status_pair.second.virtual_sensor_info->trigger_sensors.size(); i++) {
266 if (sensor_info_map_.count(
267 name_status_pair.second.virtual_sensor_info->trigger_sensors[i])) {
268 sensor_info_map_[name_status_pair.second.virtual_sensor_info
269 ->trigger_sensors[i]]
270 .is_watch = true;
271 } else {
272 LOG(ERROR)
273 << name_status_pair.first << "'s trigger sensor: "
274 << name_status_pair.second.virtual_sensor_info->trigger_sensors[i]
275 << " is invalid";
276 ret = false;
277 break;
278 }
279 }
280 }
281
282 // Check if the severity reference sensor is valid
283 if (name_status_pair.second.severity_reference != "") {
284 if (sensor_info_map_.contains(name_status_pair.second.severity_reference)) {
285 sensor_info_map_[name_status_pair.second.severity_reference].is_watch = true;
286 LOG(INFO) << "Enable is_watch for " << name_status_pair.first
287 << "'s severity reference sensor: "
288 << name_status_pair.second.severity_reference;
289 } else {
290 LOG(ERROR) << name_status_pair.first << "'s severity reference sensor: "
291 << name_status_pair.second.severity_reference << " is invalid";
292 ret = false;
293 }
294 }
295 }
296 // Check predictor info config
297 if ((name_status_pair.second.predictor_info != nullptr) &&
298 name_status_pair.second.predictor_info->support_pid_compensation) {
299 std::string predict_sensor_name = name_status_pair.second.predictor_info->sensor;
300 if (!(sensor_info_map_.count(predict_sensor_name))) {
301 LOG(ERROR) << name_status_pair.first << "'s predictor " << predict_sensor_name
302 << " is not part of sensor_info_map_";
303 ret = false;
304 break;
305 }
306
307 const auto &predictor_sensor_info = sensor_info_map_.at(predict_sensor_name);
308 if (predictor_sensor_info.virtual_sensor_info == nullptr ||
309 predictor_sensor_info.virtual_sensor_info->vt_estimator == nullptr) {
310 LOG(ERROR) << name_status_pair.first << "'s predictor " << predict_sensor_name
311 << " does not support prediction";
312 ret = false;
313 break;
314 }
315
316 std::vector<float> output_template;
317 size_t prediction_weight_count =
318 name_status_pair.second.predictor_info->prediction_weights.size();
319 // read predictor out to get the size of output vector
320 ::thermal::vtestimator::VtEstimatorStatus predict_check =
321 predictor_sensor_info.virtual_sensor_info->vt_estimator->GetAllPredictions(
322 &output_template);
323
324 if (predict_check != ::thermal::vtestimator::kVtEstimatorOk) {
325 LOG(ERROR) << "Failed to get output size of " << name_status_pair.first
326 << "'s predictor " << predict_sensor_name
327 << " GetAllPredictions ret: " << ret << ")";
328 ret = false;
329 break;
330 }
331
332 if (prediction_weight_count != output_template.size()) {
333 LOG(ERROR) << "Sensor [" << name_status_pair.first
334 << "]: " << "prediction weights size (" << prediction_weight_count
335 << ") doesn't match predictor [" << predict_sensor_name
336 << "]'s output size (" << output_template.size() << ")";
337 ret = false;
338 break;
339 }
340 }
341 }
342
343 if (!power_hal_service_.connect()) {
344 LOG(ERROR) << "Fail to connect to Power Hal";
345 } else {
346 power_hal_service_.updateSupportedPowerHints(sensor_info_map_);
347 }
348
349 if (thermal_throttling_disabled) {
350 if (ret) {
351 clearAllThrottling();
352 is_initialized_ = ret;
353 return;
354 } else {
355 sensor_info_map_.clear();
356 cooling_device_info_map_.clear();
357 return;
358 }
359 } else if (!ret) {
360 LOG(FATAL) << "ThermalHAL could not be initialized properly.";
361 }
362 is_initialized_ = ret;
363
364 const bool thermal_genl_enabled =
365 ::android::base::GetBoolProperty(kThermalGenlProperty.data(), false);
366
367 std::set<std::string> monitored_sensors;
368 initializeTrip(tz_map, &monitored_sensors, thermal_genl_enabled);
369
370 if (thermal_genl_enabled) {
371 thermal_watcher_->registerFilesToWatchNl(monitored_sensors);
372 } else {
373 thermal_watcher_->registerFilesToWatch(monitored_sensors);
374 }
375
376 // Need start watching after status map initialized
377 is_initialized_ = thermal_watcher_->startWatchingDeviceFiles();
378 if (!is_initialized_) {
379 LOG(FATAL) << "ThermalHAL could not start watching thread properly.";
380 }
381 }
382
getThermalZoneTypeById(int tz_id,std::string * type)383 bool getThermalZoneTypeById(int tz_id, std::string *type) {
384 std::string tz_type;
385 std::string path =
386 ::android::base::StringPrintf("%s/%s%d/%s", kThermalSensorsRoot.data(),
387 kSensorPrefix.data(), tz_id, kThermalNameFile.data());
388 if (!::android::base::ReadFileToString(path, &tz_type)) {
389 LOG(ERROR) << "Failed to read sensor from: " << path;
390 return false;
391 }
392
393 // Strip the newline.
394 *type = ::android::base::Trim(tz_type);
395 LOG(INFO) << "TZ path: " << path << " type: " << *type;
396 return true;
397 }
398
checkUpdateSensorForEmul(std::string_view target_sensor,const bool max_throttling)399 void ThermalHelperImpl::checkUpdateSensorForEmul(std::string_view target_sensor,
400 const bool max_throttling) {
401 // Force update all the sensors which are related to the target emul sensor
402 for (auto &[sensor_name, sensor_info] : sensor_info_map_) {
403 if (sensor_info.virtual_sensor_info == nullptr || !sensor_info.is_watch) {
404 continue;
405 }
406
407 const auto &linked_sensors = sensor_info.virtual_sensor_info->linked_sensors;
408 if (std::find(linked_sensors.begin(), linked_sensors.end(), target_sensor) ==
409 linked_sensors.end()) {
410 continue;
411 }
412
413 auto &sensor_status = sensor_status_map_.at(sensor_name.data());
414 sensor_status.override_status.max_throttling = max_throttling;
415 sensor_status.override_status.pending_update = true;
416
417 checkUpdateSensorForEmul(sensor_name, max_throttling);
418 }
419 }
420
emulTemp(std::string_view target_sensor,const float temp,const bool max_throttling)421 bool ThermalHelperImpl::emulTemp(std::string_view target_sensor, const float temp,
422 const bool max_throttling) {
423 LOG(INFO) << "Set " << target_sensor.data() << " emul_temp: " << temp
424 << " max_throttling: " << max_throttling;
425
426 std::lock_guard<std::shared_mutex> _lock(sensor_status_map_mutex_);
427
428 // Check the target sensor is valid
429 if (!sensor_status_map_.count(target_sensor.data())) {
430 LOG(ERROR) << "Cannot find target emul sensor: " << target_sensor.data();
431 return false;
432 }
433
434 auto &sensor_status = sensor_status_map_.at(target_sensor.data());
435
436 sensor_status.override_status.emul_temp.reset(new EmulTemp{temp, -1});
437 sensor_status.override_status.max_throttling = max_throttling;
438 sensor_status.override_status.pending_update = true;
439
440 checkUpdateSensorForEmul(target_sensor.data(), max_throttling);
441
442 thermal_watcher_->wake();
443 return true;
444 }
445
emulSeverity(std::string_view target_sensor,const int severity,const bool max_throttling)446 bool ThermalHelperImpl::emulSeverity(std::string_view target_sensor, const int severity,
447 const bool max_throttling) {
448 LOG(INFO) << "Set " << target_sensor.data() << " emul_severity: " << severity
449 << " max_throttling: " << max_throttling;
450
451 std::lock_guard<std::shared_mutex> _lock(sensor_status_map_mutex_);
452 // Check the target sensor is valid
453 if (!sensor_status_map_.count(target_sensor.data()) ||
454 !sensor_info_map_.count(target_sensor.data())) {
455 LOG(ERROR) << "Cannot find target emul sensor: " << target_sensor.data();
456 return false;
457 }
458 const auto &sensor_info = sensor_info_map_.at(target_sensor.data());
459
460 // Check the emul severity is valid
461 if (severity > static_cast<int>(kThrottlingSeverityCount)) {
462 LOG(ERROR) << "Invalid emul severity value " << severity;
463 return false;
464 }
465
466 const auto temp = sensor_info.hot_thresholds[severity] / sensor_info.multiplier;
467
468 auto &sensor_status = sensor_status_map_.at(target_sensor.data());
469
470 sensor_status.override_status.emul_temp.reset(new EmulTemp{temp, severity});
471 sensor_status.override_status.max_throttling = max_throttling;
472 sensor_status.override_status.pending_update = true;
473
474 checkUpdateSensorForEmul(target_sensor.data(), max_throttling);
475
476 thermal_watcher_->wake();
477 return true;
478 }
479
emulClear(std::string_view target_sensor)480 bool ThermalHelperImpl::emulClear(std::string_view target_sensor) {
481 LOG(INFO) << "Clear " << target_sensor.data() << " emulation settings";
482
483 std::lock_guard<std::shared_mutex> _lock(sensor_status_map_mutex_);
484 if (target_sensor == "all") {
485 for (auto &[sensor_name, sensor_status] : sensor_status_map_) {
486 sensor_status.override_status = {
487 .emul_temp = nullptr, .max_throttling = false, .pending_update = true};
488 checkUpdateSensorForEmul(sensor_name, false);
489 }
490 } else if (sensor_status_map_.count(target_sensor.data())) {
491 auto &sensor_status = sensor_status_map_.at(target_sensor.data());
492 sensor_status.override_status = {
493 .emul_temp = nullptr, .max_throttling = false, .pending_update = true};
494 checkUpdateSensorForEmul(target_sensor.data(), false);
495 } else {
496 LOG(ERROR) << "Cannot find target emul sensor: " << target_sensor.data();
497 return false;
498 }
499
500 thermal_watcher_->wake();
501 return true;
502 }
503
readCoolingDevice(std::string_view cooling_device,CoolingDevice * out) const504 bool ThermalHelperImpl::readCoolingDevice(std::string_view cooling_device,
505 CoolingDevice *out) const {
506 // Read the file. If the file can't be read temp will be empty string.
507 std::string data;
508
509 if (!cooling_devices_.readThermalFile(cooling_device, &data)) {
510 LOG(ERROR) << "readCoolingDevice: failed to read cooling_device: " << cooling_device;
511 return false;
512 }
513
514 const CdevInfo &cdev_info = cooling_device_info_map_.at(cooling_device.data());
515 const CoolingType &type = cdev_info.type;
516
517 out->type = type;
518 out->name = cooling_device.data();
519 out->value = std::stoi(data);
520
521 return true;
522 }
523
readTemperature(std::string_view sensor_name,Temperature * out,const bool force_no_cache)524 SensorReadStatus ThermalHelperImpl::readTemperature(std::string_view sensor_name, Temperature *out,
525 const bool force_no_cache) {
526 // Return fail if the thermal sensor cannot be read.
527 float temp = NAN;
528 std::map<std::string, float> sensor_log_map;
529 auto &sensor_status = sensor_status_map_.at(sensor_name.data());
530
531 const auto ret = readThermalSensor(sensor_name, &temp, force_no_cache, &sensor_log_map);
532 if (ret == SensorReadStatus::ERROR) {
533 LOG(ERROR) << "Failed to read thermal sensor " << sensor_name.data();
534 thermal_stats_helper_.reportThermalAbnormality(
535 ThermalSensorAbnormalityDetected::TEMP_READ_FAIL, sensor_name, std::nullopt);
536 return SensorReadStatus::ERROR;
537 }
538
539 if (ret == SensorReadStatus::UNDER_COLLECTING) {
540 LOG(INFO) << "Thermal sensor " << sensor_name.data() << " is under collecting";
541 return SensorReadStatus::UNDER_COLLECTING;
542 }
543
544 if (std::isnan(temp)) {
545 LOG(INFO) << "Sensor " << sensor_name.data() << " temperature is nan.";
546 return SensorReadStatus::ERROR;
547 }
548 const auto severity_reference = getSeverityReference(sensor_name.data());
549
550 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
551 out->type = sensor_info.type;
552 out->name = sensor_name.data();
553 out->value = temp * sensor_info.multiplier;
554
555 std::pair<ThrottlingSeverity, ThrottlingSeverity> status =
556 std::make_pair(ThrottlingSeverity::NONE, ThrottlingSeverity::NONE);
557
558 // Only update status if the thermal sensor is being monitored
559 if (!sensor_info.is_watch) {
560 return SensorReadStatus::OKAY;
561 }
562 ThrottlingSeverity prev_hot_severity, prev_cold_severity;
563 {
564 std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
565 prev_hot_severity = sensor_status.prev_hot_severity;
566 prev_cold_severity = sensor_status.prev_cold_severity;
567 status = getSeverityFromThresholds(sensor_info.hot_thresholds, sensor_info.cold_thresholds,
568 sensor_info.hot_hysteresis, sensor_info.cold_hysteresis,
569 prev_hot_severity, prev_cold_severity, out->value);
570
571 out->throttlingStatus =
572 static_cast<size_t>(status.first) > static_cast<size_t>(status.second)
573 ? status.first
574 : status.second;
575
576 if (status.first != sensor_status.prev_hot_severity) {
577 sensor_status.prev_hot_severity = status.first;
578 }
579 if (status.second != sensor_status.prev_cold_severity) {
580 sensor_status.prev_cold_severity = status.second;
581 }
582
583 out->throttlingStatus = std::max(out->throttlingStatus, severity_reference);
584
585 if (sensor_status.override_status.emul_temp != nullptr &&
586 sensor_status.override_status.emul_temp->severity >= 0) {
587 out->throttlingStatus = static_cast<ThrottlingSeverity>(
588 sensor_status.override_status.emul_temp->severity);
589 }
590
591 if (sensor_status.severity != out->throttlingStatus) {
592 sensor_status.severity = out->throttlingStatus;
593 sensor_status.pending_notification = true;
594 }
595 }
596
597 std::ostringstream sensor_log;
598 for (const auto &sensor_log_pair : sensor_log_map) {
599 sensor_log << sensor_log_pair.first << ":" << sensor_log_pair.second << " ";
600 }
601 // Update sensor temperature time in state
602 thermal_stats_helper_.updateSensorTempStatsBySeverity(sensor_name, out->throttlingStatus);
603 if (out->throttlingStatus >= sensor_info.log_level) {
604 LOG(INFO) << sensor_name.data() << ":" << out->value << " raw data: " << sensor_log.str();
605 } else {
606 LOG(VERBOSE) << sensor_name.data() << ":" << out->value
607 << " raw data: " << sensor_log.str();
608 }
609 ATRACE_INT((sensor_name.data() + std::string("-severity")).c_str(),
610 static_cast<int>(out->throttlingStatus));
611
612 return SensorReadStatus::OKAY;
613 }
614
readTemperatureThreshold(std::string_view sensor_name,TemperatureThreshold * out) const615 bool ThermalHelperImpl::readTemperatureThreshold(std::string_view sensor_name,
616 TemperatureThreshold *out) const {
617 // Read the file. If the file can't be read temp will be empty string.
618 std::string temp;
619 std::string path;
620
621 if (!sensor_info_map_.count(sensor_name.data())) {
622 LOG(ERROR) << __func__ << ": sensor not found: " << sensor_name;
623 return false;
624 }
625
626 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
627
628 out->type = sensor_info.type;
629 out->name = sensor_name.data();
630 out->hotThrottlingThresholds =
631 std::vector(sensor_info.hot_thresholds.begin(), sensor_info.hot_thresholds.end());
632 out->coldThrottlingThresholds =
633 std::vector(sensor_info.cold_thresholds.begin(), sensor_info.cold_thresholds.end());
634 return true;
635 }
636
updateCoolingDevices(const std::vector<std::string> & updated_cdev)637 void ThermalHelperImpl::updateCoolingDevices(const std::vector<std::string> &updated_cdev) {
638 int max_state;
639
640 for (const auto &target_cdev : updated_cdev) {
641 if (thermal_throttling_.getCdevMaxRequest(target_cdev, &max_state)) {
642 if (cooling_devices_.writeCdevFile(target_cdev, std::to_string(max_state))) {
643 ATRACE_INT(target_cdev.c_str(), max_state);
644 LOG(INFO) << "Successfully update cdev " << target_cdev << " sysfs to "
645 << max_state;
646 } else {
647 LOG(ERROR) << "Failed to update cdev " << target_cdev << " sysfs to " << max_state;
648 }
649 }
650 }
651 }
652
getSeverityFromThresholds(const ThrottlingArray & hot_thresholds,const ThrottlingArray & cold_thresholds,const ThrottlingArray & hot_hysteresis,const ThrottlingArray & cold_hysteresis,ThrottlingSeverity prev_hot_severity,ThrottlingSeverity prev_cold_severity,float value) const653 std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelperImpl::getSeverityFromThresholds(
654 const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
655 const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
656 ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
657 float value) const {
658 ThrottlingSeverity ret_hot = ThrottlingSeverity::NONE;
659 ThrottlingSeverity ret_hot_hysteresis = ThrottlingSeverity::NONE;
660 ThrottlingSeverity ret_cold = ThrottlingSeverity::NONE;
661 ThrottlingSeverity ret_cold_hysteresis = ThrottlingSeverity::NONE;
662
663 // Here we want to control the iteration from high to low, and ::ndk::enum_range doesn't support
664 // a reverse iterator yet.
665 for (size_t i = static_cast<size_t>(ThrottlingSeverity::SHUTDOWN);
666 i > static_cast<size_t>(ThrottlingSeverity::NONE); --i) {
667 if (!std::isnan(hot_thresholds[i]) && hot_thresholds[i] <= value &&
668 ret_hot == ThrottlingSeverity::NONE) {
669 ret_hot = static_cast<ThrottlingSeverity>(i);
670 }
671 if (!std::isnan(hot_thresholds[i]) && (hot_thresholds[i] - hot_hysteresis[i]) < value &&
672 ret_hot_hysteresis == ThrottlingSeverity::NONE) {
673 ret_hot_hysteresis = static_cast<ThrottlingSeverity>(i);
674 }
675 if (!std::isnan(cold_thresholds[i]) && cold_thresholds[i] >= value &&
676 ret_cold == ThrottlingSeverity::NONE) {
677 ret_cold = static_cast<ThrottlingSeverity>(i);
678 }
679 if (!std::isnan(cold_thresholds[i]) && (cold_thresholds[i] + cold_hysteresis[i]) > value &&
680 ret_cold_hysteresis == ThrottlingSeverity::NONE) {
681 ret_cold_hysteresis = static_cast<ThrottlingSeverity>(i);
682 }
683 }
684 if (static_cast<size_t>(ret_hot) < static_cast<size_t>(prev_hot_severity)) {
685 ret_hot = ret_hot_hysteresis;
686 }
687 if (static_cast<size_t>(ret_cold) < static_cast<size_t>(prev_cold_severity)) {
688 ret_cold = ret_cold_hysteresis;
689 }
690
691 return std::make_pair(ret_hot, ret_cold);
692 }
693
isSubSensorValid(std::string_view sensor_data,const SensorFusionType sensor_fusion_type)694 bool ThermalHelperImpl::isSubSensorValid(std::string_view sensor_data,
695 const SensorFusionType sensor_fusion_type) {
696 switch (sensor_fusion_type) {
697 case SensorFusionType::SENSOR:
698 if (!sensor_info_map_.count(sensor_data.data())) {
699 LOG(ERROR) << "Cannot find " << sensor_data.data() << " from sensor info map";
700 return false;
701 }
702 break;
703 case SensorFusionType::ODPM:
704 if (!GetPowerStatusMap().count(sensor_data.data())) {
705 LOG(ERROR) << "Cannot find " << sensor_data.data() << " from power status map";
706 return false;
707 }
708 break;
709 default:
710 break;
711 }
712 return true;
713 }
714
clearAllThrottling(void)715 void ThermalHelperImpl::clearAllThrottling(void) {
716 // Clear the CDEV request
717 for (const auto &cdev_info_pair : cooling_device_info_map_) {
718 cooling_devices_.writeCdevFile(cdev_info_pair.first, "0");
719 }
720
721 for (auto &sensor_info_pair : sensor_info_map_) {
722 sensor_info_pair.second.is_watch = false;
723 sensor_info_pair.second.throttling_info.reset();
724 sensor_info_pair.second.hot_thresholds.fill(NAN);
725 sensor_info_pair.second.cold_thresholds.fill(NAN);
726 Temperature temp = {
727 .type = sensor_info_pair.second.type,
728 .name = sensor_info_pair.first,
729 .value = NAN,
730 .throttlingStatus = ThrottlingSeverity::NONE,
731 };
732 // Send callbacks with NONE severity
733 if (sensor_info_pair.second.send_cb && cb_) {
734 cb_(temp);
735 }
736 // Disable thermal power hints
737 if (sensor_info_pair.second.send_powerhint) {
738 for (const auto &severity : ::ndk::enum_range<ThrottlingSeverity>()) {
739 power_hal_service_.setMode(sensor_info_pair.first, severity, false);
740 }
741 }
742 }
743 }
744
initializeSensorMap(const std::unordered_map<std::string,std::string> & path_map)745 bool ThermalHelperImpl::initializeSensorMap(
746 const std::unordered_map<std::string, std::string> &path_map) {
747 for (const auto &sensor_info_pair : sensor_info_map_) {
748 std::string_view sensor_name = sensor_info_pair.first;
749 if (sensor_info_pair.second.virtual_sensor_info != nullptr) {
750 continue;
751 }
752 if (!path_map.count(sensor_name.data())) {
753 LOG(ERROR) << "Could not find " << sensor_name << " in sysfs";
754 return false;
755 }
756
757 std::string path;
758 if (sensor_info_pair.second.temp_path.empty()) {
759 path = ::android::base::StringPrintf("%s/%s", path_map.at(sensor_name.data()).c_str(),
760 kSensorTempSuffix.data());
761 } else {
762 path = sensor_info_pair.second.temp_path;
763 }
764
765 if (!thermal_sensors_.addThermalFile(sensor_name, path)) {
766 LOG(ERROR) << "Could not add " << sensor_name << "to sensors map";
767 return false;
768 }
769 }
770 return true;
771 }
772
initializeCoolingDevices(const std::unordered_map<std::string,std::string> & path_map)773 bool ThermalHelperImpl::initializeCoolingDevices(
774 const std::unordered_map<std::string, std::string> &path_map) {
775 for (auto &cooling_device_info_pair : cooling_device_info_map_) {
776 std::string cooling_device_name = cooling_device_info_pair.first;
777 if (!path_map.count(cooling_device_name)) {
778 LOG(ERROR) << "Could not find " << cooling_device_name << " in sysfs";
779 return false;
780 }
781 // Add cooling device path for thermalHAL to get current state
782 std::string_view path = path_map.at(cooling_device_name);
783 std::string read_path;
784 if (!cooling_device_info_pair.second.read_path.empty()) {
785 read_path = cooling_device_info_pair.second.read_path.data();
786 } else {
787 read_path = ::android::base::StringPrintf("%s/%s", path.data(),
788 kCoolingDeviceCurStateSuffix.data());
789 }
790 if (!cooling_devices_.addThermalFile(cooling_device_name, read_path)) {
791 LOG(ERROR) << "Could not add " << cooling_device_name
792 << " read path to cooling device map";
793 return false;
794 }
795
796 // Get cooling device state2power table from sysfs if not defined in config
797 if (!cooling_device_info_pair.second.state2power.size()) {
798 std::string state2power_path = ::android::base::StringPrintf(
799 "%s/%s", path.data(), kCoolingDeviceState2powerSuffix.data());
800 std::string state2power_str;
801 if (::android::base::ReadFileToString(state2power_path, &state2power_str)) {
802 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first
803 << " use State2power read from sysfs";
804 std::stringstream power(state2power_str);
805 unsigned int power_number;
806 while (power >> power_number) {
807 cooling_device_info_pair.second.state2power.push_back(
808 static_cast<float>(power_number));
809 }
810 }
811 }
812
813 // Check if there's any wrong ordered state2power value to avoid cdev stuck issue
814 for (size_t i = 0; i < cooling_device_info_pair.second.state2power.size(); ++i) {
815 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first << " state:" << i
816 << " power: " << cooling_device_info_pair.second.state2power[i];
817 if (i > 0 && cooling_device_info_pair.second.state2power[i] >
818 cooling_device_info_pair.second.state2power[i - 1]) {
819 LOG(ERROR) << "Higher power with higher state on cooling device "
820 << cooling_device_info_pair.first << "'s state" << i;
821 }
822 }
823
824 // Get max cooling device request state
825 std::string max_state;
826 std::string max_state_path = ::android::base::StringPrintf(
827 "%s/%s", path.data(), kCoolingDeviceMaxStateSuffix.data());
828 if (!::android::base::ReadFileToString(max_state_path, &max_state)) {
829 LOG(ERROR) << cooling_device_info_pair.first
830 << " could not open max state file:" << max_state_path;
831 cooling_device_info_pair.second.max_state = std::numeric_limits<int>::max();
832 } else {
833 cooling_device_info_pair.second.max_state = std::stoi(::android::base::Trim(max_state));
834 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first
835 << " max state: " << cooling_device_info_pair.second.max_state
836 << " state2power number: "
837 << cooling_device_info_pair.second.state2power.size();
838 if (cooling_device_info_pair.second.state2power.size() > 0 &&
839 static_cast<int>(cooling_device_info_pair.second.state2power.size()) !=
840 (cooling_device_info_pair.second.max_state + 1)) {
841 LOG(ERROR) << "Invalid state2power number: "
842 << cooling_device_info_pair.second.state2power.size()
843 << ", number should be " << cooling_device_info_pair.second.max_state + 1
844 << " (max_state + 1)";
845 }
846 }
847
848 // Add cooling device path for thermalHAL to request state
849 cooling_device_name =
850 ::android::base::StringPrintf("%s_%s", cooling_device_name.c_str(), "w");
851 std::string write_path;
852 if (!cooling_device_info_pair.second.write_path.empty()) {
853 write_path = cooling_device_info_pair.second.write_path.data();
854 } else {
855 write_path = ::android::base::StringPrintf("%s/%s", path.data(),
856 kCoolingDeviceCurStateSuffix.data());
857 }
858
859 if (!cooling_devices_.addThermalFile(cooling_device_name, write_path)) {
860 LOG(ERROR) << "Could not add " << cooling_device_name
861 << " write path to cooling device map";
862 return false;
863 }
864 }
865 return true;
866 }
867
setMinTimeout(SensorInfo * sensor_info)868 void ThermalHelperImpl::setMinTimeout(SensorInfo *sensor_info) {
869 sensor_info->polling_delay = kMinPollIntervalMs;
870 sensor_info->passive_delay = kMinPollIntervalMs;
871 }
872
initializeTrip(const std::unordered_map<std::string,std::string> & path_map,std::set<std::string> * monitored_sensors,bool thermal_genl_enabled)873 void ThermalHelperImpl::initializeTrip(const std::unordered_map<std::string, std::string> &path_map,
874 std::set<std::string> *monitored_sensors,
875 bool thermal_genl_enabled) {
876 for (auto &sensor_info : sensor_info_map_) {
877 if (!sensor_info.second.is_watch || (sensor_info.second.virtual_sensor_info != nullptr)) {
878 continue;
879 }
880
881 bool trip_update = false;
882 std::string_view sensor_name = sensor_info.first;
883 std::string_view tz_path = path_map.at(sensor_name.data());
884 std::string tz_policy;
885 std::string path =
886 ::android::base::StringPrintf("%s/%s", (tz_path.data()), kSensorPolicyFile.data());
887
888 if (thermal_genl_enabled) {
889 trip_update = true;
890 } else {
891 // Check if thermal zone support uevent notify
892 if (!::android::base::ReadFileToString(path, &tz_policy)) {
893 LOG(ERROR) << sensor_name << " could not open tz policy file:" << path;
894 } else {
895 tz_policy = ::android::base::Trim(tz_policy);
896 if (tz_policy != kUserSpaceSuffix) {
897 LOG(ERROR) << sensor_name << " does not support uevent notify";
898 } else {
899 trip_update = true;
900 }
901 }
902 }
903 if (trip_update) {
904 // Update thermal zone trip point
905 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
906 if (!std::isnan(sensor_info.second.hot_thresholds[i]) &&
907 !std::isnan(sensor_info.second.hot_hysteresis[i])) {
908 // Update trip_point_0_temp threshold
909 std::string threshold = std::to_string(std::lround(
910 sensor_info.second.hot_thresholds[i] / sensor_info.second.multiplier));
911 path = ::android::base::StringPrintf("%s/%s", (tz_path.data()),
912 kSensorTripPointTempZeroFile.data());
913 if (!::android::base::WriteStringToFile(threshold, path)) {
914 LOG(ERROR) << "fail to update " << sensor_name << " trip point: " << path
915 << " to " << threshold;
916 trip_update = false;
917 break;
918 }
919 // Update trip_point_0_hyst threshold
920 threshold = std::to_string(std::lround(sensor_info.second.hot_hysteresis[i] /
921 sensor_info.second.multiplier));
922 path = ::android::base::StringPrintf("%s/%s", (tz_path.data()),
923 kSensorTripPointHystZeroFile.data());
924 if (!::android::base::WriteStringToFile(threshold, path)) {
925 LOG(ERROR) << "fail to update " << sensor_name << "trip hyst" << threshold
926 << path;
927 trip_update = false;
928 break;
929 }
930 break;
931 } else if (i == kThrottlingSeverityCount - 1) {
932 LOG(ERROR) << sensor_name << ":all thresholds are NAN";
933 trip_update = false;
934 break;
935 }
936 }
937 monitored_sensors->insert(sensor_info.first);
938 }
939
940 if (!trip_update) {
941 LOG(INFO) << "config Sensor: " << sensor_info.first
942 << " to default polling interval: " << kMinPollIntervalMs.count();
943 setMinTimeout(&sensor_info.second);
944 }
945 }
946 }
947
fillCurrentTemperatures(bool filterType,bool filterCallback,TemperatureType type,std::vector<Temperature> * temperatures)948 bool ThermalHelperImpl::fillCurrentTemperatures(bool filterType, bool filterCallback,
949 TemperatureType type,
950 std::vector<Temperature> *temperatures) {
951 std::vector<Temperature> ret;
952 for (const auto &name_info_pair : sensor_info_map_) {
953 Temperature temp;
954 if (name_info_pair.second.is_hidden) {
955 continue;
956 }
957 if (filterType && name_info_pair.second.type != type) {
958 continue;
959 }
960 if (filterCallback && !name_info_pair.second.send_cb) {
961 continue;
962 }
963
964 const auto status = readTemperature(name_info_pair.first, &temp, false);
965 if (status == SensorReadStatus::OKAY) {
966 ret.emplace_back(std::move(temp));
967 } else if (status == SensorReadStatus::ERROR) {
968 LOG(ERROR) << __func__
969 << ": error reading temperature for sensor: " << name_info_pair.first;
970 }
971 }
972 *temperatures = ret;
973 return ret.size() > 0;
974 }
975
fillTemperatureThresholds(bool filterType,TemperatureType type,std::vector<TemperatureThreshold> * thresholds) const976 bool ThermalHelperImpl::fillTemperatureThresholds(
977 bool filterType, TemperatureType type,
978 std::vector<TemperatureThreshold> *thresholds) const {
979 std::vector<TemperatureThreshold> ret;
980 for (const auto &name_info_pair : sensor_info_map_) {
981 TemperatureThreshold temp;
982 if (name_info_pair.second.is_hidden) {
983 continue;
984 }
985 if (filterType && name_info_pair.second.type != type) {
986 continue;
987 }
988 if (readTemperatureThreshold(name_info_pair.first, &temp)) {
989 ret.emplace_back(std::move(temp));
990 } else {
991 LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
992 << name_info_pair.first;
993 return false;
994 }
995 }
996 *thresholds = ret;
997 return ret.size() > 0;
998 }
999
fillCurrentCoolingDevices(bool filterType,CoolingType type,std::vector<CoolingDevice> * cooling_devices) const1000 bool ThermalHelperImpl::fillCurrentCoolingDevices(
1001 bool filterType, CoolingType type, std::vector<CoolingDevice> *cooling_devices) const {
1002 std::vector<CoolingDevice> ret;
1003 for (const auto &name_info_pair : cooling_device_info_map_) {
1004 CoolingDevice value;
1005 if (filterType && name_info_pair.second.type != type) {
1006 continue;
1007 }
1008 if (readCoolingDevice(name_info_pair.first, &value)) {
1009 ret.emplace_back(std::move(value));
1010 } else {
1011 LOG(ERROR) << __func__ << ": error reading cooling device: " << name_info_pair.first;
1012 return false;
1013 }
1014 }
1015 *cooling_devices = ret;
1016 return ret.size() > 0;
1017 }
1018
getSeverityReference(std::string_view sensor_name)1019 ThrottlingSeverity ThermalHelperImpl::getSeverityReference(std::string_view sensor_name) {
1020 if (!sensor_info_map_.contains(sensor_name.data())) {
1021 return ThrottlingSeverity::NONE;
1022 }
1023 const std::string &severity_reference =
1024 sensor_info_map_.at(sensor_name.data()).severity_reference;
1025 if (severity_reference == "") {
1026 return ThrottlingSeverity::NONE;
1027 }
1028
1029 Temperature temp;
1030 if (readTemperature(severity_reference, &temp, false) != SensorReadStatus::OKAY) {
1031 return ThrottlingSeverity::NONE;
1032 }
1033 LOG(VERBOSE) << sensor_name << "'s severity reference " << severity_reference
1034 << " reading:" << toString(temp.throttlingStatus);
1035 return temp.throttlingStatus;
1036 }
1037
readDataByType(std::string_view sensor_data,float * reading_value,const SensorFusionType type,const bool force_no_cache,std::map<std::string,float> * sensor_log_map)1038 bool ThermalHelperImpl::readDataByType(std::string_view sensor_data, float *reading_value,
1039 const SensorFusionType type, const bool force_no_cache,
1040 std::map<std::string, float> *sensor_log_map) {
1041 switch (type) {
1042 case SensorFusionType::SENSOR:
1043 if (readThermalSensor(sensor_data.data(), reading_value, force_no_cache,
1044 sensor_log_map) == SensorReadStatus::ERROR) {
1045 LOG(ERROR) << "Failed to get " << sensor_data.data() << " data";
1046 return false;
1047 }
1048 break;
1049 case SensorFusionType::ODPM:
1050 *reading_value = GetPowerStatusMap().at(sensor_data.data()).last_updated_avg_power;
1051 if (std::isnan(*reading_value)) {
1052 LOG(INFO) << "Power data " << sensor_data.data() << " is under collecting";
1053 return true;
1054 }
1055 (*sensor_log_map)[sensor_data.data()] = *reading_value;
1056 break;
1057 case SensorFusionType::CONSTANT:
1058 *reading_value = std::atof(sensor_data.data());
1059 break;
1060 case SensorFusionType::CDEV:
1061 int max_state;
1062 if (thermal_throttling_.getCdevMaxRequest(sensor_data.data(), &max_state)) {
1063 *reading_value = max_state;
1064 break;
1065 } else {
1066 return false;
1067 }
1068 break;
1069 default:
1070 break;
1071 }
1072 return true;
1073 }
1074
runVirtualTempEstimator(std::string_view sensor_name,std::map<std::string,float> * sensor_log_map,const bool force_no_cache,std::vector<float> * outputs)1075 bool ThermalHelperImpl::runVirtualTempEstimator(std::string_view sensor_name,
1076 std::map<std::string, float> *sensor_log_map,
1077 const bool force_no_cache,
1078 std::vector<float> *outputs) {
1079 std::vector<float> model_inputs;
1080 std::vector<float> model_outputs;
1081
1082 ATRACE_NAME(StringPrintf("ThermalHelper::runVirtualTempEstimator - %s", sensor_name.data())
1083 .c_str());
1084 if (!(sensor_info_map_.count(sensor_name.data()) &&
1085 sensor_status_map_.count(sensor_name.data()))) {
1086 LOG(ERROR) << sensor_name << " not part of sensor_info_map_ or sensor_status_map_";
1087 return false;
1088 }
1089
1090 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
1091 if (sensor_info.virtual_sensor_info == nullptr ||
1092 sensor_info.virtual_sensor_info->vt_estimator == nullptr) {
1093 LOG(ERROR) << "vt_estimator not valid for " << sensor_name;
1094 return false;
1095 }
1096
1097 if (outputs == nullptr) {
1098 LOG(ERROR) << "vt_estimator output is nullptr";
1099 return false;
1100 }
1101
1102 model_inputs.reserve(sensor_info.virtual_sensor_info->linked_sensors.size());
1103
1104 for (size_t i = 0; i < sensor_info.virtual_sensor_info->linked_sensors.size(); i++) {
1105 std::string linked_sensor = sensor_info.virtual_sensor_info->linked_sensors[i];
1106
1107 if ((*sensor_log_map).count(linked_sensor.data())) {
1108 float value = (*sensor_log_map)[linked_sensor.data()];
1109 model_inputs.push_back(value);
1110 } else {
1111 LOG(ERROR) << "failed to read sensor: " << linked_sensor;
1112 return false;
1113 }
1114 }
1115
1116 ::thermal::vtestimator::VtEstimatorStatus ret =
1117 sensor_info.virtual_sensor_info->vt_estimator->Estimate(model_inputs, &model_outputs);
1118
1119 if (ret == ::thermal::vtestimator::kVtEstimatorOk) {
1120 if (sensor_info.predictor_info && sensor_info.predictor_info->supports_predictions) {
1121 thermal_predictions_helper_.updateSensor(sensor_name, model_outputs);
1122 }
1123 *outputs = model_outputs;
1124 return true;
1125 } else if (ret == ::thermal::vtestimator::kVtEstimatorLowConfidence ||
1126 ret == ::thermal::vtestimator::kVtEstimatorUnderSampling) {
1127 std::string_view backup_sensor = sensor_info.virtual_sensor_info->backup_sensor;
1128 float backup_sensor_vt;
1129 if (backup_sensor.empty()) {
1130 LOG(ERROR) << "Failed to run estimator (ret: " << ret << ") for " << sensor_name
1131 << " with no backup.";
1132 return false;
1133 }
1134 LOG(INFO) << "VT Estimator returned (ret: " << ret << ") for " << sensor_name
1135 << ". Reading backup sensor [" << backup_sensor << "] data to use";
1136 if (!readDataByType(backup_sensor, &backup_sensor_vt, SensorFusionType::SENSOR,
1137 force_no_cache, sensor_log_map)) {
1138 LOG(ERROR) << "Failed to read " << sensor_name.data() << "'s backup sensor "
1139 << backup_sensor;
1140 return false;
1141 }
1142 model_outputs.clear();
1143 model_outputs.push_back(backup_sensor_vt);
1144 *outputs = model_outputs;
1145 return true;
1146 }
1147
1148 LOG(ERROR) << "Failed to run estimator (ret: " << ret << ") for " << sensor_name;
1149 return false;
1150 }
1151
dumpVtEstimatorStatus(std::string_view sensor_name,std::ostringstream * dump_buf) const1152 void ThermalHelperImpl::dumpVtEstimatorStatus(std::string_view sensor_name,
1153 std::ostringstream *dump_buf) const {
1154 if (!(sensor_info_map_.count(sensor_name.data()) &&
1155 sensor_status_map_.count(sensor_name.data()))) {
1156 LOG(ERROR) << sensor_name << " not part of sensor_info_map_ or sensor_status_map_";
1157 return;
1158 }
1159
1160 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
1161 if (sensor_info.virtual_sensor_info == nullptr ||
1162 sensor_info.virtual_sensor_info->vt_estimator == nullptr) {
1163 return;
1164 }
1165
1166 sensor_info.virtual_sensor_info->vt_estimator->DumpStatus(sensor_name, dump_buf);
1167 }
1168
getPredictionMaxWindowMs(std::string_view sensor_name)1169 size_t ThermalHelperImpl::getPredictionMaxWindowMs(std::string_view sensor_name) {
1170 size_t predict_window = 0;
1171
1172 ATRACE_NAME(StringPrintf("ThermalHelper::getPredictionMaxWindowMs - %s", sensor_name.data())
1173 .c_str());
1174
1175 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
1176 if (sensor_info.predictor_info == nullptr) {
1177 LOG(ERROR) << "No predictor info found for sensor: " << sensor_name;
1178 return 0;
1179 }
1180
1181 std::string_view predict_sensor_name = sensor_info.predictor_info->sensor;
1182 const auto &predictor_sensor_info = sensor_info_map_.at(predict_sensor_name.data());
1183 ::thermal::vtestimator::VtEstimatorStatus ret =
1184 predictor_sensor_info.virtual_sensor_info->vt_estimator->GetMaxPredictWindowMs(
1185 &predict_window);
1186
1187 if (ret != ::thermal::vtestimator::kVtEstimatorOk) {
1188 LOG(ERROR) << "Failed to read prediction (ret: " << ret << ") from " << predict_sensor_name
1189 << " for sensor " << sensor_name;
1190 return 0;
1191 }
1192
1193 return predict_window;
1194 }
1195
readPredictionAfterTimeMs(std::string_view sensor_name,const size_t time_ms)1196 float ThermalHelperImpl::readPredictionAfterTimeMs(std::string_view sensor_name,
1197 const size_t time_ms) {
1198 float predicted_vt = NAN;
1199
1200 ATRACE_NAME(
1201 StringPrintf("ThermalHelper::readPredictAfterTimeMs - %s", sensor_name.data()).c_str());
1202
1203 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
1204 if (sensor_info.predictor_info == nullptr) {
1205 LOG(ERROR) << "No predictor info found for sensor: " << sensor_name;
1206 return NAN;
1207 }
1208
1209 std::string_view predict_sensor_name = sensor_info.predictor_info->sensor;
1210 const auto &predictor_sensor_info = sensor_info_map_.at(predict_sensor_name.data());
1211 ::thermal::vtestimator::VtEstimatorStatus ret =
1212 predictor_sensor_info.virtual_sensor_info->vt_estimator->PredictAfterTimeMs(
1213 time_ms, &predicted_vt);
1214
1215 if (ret == ::thermal::vtestimator::kVtEstimatorOk) {
1216 return predicted_vt;
1217 } else if (ret == ::thermal::vtestimator::kVtEstimatorUnderSampling) {
1218 LOG(INFO) << predict_sensor_name << " cannot provide prediction for sensor " << sensor_name
1219 << "while under sampling";
1220 } else if (ret == ::thermal::vtestimator::kVtEstimatorUnSupported) {
1221 LOG(INFO) << "PredictAfterTimeMs not supported with " << predict_sensor_name
1222 << " for sensor " << sensor_name;
1223 } else {
1224 LOG(ERROR) << "Failed to read prediction (ret: " << ret << ") from " << predict_sensor_name
1225 << " for sensor " << sensor_name;
1226 }
1227
1228 return NAN;
1229 }
1230
readTemperaturePredictions(std::string_view sensor_name,std::vector<float> * predictions)1231 bool ThermalHelperImpl::readTemperaturePredictions(std::string_view sensor_name,
1232 std::vector<float> *predictions) {
1233 ATRACE_NAME(StringPrintf("ThermalHelper::readTemperaturePredictions - %s", sensor_name.data())
1234 .c_str());
1235
1236 if (predictions == nullptr) {
1237 LOG(ERROR) << " predictions is nullptr";
1238 return false;
1239 }
1240
1241 if (!sensor_info_map_.count(sensor_name.data())) {
1242 LOG(ERROR) << sensor_name << " not part of sensor_info_map_";
1243 return false;
1244 }
1245
1246 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
1247 if (sensor_info.predictor_info == nullptr) {
1248 LOG(ERROR) << "No predictor info found for sensor: " << sensor_name;
1249 return false;
1250 }
1251
1252 std::string predict_sensor_name = sensor_info.predictor_info->sensor;
1253 const auto &predictor_sensor_info = sensor_info_map_.at(predict_sensor_name);
1254 ::thermal::vtestimator::VtEstimatorStatus ret =
1255 predictor_sensor_info.virtual_sensor_info->vt_estimator->GetAllPredictions(predictions);
1256
1257 if (ret != ::thermal::vtestimator::kVtEstimatorOk) {
1258 LOG(ERROR) << "Failed to read predictions (ret: " << ret << ") from " << predict_sensor_name
1259 << " for sensor " << sensor_name;
1260 return false;
1261 }
1262
1263 return true;
1264 }
1265
1266 constexpr int kTranTimeoutParam = 2;
1267
readThermalSensor(std::string_view sensor_name,float * temp,const bool force_no_cache,std::map<std::string,float> * sensor_log_map)1268 SensorReadStatus ThermalHelperImpl::readThermalSensor(
1269 std::string_view sensor_name, float *temp, const bool force_no_cache,
1270 std::map<std::string, float> *sensor_log_map) {
1271 std::string file_reading;
1272 boot_clock::time_point now = boot_clock::now();
1273
1274 ATRACE_NAME(StringPrintf("ThermalHelper::readThermalSensor - %s", sensor_name.data()).c_str());
1275 if (!(sensor_info_map_.count(sensor_name.data()) &&
1276 sensor_status_map_.count(sensor_name.data()))) {
1277 return SensorReadStatus::ERROR;
1278 }
1279
1280 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
1281 auto &sensor_status = sensor_status_map_.at(sensor_name.data());
1282
1283 {
1284 std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
1285 if (sensor_status.override_status.emul_temp != nullptr) {
1286 *temp = sensor_status.override_status.emul_temp->temp;
1287 (*sensor_log_map)[sensor_name.data()] = *temp;
1288 return SensorReadStatus::OKAY;
1289 }
1290 }
1291
1292 const auto since_last_update = std::chrono::duration_cast<std::chrono::milliseconds>(
1293 now - sensor_status.thermal_cached.timestamp);
1294
1295 // Check if thermal data need to be read from cache
1296 if (!force_no_cache &&
1297 (sensor_status.thermal_cached.timestamp != boot_clock::time_point::min()) &&
1298 (since_last_update < sensor_info.time_resolution) &&
1299 !isnan(sensor_status.thermal_cached.temp)) {
1300 *temp = sensor_status.thermal_cached.temp;
1301 (*sensor_log_map)[sensor_name.data()] = *temp;
1302 ATRACE_INT((sensor_name.data() + std::string("-cached")).c_str(), static_cast<int>(*temp));
1303 return SensorReadStatus::OKAY;
1304 }
1305
1306 // Reading thermal sensor according to it's composition
1307 if (sensor_info.virtual_sensor_info == nullptr) {
1308 if (!thermal_sensors_.readThermalFile(sensor_name.data(), &file_reading) ||
1309 file_reading.empty()) {
1310 LOG(ERROR) << "failed to read sensor: " << sensor_name;
1311 return SensorReadStatus::ERROR;
1312 }
1313 *temp = std::stof(::android::base::Trim(file_reading));
1314 } else {
1315 const auto &linked_sensors_size = sensor_info.virtual_sensor_info->linked_sensors.size();
1316 std::vector<float> sensor_readings(linked_sensors_size, NAN);
1317
1318 // Calculate temperature of each of the linked sensor
1319 for (size_t i = 0; i < linked_sensors_size; i++) {
1320 if (!readDataByType(sensor_info.virtual_sensor_info->linked_sensors[i],
1321 &sensor_readings[i],
1322 sensor_info.virtual_sensor_info->linked_sensors_type[i],
1323 force_no_cache, sensor_log_map)) {
1324 LOG(ERROR) << "Failed to read " << sensor_name.data() << "'s linked sensor "
1325 << sensor_info.virtual_sensor_info->linked_sensors[i];
1326 return SensorReadStatus::ERROR;
1327 }
1328 if (std::isnan(sensor_readings[i])) {
1329 LOG(INFO) << sensor_name << " data is under collecting";
1330 return SensorReadStatus::UNDER_COLLECTING;
1331 }
1332 }
1333
1334 if (sensor_info.virtual_sensor_info->formula == FormulaOption::PREVIOUSLY_PREDICTED) {
1335 const auto ret = thermal_predictions_helper_.readSensor(sensor_name, temp);
1336 if (ret != SensorReadStatus::OKAY) {
1337 return ret;
1338 }
1339 } else if ((sensor_info.virtual_sensor_info->formula == FormulaOption::USE_ML_MODEL) ||
1340 (sensor_info.virtual_sensor_info->formula == FormulaOption::USE_LINEAR_MODEL)) {
1341 std::vector<float> vt_estimator_out;
1342 if (!runVirtualTempEstimator(sensor_name, sensor_log_map, force_no_cache,
1343 &vt_estimator_out)) {
1344 LOG(ERROR) << "Failed running VirtualEstimator for " << sensor_name;
1345 return SensorReadStatus::ERROR;
1346 }
1347 *temp = vt_estimator_out[0];
1348 } else {
1349 float temp_val = 0.0;
1350 for (size_t i = 0; i < linked_sensors_size; i++) {
1351 float coefficient = NAN;
1352 if (!readDataByType(sensor_info.virtual_sensor_info->coefficients[i], &coefficient,
1353 sensor_info.virtual_sensor_info->coefficients_type[i],
1354 force_no_cache, sensor_log_map)) {
1355 LOG(ERROR) << "Failed to read " << sensor_name.data() << "'s coefficient "
1356 << sensor_info.virtual_sensor_info->coefficients[i];
1357 return SensorReadStatus::ERROR;
1358 }
1359 if (std::isnan(coefficient)) {
1360 LOG(INFO) << sensor_name << " data is under collecting";
1361 return SensorReadStatus::UNDER_COLLECTING;
1362 }
1363 switch (sensor_info.virtual_sensor_info->formula) {
1364 case FormulaOption::COUNT_THRESHOLD:
1365 if ((coefficient < 0 && sensor_readings[i] < -coefficient) ||
1366 (coefficient >= 0 && sensor_readings[i] >= coefficient))
1367 temp_val += 1;
1368 break;
1369 case FormulaOption::WEIGHTED_AVG:
1370 temp_val += sensor_readings[i] * coefficient;
1371 break;
1372 case FormulaOption::MAXIMUM:
1373 if (i == 0)
1374 temp_val = std::numeric_limits<float>::lowest();
1375 if (sensor_readings[i] * coefficient > temp_val)
1376 temp_val = sensor_readings[i] * coefficient;
1377 break;
1378 case FormulaOption::MINIMUM:
1379 if (i == 0)
1380 temp_val = std::numeric_limits<float>::max();
1381 if (sensor_readings[i] * coefficient < temp_val)
1382 temp_val = sensor_readings[i] * coefficient;
1383 break;
1384 default:
1385 LOG(ERROR) << "Unknown formula type for sensor " << sensor_name.data();
1386 return SensorReadStatus::ERROR;
1387 }
1388 }
1389 *temp = (temp_val + sensor_info.virtual_sensor_info->offset);
1390 }
1391 }
1392
1393 if (!isnan(sensor_info.step_ratio) && !isnan(sensor_status.thermal_cached.temp) &&
1394 since_last_update < sensor_info.passive_delay * kTranTimeoutParam) {
1395 *temp = (sensor_info.step_ratio * *temp +
1396 (1 - sensor_info.step_ratio) * sensor_status.thermal_cached.temp);
1397 }
1398
1399 (*sensor_log_map)[sensor_name.data()] = *temp;
1400 ATRACE_INT(sensor_name.data(), static_cast<int>(*temp));
1401
1402 {
1403 std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
1404 sensor_status.thermal_cached.temp = *temp;
1405 sensor_status.thermal_cached.timestamp = now;
1406 }
1407 auto real_temp = (*temp) * sensor_info.multiplier;
1408 thermal_stats_helper_.updateSensorTempStatsByThreshold(sensor_name, real_temp);
1409 return SensorReadStatus::OKAY;
1410 }
1411
1412 // This is called in the different thread context and will update sensor_status
1413 // uevent_sensors_map maps sensor which trigger uevent from thermal core driver to the temperature
1414 // read from uevent.
thermalWatcherCallbackFunc(const std::unordered_map<std::string,float> & uevent_sensor_map)1415 std::chrono::milliseconds ThermalHelperImpl::thermalWatcherCallbackFunc(
1416 const std::unordered_map<std::string, float> &uevent_sensor_map) {
1417 std::vector<Temperature> temps;
1418 std::vector<std::string> cooling_devices_to_update;
1419 boot_clock::time_point now = boot_clock::now();
1420 auto min_sleep_ms = std::chrono::milliseconds::max();
1421 bool power_data_is_updated = false;
1422
1423 for (const auto &[sensor, temp] : uevent_sensor_map) {
1424 if (!std::isnan(temp)) {
1425 std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
1426 sensor_status_map_[sensor].thermal_cached.temp = temp;
1427 sensor_status_map_[sensor].thermal_cached.timestamp = now;
1428 }
1429 }
1430
1431 ATRACE_CALL();
1432 // Go through all virtual and physical sensor and update if needed
1433 for (auto &name_status_pair : sensor_status_map_) {
1434 bool force_update = false;
1435 bool force_no_cache = false;
1436 Temperature temp;
1437 SensorStatus &sensor_status = name_status_pair.second;
1438 const SensorInfo &sensor_info = sensor_info_map_.at(name_status_pair.first);
1439 bool max_throttling = false;
1440
1441 // Only handle the sensors in allow list
1442 if (!sensor_info.is_watch) {
1443 continue;
1444 }
1445
1446 ATRACE_NAME(StringPrintf("ThermalHelper::thermalWatcherCallbackFunc - %s",
1447 name_status_pair.first.data())
1448 .c_str());
1449
1450 std::chrono::milliseconds time_elapsed_ms = std::chrono::milliseconds::zero();
1451 auto sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
1452 ? sensor_info.passive_delay
1453 : sensor_info.polling_delay;
1454
1455 if (sensor_info.virtual_sensor_info != nullptr &&
1456 !sensor_info.virtual_sensor_info->trigger_sensors.empty()) {
1457 for (size_t i = 0; i < sensor_info.virtual_sensor_info->trigger_sensors.size(); i++) {
1458 const auto &trigger_sensor_status =
1459 sensor_status_map_.at(sensor_info.virtual_sensor_info->trigger_sensors[i]);
1460 if (trigger_sensor_status.severity != ThrottlingSeverity::NONE) {
1461 sleep_ms = sensor_info.passive_delay;
1462 break;
1463 }
1464 }
1465 }
1466 // Force update if it's first time we update temperature value after device boot
1467 if (sensor_status.last_update_time == boot_clock::time_point::min()) {
1468 force_update = true;
1469
1470 } else {
1471 // Handle other update event
1472 time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
1473 now - sensor_status.last_update_time);
1474 // Update triggered from genlink or uevent
1475 if (uevent_sensor_map.size()) {
1476 // Checking virtual sensor
1477 if (sensor_info.virtual_sensor_info != nullptr) {
1478 for (size_t i = 0; i < sensor_info.virtual_sensor_info->trigger_sensors.size();
1479 i++) {
1480 if (uevent_sensor_map.find(
1481 sensor_info.virtual_sensor_info->trigger_sensors[i]) !=
1482 uevent_sensor_map.end()) {
1483 force_update = true;
1484 break;
1485 }
1486 }
1487 } else if (uevent_sensor_map.find(name_status_pair.first) !=
1488 uevent_sensor_map.end()) {
1489 // Checking physical sensor
1490 force_update = true;
1491 if (std::isnan(uevent_sensor_map.at(name_status_pair.first))) {
1492 // Handle the case that uevent does not contain temperature
1493 force_no_cache = true;
1494 }
1495 }
1496 } else if (time_elapsed_ms > sleep_ms) {
1497 // Update triggered from normal polling cylce
1498 force_update = true;
1499 }
1500 }
1501 {
1502 std::lock_guard<std::shared_mutex> _lock(sensor_status_map_mutex_);
1503 max_throttling = sensor_status.override_status.max_throttling;
1504 if (sensor_status.override_status.pending_update) {
1505 force_update = sensor_status.override_status.pending_update;
1506 sensor_status.override_status.pending_update = false;
1507 }
1508 }
1509 LOG(VERBOSE) << "sensor " << name_status_pair.first
1510 << ": time_elapsed=" << time_elapsed_ms.count()
1511 << ", sleep_ms=" << sleep_ms.count() << ", force_update = " << force_update
1512 << ", force_no_cache = " << force_no_cache;
1513
1514 if (!force_update) {
1515 auto timeout_remaining = sleep_ms - time_elapsed_ms;
1516 if (min_sleep_ms > timeout_remaining) {
1517 min_sleep_ms = timeout_remaining;
1518 }
1519 LOG(VERBOSE) << "sensor " << name_status_pair.first
1520 << ": timeout_remaining=" << timeout_remaining.count();
1521 continue;
1522 }
1523
1524 std::pair<ThrottlingSeverity, ThrottlingSeverity> throttling_status;
1525 const auto ret = readTemperature(name_status_pair.first, &temp, force_no_cache);
1526 if (ret == SensorReadStatus::ERROR) {
1527 LOG(ERROR) << __func__
1528 << ": error reading temperature for sensor: " << name_status_pair.first;
1529 continue;
1530 }
1531
1532 if (ret == SensorReadStatus::UNDER_COLLECTING) {
1533 LOG(INFO) << __func__
1534 << ": data under collecting for sensor: " << name_status_pair.first;
1535 continue;
1536 }
1537
1538 {
1539 std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
1540 if (sensor_status.pending_notification) {
1541 temps.push_back(temp);
1542 sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
1543 ? sensor_info.passive_delay
1544 : sensor_info.polling_delay;
1545 sensor_status.pending_notification = false;
1546 }
1547 }
1548
1549 if (!power_data_is_updated) {
1550 power_files_.refreshPowerStatus();
1551 power_data_is_updated = true;
1552 }
1553
1554 if (sensor_status.severity == ThrottlingSeverity::NONE) {
1555 thermal_throttling_.clearThrottlingData(name_status_pair.first);
1556 } else {
1557 // prepare for predictions for throttling compensation
1558 std::vector<float> sensor_predictions;
1559 if (sensor_info.predictor_info != nullptr &&
1560 sensor_info.predictor_info->support_pid_compensation) {
1561 if (!readTemperaturePredictions(name_status_pair.first, &sensor_predictions)) {
1562 LOG(ERROR) << "Failed to read predictions of " << name_status_pair.first
1563 << " for throttling compensation";
1564 }
1565 }
1566
1567 // update thermal throttling request
1568 thermal_throttling_.thermalThrottlingUpdate(
1569 temp, sensor_info, sensor_status.severity, time_elapsed_ms,
1570 power_files_.GetPowerStatusMap(), cooling_device_info_map_, max_throttling,
1571 sensor_predictions);
1572 }
1573
1574 thermal_throttling_.computeCoolingDevicesRequest(
1575 name_status_pair.first, sensor_info, sensor_status.severity,
1576 &cooling_devices_to_update, &thermal_stats_helper_);
1577 if (min_sleep_ms > sleep_ms) {
1578 min_sleep_ms = sleep_ms;
1579 }
1580
1581 LOG(VERBOSE) << "Sensor " << name_status_pair.first << ": sleep_ms=" << sleep_ms.count()
1582 << ", min_sleep_ms voting result=" << min_sleep_ms.count();
1583 sensor_status.last_update_time = now;
1584 }
1585
1586 if (!temps.empty()) {
1587 for (const auto &t : temps) {
1588 if (sensor_info_map_.at(t.name).send_cb && cb_) {
1589 cb_(t);
1590 }
1591
1592 if (sensor_info_map_.at(t.name).send_powerhint) {
1593 power_hal_service_.sendPowerExtHint(t);
1594 }
1595 }
1596 }
1597
1598 if (!cooling_devices_to_update.empty()) {
1599 updateCoolingDevices(cooling_devices_to_update);
1600 }
1601
1602 int count_failed_reporting = thermal_stats_helper_.reportStats();
1603 if (count_failed_reporting != 0) {
1604 LOG(ERROR) << "Failed to report " << count_failed_reporting << " thermal stats";
1605 }
1606
1607 const auto since_last_power_log_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
1608 now - power_files_.GetPrevPowerLogTime());
1609 if (since_last_power_log_ms >= kPowerLogIntervalMs) {
1610 power_files_.logPowerStatus(now);
1611 }
1612
1613 return min_sleep_ms;
1614 }
1615
1616 } // namespace implementation
1617 } // namespace thermal
1618 } // namespace hardware
1619 } // namespace android
1620 } // namespace aidl
1621