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
17 #include <iterator>
18 #include <set>
19 #include <sstream>
20 #include <thread>
21 #include <vector>
22
23 #include <android-base/file.h>
24 #include <android-base/logging.h>
25 #include <android-base/properties.h>
26 #include <android-base/stringprintf.h>
27 #include <android-base/strings.h>
28 #include <android/binder_manager.h>
29 #include <hidl/HidlTransportSupport.h>
30
31 #include "thermal-helper.h"
32
33 namespace android {
34 namespace hardware {
35 namespace thermal {
36 namespace V2_0 {
37 namespace implementation {
38
39 constexpr std::string_view kCpuOnlineRoot("/sys/devices/system/cpu");
40 constexpr std::string_view kThermalSensorsRoot("/sys/devices/virtual/thermal");
41 constexpr std::string_view kCpuUsageFile("/proc/stat");
42 constexpr std::string_view kCpuOnlineFileSuffix("online");
43 constexpr std::string_view kCpuPresentFile("/sys/devices/system/cpu/present");
44 constexpr std::string_view kSensorPrefix("thermal_zone");
45 constexpr std::string_view kCoolingDevicePrefix("cooling_device");
46 constexpr std::string_view kThermalNameFile("type");
47 constexpr std::string_view kSensorPolicyFile("policy");
48 constexpr std::string_view kSensorTempSuffix("temp");
49 constexpr std::string_view kSensorTripPointTempZeroFile("trip_point_0_temp");
50 constexpr std::string_view kSensorTripPointHystZeroFile("trip_point_0_hyst");
51 constexpr std::string_view kUserSpaceSuffix("user_space");
52 constexpr std::string_view kCoolingDeviceCurStateSuffix("cur_state");
53 constexpr std::string_view kCoolingDeviceMaxStateSuffix("max_state");
54 constexpr std::string_view kCoolingDeviceState2powerSuffix("state2power_table");
55 constexpr std::string_view kConfigProperty("vendor.thermal.config");
56 constexpr std::string_view kConfigDefaultFileName("thermal_info_config.json");
57 constexpr std::string_view kThermalGenlProperty("persist.vendor.enable.thermal.genl");
58 constexpr std::string_view kThermalDisabledProperty("vendor.disable.thermal.control");
59
60 namespace {
61 using android::base::StringPrintf;
62 using android::hardware::thermal::V2_0::toString;
63
64 /*
65 * Pixel don't offline CPU, so std::thread::hardware_concurrency(); should work.
66 * However /sys/devices/system/cpu/present is preferred.
67 * The file is expected to contain single text line with two numbers %d-%d,
68 * which is a range of available cpu numbers, e.g. 0-7 would mean there
69 * are 8 cores number from 0 to 7.
70 * For Android systems this approach is safer than using cpufeatures, see bug
71 * b/36941727.
72 */
getNumberOfCores()73 static int getNumberOfCores() {
74 std::string file;
75 if (!android::base::ReadFileToString(kCpuPresentFile.data(), &file)) {
76 LOG(ERROR) << "Error reading Cpu present file: " << kCpuPresentFile;
77 return 0;
78 }
79 std::vector<std::string> pieces = android::base::Split(file, "-");
80 if (pieces.size() != 2) {
81 LOG(ERROR) << "Error parsing Cpu present file content: " << file;
82 return 0;
83 }
84 auto min_core = std::stoul(pieces[0]);
85 auto max_core = std::stoul(pieces[1]);
86 if (max_core < min_core) {
87 LOG(ERROR) << "Error parsing Cpu present min and max: " << min_core << " - " << max_core;
88 return 0;
89 }
90 return static_cast<std::size_t>(max_core - min_core + 1);
91 }
92 const int kMaxCpus = getNumberOfCores();
93
parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> * cpu_usages)94 void parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> *cpu_usages) {
95 std::string data;
96 if (!android::base::ReadFileToString(kCpuUsageFile.data(), &data)) {
97 LOG(ERROR) << "Error reading cpu usage file: " << kCpuUsageFile;
98 return;
99 }
100
101 std::istringstream stat_data(data);
102 std::string line;
103 while (std::getline(stat_data, line)) {
104 if (!line.find("cpu") && isdigit(line[3])) {
105 // Split the string using spaces.
106 std::vector<std::string> words = android::base::Split(line, " ");
107 std::string cpu_name = words[0];
108 int cpu_num = std::stoi(cpu_name.substr(3));
109
110 if (cpu_num < kMaxCpus) {
111 uint64_t user = std::stoull(words[1]);
112 uint64_t nice = std::stoull(words[2]);
113 uint64_t system = std::stoull(words[3]);
114 uint64_t idle = std::stoull(words[4]);
115
116 // Check if the CPU is online by reading the online file.
117 std::string cpu_online_path =
118 StringPrintf("%s/%s/%s", kCpuOnlineRoot.data(), cpu_name.c_str(),
119 kCpuOnlineFileSuffix.data());
120 std::string is_online;
121 if (!android::base::ReadFileToString(cpu_online_path, &is_online)) {
122 LOG(ERROR) << "Could not open Cpu online file: " << cpu_online_path;
123 if (cpu_num != 0) {
124 return;
125 }
126 // Some architecture cannot offline cpu0, so assuming it is online
127 is_online = "1";
128 }
129 is_online = android::base::Trim(is_online);
130
131 (*cpu_usages)[cpu_num].active = user + nice + system;
132 (*cpu_usages)[cpu_num].total = user + nice + system + idle;
133 (*cpu_usages)[cpu_num].isOnline = (is_online == "1") ? true : false;
134 } else {
135 LOG(ERROR) << "Unexpected cpu number: " << words[0];
136 return;
137 }
138 }
139 }
140 }
141
parseThermalPathMap(std::string_view prefix)142 std::unordered_map<std::string, std::string> parseThermalPathMap(std::string_view prefix) {
143 std::unordered_map<std::string, std::string> path_map;
144 std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(kThermalSensorsRoot.data()), closedir);
145 if (!dir) {
146 return path_map;
147 }
148
149 // std::filesystem is not available for vendor yet
150 // see discussion: aosp/894015
151 while (struct dirent *dp = readdir(dir.get())) {
152 if (dp->d_type != DT_DIR) {
153 continue;
154 }
155
156 if (!android::base::StartsWith(dp->d_name, prefix.data())) {
157 continue;
158 }
159
160 std::string path = android::base::StringPrintf("%s/%s/%s", kThermalSensorsRoot.data(),
161 dp->d_name, kThermalNameFile.data());
162 std::string name;
163 if (!android::base::ReadFileToString(path, &name)) {
164 PLOG(ERROR) << "Failed to read from " << path;
165 continue;
166 }
167
168 path_map.emplace(
169 android::base::Trim(name),
170 android::base::StringPrintf("%s/%s", kThermalSensorsRoot.data(), dp->d_name));
171 }
172
173 return path_map;
174 }
175
176 } // namespace
PowerHalService()177 PowerHalService::PowerHalService()
178 : power_hal_aidl_exist_(true), power_hal_aidl_(nullptr), power_hal_ext_aidl_(nullptr) {
179 connect();
180 }
181
connect()182 bool PowerHalService::connect() {
183 std::lock_guard<std::mutex> lock(lock_);
184 if (!power_hal_aidl_exist_)
185 return false;
186
187 if (power_hal_aidl_ != nullptr)
188 return true;
189
190 const std::string kInstance = std::string(IPower::descriptor) + "/default";
191 ndk::SpAIBinder power_binder = ndk::SpAIBinder(AServiceManager_getService(kInstance.c_str()));
192 ndk::SpAIBinder ext_power_binder;
193
194 if (power_binder.get() == nullptr) {
195 LOG(ERROR) << "Cannot get Power Hal Binder";
196 power_hal_aidl_exist_ = false;
197 return false;
198 }
199
200 power_hal_aidl_ = IPower::fromBinder(power_binder);
201
202 if (power_hal_aidl_ == nullptr) {
203 power_hal_aidl_exist_ = false;
204 LOG(ERROR) << "Cannot get Power Hal AIDL" << kInstance.c_str();
205 return false;
206 }
207
208 if (STATUS_OK != AIBinder_getExtension(power_binder.get(), ext_power_binder.getR()) ||
209 ext_power_binder.get() == nullptr) {
210 LOG(ERROR) << "Cannot get Power Hal Extension Binder";
211 power_hal_aidl_exist_ = false;
212 return false;
213 }
214
215 power_hal_ext_aidl_ = IPowerExt::fromBinder(ext_power_binder);
216 if (power_hal_ext_aidl_ == nullptr) {
217 LOG(ERROR) << "Cannot get Power Hal Extension AIDL";
218 power_hal_aidl_exist_ = false;
219 }
220
221 return true;
222 }
223
isModeSupported(const std::string & type,const ThrottlingSeverity & t)224 bool PowerHalService::isModeSupported(const std::string &type, const ThrottlingSeverity &t) {
225 bool isSupported = false;
226 if (!isPowerHalConnected()) {
227 return false;
228 }
229 std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str());
230 lock_.lock();
231 if (!power_hal_ext_aidl_->isModeSupported(power_hint, &isSupported).isOk()) {
232 LOG(ERROR) << "Fail to check supported mode, Hint: " << power_hint;
233 power_hal_aidl_exist_ = false;
234 power_hal_ext_aidl_ = nullptr;
235 power_hal_aidl_ = nullptr;
236 lock_.unlock();
237 return false;
238 }
239 lock_.unlock();
240 return isSupported;
241 }
242
setMode(const std::string & type,const ThrottlingSeverity & t,const bool & enable)243 void PowerHalService::setMode(const std::string &type, const ThrottlingSeverity &t,
244 const bool &enable) {
245 if (!isPowerHalConnected()) {
246 return;
247 }
248
249 std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str());
250 LOG(INFO) << "Send Hint " << power_hint << " Enable: " << std::boolalpha << enable;
251 lock_.lock();
252 if (!power_hal_ext_aidl_->setMode(power_hint, enable).isOk()) {
253 LOG(ERROR) << "Fail to set mode, Hint: " << power_hint;
254 power_hal_aidl_exist_ = false;
255 power_hal_ext_aidl_ = nullptr;
256 power_hal_aidl_ = nullptr;
257 lock_.unlock();
258 return;
259 }
260 lock_.unlock();
261 }
262
263 /*
264 * Populate the sensor_name_to_file_map_ map by walking through the file tree,
265 * reading the type file and assigning the temp file path to the map. If we do
266 * not succeed, abort.
267 */
ThermalHelper(const NotificationCallback & cb)268 ThermalHelper::ThermalHelper(const NotificationCallback &cb)
269 : thermal_watcher_(new ThermalWatcher(
270 std::bind(&ThermalHelper::thermalWatcherCallbackFunc, this, std::placeholders::_1))),
271 cb_(cb) {
272 const std::string config_path =
273 "/vendor/etc/" +
274 android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data());
275 cooling_device_info_map_ = ParseCoolingDevice(config_path);
276 sensor_info_map_ = ParseSensorInfo(config_path);
277 power_rail_info_map_ = ParsePowerRailInfo(config_path);
278 auto tz_map = parseThermalPathMap(kSensorPrefix.data());
279 auto cdev_map = parseThermalPathMap(kCoolingDevicePrefix.data());
280
281 is_initialized_ = initializeSensorMap(tz_map) && initializeCoolingDevices(cdev_map);
282 if (!is_initialized_) {
283 LOG(FATAL) << "ThermalHAL could not be initialized properly.";
284 }
285
286 for (auto const &name_status_pair : sensor_info_map_) {
287 sensor_status_map_[name_status_pair.first] = {
288 .severity = ThrottlingSeverity::NONE,
289 .prev_hot_severity = ThrottlingSeverity::NONE,
290 .prev_cold_severity = ThrottlingSeverity::NONE,
291 .prev_hint_severity = ThrottlingSeverity::NONE,
292 .last_update_time = boot_clock::time_point::min(),
293 .err_integral = 0.0,
294 .prev_err = NAN,
295 };
296
297 bool invalid_binded_cdev = false;
298 for (auto &binded_cdev_pair :
299 name_status_pair.second.throttling_info->binded_cdev_info_map) {
300 if (!cooling_device_info_map_.count(binded_cdev_pair.first)) {
301 invalid_binded_cdev = true;
302 LOG(ERROR) << "Could not find " << binded_cdev_pair.first
303 << " in cooling device info map";
304 }
305
306 for (const auto &cdev_weight : binded_cdev_pair.second.cdev_weight_for_pid) {
307 if (!std::isnan(cdev_weight)) {
308 sensor_status_map_[name_status_pair.first]
309 .pid_request_map[binded_cdev_pair.first] = 0;
310 cdev_status_map_[binded_cdev_pair.first][name_status_pair.first] = 0;
311 break;
312 }
313 }
314
315 for (const auto &limit_info : binded_cdev_pair.second.limit_info) {
316 if (limit_info > 0) {
317 sensor_status_map_[name_status_pair.first]
318 .hard_limit_request_map[binded_cdev_pair.first] = 0;
319 cdev_status_map_[binded_cdev_pair.first][name_status_pair.first] = 0;
320 }
321 }
322 const auto &cdev_info = cooling_device_info_map_.at(binded_cdev_pair.first);
323
324 for (auto &cdev_ceiling : binded_cdev_pair.second.cdev_ceiling) {
325 if (cdev_ceiling > cdev_info.max_state) {
326 if (cdev_ceiling != std::numeric_limits<int>::max()) {
327 LOG(ERROR) << "Sensor " << name_status_pair.first << "'s "
328 << binded_cdev_pair.first << " cdev_ceiling:" << cdev_ceiling
329 << " is higher than max state:" << cdev_info.max_state;
330 }
331 cdev_ceiling = cdev_info.max_state;
332 }
333 }
334
335 if (power_rail_info_map_.count(binded_cdev_pair.second.power_rail) &&
336 power_rail_info_map_.at(binded_cdev_pair.second.power_rail).power_sample_count &&
337 power_files_.findEnergySourceToWatch()) {
338 const auto &power_rail_info =
339 power_rail_info_map_.at(binded_cdev_pair.second.power_rail);
340 if (!power_files_.registerPowerRailsToWatch(
341 name_status_pair.first, binded_cdev_pair.first, binded_cdev_pair.second,
342 cdev_info, power_rail_info)) {
343 invalid_binded_cdev = true;
344 LOG(ERROR) << "Could not find " << binded_cdev_pair.first
345 << "'s power energy source: " << binded_cdev_pair.second.power_rail;
346 }
347 }
348 }
349
350 if (invalid_binded_cdev) {
351 name_status_pair.second.throttling_info->binded_cdev_info_map.clear();
352 sensor_status_map_[name_status_pair.first].hard_limit_request_map.clear();
353 sensor_status_map_[name_status_pair.first].pid_request_map.clear();
354 }
355
356 if (name_status_pair.second.virtual_sensor_info != nullptr &&
357 name_status_pair.second.is_monitor) {
358 if (sensor_info_map_.count(
359 name_status_pair.second.virtual_sensor_info->trigger_sensor)) {
360 sensor_info_map_[name_status_pair.second.virtual_sensor_info->trigger_sensor]
361 .is_monitor = true;
362 } else {
363 LOG(FATAL) << name_status_pair.first << " does not have trigger sensor: "
364 << name_status_pair.second.virtual_sensor_info->trigger_sensor;
365 }
366 }
367 }
368
369 const bool thermal_throttling_disabled =
370 android::base::GetBoolProperty(kThermalDisabledProperty.data(), false);
371
372 if (thermal_throttling_disabled) {
373 LOG(INFO) << kThermalDisabledProperty.data() << " is true";
374 for (const auto &cdev_pair : cooling_device_info_map_) {
375 if (cooling_devices_.writeCdevFile(cdev_pair.first, std::to_string(0))) {
376 LOG(INFO) << "Successfully clear cdev " << cdev_pair.first << " to 0";
377 }
378 }
379 return;
380 }
381
382 const bool thermal_genl_enabled =
383 android::base::GetBoolProperty(kThermalGenlProperty.data(), false);
384
385 std::set<std::string> monitored_sensors;
386 initializeTrip(tz_map, &monitored_sensors, thermal_genl_enabled);
387
388 if (thermal_genl_enabled) {
389 thermal_watcher_->registerFilesToWatchNl(monitored_sensors);
390 } else {
391 thermal_watcher_->registerFilesToWatch(monitored_sensors);
392 }
393
394 // Need start watching after status map initialized
395 is_initialized_ = thermal_watcher_->startWatchingDeviceFiles();
396 if (!is_initialized_) {
397 LOG(FATAL) << "ThermalHAL could not start watching thread properly.";
398 }
399
400 if (!connectToPowerHal()) {
401 LOG(ERROR) << "Fail to connect to Power Hal";
402 } else {
403 updateSupportedPowerHints();
404 }
405 }
406
getThermalZoneTypeById(int tz_id,std::string * type)407 bool getThermalZoneTypeById(int tz_id, std::string *type) {
408 std::string tz_type;
409 std::string path =
410 android::base::StringPrintf("%s/%s%d/%s", kThermalSensorsRoot.data(),
411 kSensorPrefix.data(), tz_id, kThermalNameFile.data());
412 LOG(INFO) << "TZ Path: " << path;
413 if (!::android::base::ReadFileToString(path, &tz_type)) {
414 LOG(ERROR) << "Failed to read sensor: " << tz_type;
415 return false;
416 }
417
418 // Strip the newline.
419 *type = ::android::base::Trim(tz_type);
420 LOG(INFO) << "TZ type: " << *type;
421 return true;
422 }
423
readCoolingDevice(std::string_view cooling_device,CoolingDevice_2_0 * out) const424 bool ThermalHelper::readCoolingDevice(std::string_view cooling_device,
425 CoolingDevice_2_0 *out) const {
426 // Read the file. If the file can't be read temp will be empty string.
427 std::string data;
428
429 if (!cooling_devices_.readThermalFile(cooling_device, &data)) {
430 LOG(ERROR) << "readCoolingDevice: failed to read cooling_device: " << cooling_device;
431 return false;
432 }
433
434 const CdevInfo &cdev_info = cooling_device_info_map_.at(cooling_device.data());
435 const CoolingType &type = cdev_info.type;
436
437 out->type = type;
438 out->name = cooling_device.data();
439 out->value = std::stoi(data);
440
441 return true;
442 }
443
readTemperature(std::string_view sensor_name,Temperature_1_0 * out,bool is_virtual_sensor) const444 bool ThermalHelper::readTemperature(std::string_view sensor_name, Temperature_1_0 *out,
445 bool is_virtual_sensor) const {
446 // Read the file. If the file can't be read temp will be empty string.
447 std::string temp;
448
449 if (!is_virtual_sensor) {
450 if (!thermal_sensors_.readThermalFile(sensor_name, &temp)) {
451 LOG(ERROR) << "readTemperature: sensor not found: " << sensor_name;
452 return false;
453 }
454
455 if (temp.empty()) {
456 LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
457 return false;
458 }
459 } else {
460 if (!checkVirtualSensor(sensor_name.data(), &temp)) {
461 LOG(ERROR) << "readTemperature: failed to read virtual sensor: " << sensor_name;
462 return false;
463 }
464 }
465
466 const SensorInfo &sensor_info = sensor_info_map_.at(sensor_name.data());
467 TemperatureType_1_0 type =
468 (static_cast<int>(sensor_info.type) > static_cast<int>(TemperatureType_1_0::SKIN))
469 ? TemperatureType_1_0::UNKNOWN
470 : static_cast<TemperatureType_1_0>(sensor_info.type);
471 out->type = type;
472 out->name = sensor_name.data();
473 out->currentValue = std::stof(temp) * sensor_info.multiplier;
474 out->throttlingThreshold =
475 sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)];
476 out->shutdownThreshold =
477 sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SHUTDOWN)];
478 out->vrThrottlingThreshold = sensor_info.vr_threshold;
479
480 return true;
481 }
482
readTemperature(std::string_view sensor_name,Temperature_2_0 * out,std::pair<ThrottlingSeverity,ThrottlingSeverity> * throtting_status,bool is_virtual_sensor) const483 bool ThermalHelper::readTemperature(
484 std::string_view sensor_name, Temperature_2_0 *out,
485 std::pair<ThrottlingSeverity, ThrottlingSeverity> *throtting_status,
486 bool is_virtual_sensor) const {
487 // Read the file. If the file can't be read temp will be empty string.
488 std::string temp;
489
490 if (!is_virtual_sensor) {
491 if (!thermal_sensors_.readThermalFile(sensor_name, &temp)) {
492 LOG(ERROR) << "readTemperature: sensor not found: " << sensor_name;
493 return false;
494 }
495
496 if (temp.empty()) {
497 LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
498 return false;
499 }
500 } else {
501 if (!checkVirtualSensor(sensor_name.data(), &temp)) {
502 LOG(ERROR) << "readTemperature: failed to read virtual sensor: " << sensor_name;
503 return false;
504 }
505 }
506
507 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
508 out->type = sensor_info.type;
509 out->name = sensor_name.data();
510 out->value = std::stof(temp) * sensor_info.multiplier;
511
512 std::pair<ThrottlingSeverity, ThrottlingSeverity> status =
513 std::make_pair(ThrottlingSeverity::NONE, ThrottlingSeverity::NONE);
514 // Only update status if the thermal sensor is being monitored
515 if (sensor_info.is_monitor) {
516 ThrottlingSeverity prev_hot_severity, prev_cold_severity;
517 {
518 // reader lock, readTemperature will be called in Binder call and the watcher thread.
519 std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
520 prev_hot_severity = sensor_status_map_.at(sensor_name.data()).prev_hot_severity;
521 prev_cold_severity = sensor_status_map_.at(sensor_name.data()).prev_cold_severity;
522 }
523 status = getSeverityFromThresholds(sensor_info.hot_thresholds, sensor_info.cold_thresholds,
524 sensor_info.hot_hysteresis, sensor_info.cold_hysteresis,
525 prev_hot_severity, prev_cold_severity, out->value);
526 }
527 if (throtting_status) {
528 *throtting_status = status;
529 }
530
531 out->throttlingStatus = static_cast<size_t>(status.first) > static_cast<size_t>(status.second)
532 ? status.first
533 : status.second;
534
535 return true;
536 }
537
readTemperatureThreshold(std::string_view sensor_name,TemperatureThreshold * out) const538 bool ThermalHelper::readTemperatureThreshold(std::string_view sensor_name,
539 TemperatureThreshold *out) const {
540 // Read the file. If the file can't be read temp will be empty string.
541 std::string temp;
542 std::string path;
543
544 if (!sensor_info_map_.count(sensor_name.data())) {
545 LOG(ERROR) << __func__ << ": sensor not found: " << sensor_name;
546 return false;
547 }
548
549 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
550
551 out->type = sensor_info.type;
552 out->name = sensor_name.data();
553 out->hotThrottlingThresholds = sensor_info.hot_thresholds;
554 out->coldThrottlingThresholds = sensor_info.cold_thresholds;
555 out->vrThrottlingThreshold = sensor_info.vr_threshold;
556 return true;
557 }
558
559 // To find the next PID target state according to the current thermal severity
getTargetStateOfPID(const SensorInfo & sensor_info,const SensorStatus & sensor_status)560 size_t ThermalHelper::getTargetStateOfPID(const SensorInfo &sensor_info,
561 const SensorStatus &sensor_status) {
562 size_t target_state = 0;
563
564 for (const auto &severity : hidl_enum_range<ThrottlingSeverity>()) {
565 size_t state = static_cast<size_t>(severity);
566 if (std::isnan(sensor_info.throttling_info->s_power[state])) {
567 continue;
568 }
569 target_state = state;
570 if (severity > sensor_status.severity) {
571 break;
572 }
573 }
574 return target_state;
575 }
576
577 // Return the power budget which is computed by PID algorithm
pidPowerCalculator(const Temperature_2_0 & temp,const SensorInfo & sensor_info,SensorStatus * sensor_status,std::chrono::milliseconds time_elapsed_ms,size_t target_state)578 float ThermalHelper::pidPowerCalculator(const Temperature_2_0 &temp, const SensorInfo &sensor_info,
579 SensorStatus *sensor_status,
580 std::chrono::milliseconds time_elapsed_ms,
581 size_t target_state) {
582 float p = 0, i = 0, d = 0;
583 float power_budget = std::numeric_limits<float>::max();
584
585 LOG(VERBOSE) << "PID target state=" << target_state;
586 if (!target_state || (sensor_status->severity == ThrottlingSeverity::NONE)) {
587 sensor_status->err_integral = 0;
588 sensor_status->prev_err = NAN;
589 return power_budget;
590 }
591
592 // Compute PID
593 float err = sensor_info.hot_thresholds[target_state] - temp.value;
594 p = err * (err < 0 ? sensor_info.throttling_info->k_po[target_state]
595 : sensor_info.throttling_info->k_pu[target_state]);
596 i = sensor_status->err_integral * sensor_info.throttling_info->k_i[target_state];
597 if (err < sensor_info.throttling_info->i_cutoff[target_state]) {
598 float i_next = i + err * sensor_info.throttling_info->k_i[target_state];
599 if (abs(i_next) < sensor_info.throttling_info->i_max[target_state]) {
600 i = i_next;
601 sensor_status->err_integral += err;
602 }
603 }
604
605 if (!std::isnan(sensor_status->prev_err) &&
606 time_elapsed_ms != std::chrono::milliseconds::zero()) {
607 d = sensor_info.throttling_info->k_d[target_state] * (err - sensor_status->prev_err) /
608 time_elapsed_ms.count();
609 }
610
611 sensor_status->prev_err = err;
612 // Calculate power budget
613 power_budget = sensor_info.throttling_info->s_power[target_state] + p + i + d;
614 if (power_budget < sensor_info.throttling_info->min_alloc_power[target_state]) {
615 power_budget = sensor_info.throttling_info->min_alloc_power[target_state];
616 }
617 if (power_budget > sensor_info.throttling_info->max_alloc_power[target_state]) {
618 power_budget = sensor_info.throttling_info->max_alloc_power[target_state];
619 }
620
621 LOG(VERBOSE) << "power_budget=" << power_budget << " err=" << err
622 << " err_integral=" << sensor_status->err_integral
623 << " s_power=" << sensor_info.throttling_info->s_power[target_state]
624 << " time_elpased_ms=" << time_elapsed_ms.count() << " p=" << p << " i=" << i
625 << " d=" << d;
626
627 return power_budget;
628 }
629
requestCdevByPower(std::string_view sensor_name,SensorStatus * sensor_status,const SensorInfo & sensor_info,float total_power_budget,size_t target_state)630 bool ThermalHelper::requestCdevByPower(std::string_view sensor_name, SensorStatus *sensor_status,
631 const SensorInfo &sensor_info, float total_power_budget,
632 size_t target_state) {
633 float total_weight = 0, cdev_power_budget;
634 size_t j;
635
636 for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
637 if (!std::isnan(binded_cdev_info_pair.second.cdev_weight_for_pid[target_state])) {
638 total_weight += binded_cdev_info_pair.second.cdev_weight_for_pid[target_state];
639 }
640 }
641
642 if (!total_weight) {
643 LOG(ERROR) << "Sensor: " << sensor_name.data() << " total weight value is zero";
644 return false;
645 }
646
647 // Map cdev state by power
648 for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
649 const auto cdev_weight = binded_cdev_info_pair.second.cdev_weight_for_pid[target_state];
650 if (!std::isnan(cdev_weight)) {
651 cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
652
653 const CdevInfo &cdev_info_pair =
654 cooling_device_info_map_.at(binded_cdev_info_pair.first);
655 for (j = 0; j < cdev_info_pair.state2power.size() - 1; ++j) {
656 if (cdev_power_budget > cdev_info_pair.state2power[j]) {
657 break;
658 }
659 }
660 sensor_status->pid_request_map.at(binded_cdev_info_pair.first) = static_cast<int>(j);
661 LOG(VERBOSE) << "Power allocator: Sensor " << sensor_name.data() << " allocate "
662 << cdev_power_budget << "mW to " << binded_cdev_info_pair.first
663 << "(cdev_weight=" << cdev_weight << ") update state to " << j;
664 }
665 }
666 return true;
667 }
668
requestCdevBySeverity(std::string_view sensor_name,SensorStatus * sensor_status,const SensorInfo & sensor_info)669 void ThermalHelper::requestCdevBySeverity(std::string_view sensor_name, SensorStatus *sensor_status,
670 const SensorInfo &sensor_info) {
671 for (auto const &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
672 sensor_status->hard_limit_request_map.at(binded_cdev_info_pair.first) =
673 binded_cdev_info_pair.second
674 .limit_info[static_cast<size_t>(sensor_status->severity)];
675 LOG(VERBOSE) << "Hard Limit: Sensor " << sensor_name.data() << " update cdev "
676 << binded_cdev_info_pair.first << " to "
677 << sensor_status->hard_limit_request_map.at(binded_cdev_info_pair.first);
678 }
679 }
680
computeCoolingDevicesRequest(std::string_view sensor_name,const SensorInfo & sensor_info,const SensorStatus & sensor_status,std::vector<std::string> * cooling_devices_to_update)681 void ThermalHelper::computeCoolingDevicesRequest(
682 std::string_view sensor_name, const SensorInfo &sensor_info,
683 const SensorStatus &sensor_status, std::vector<std::string> *cooling_devices_to_update) {
684 int release_step = 0;
685
686 std::unique_lock<std::shared_mutex> _lock(cdev_status_map_mutex_);
687 for (auto &cdev_request_pair : cdev_status_map_) {
688 if (!cdev_request_pair.second.count(sensor_name.data())) {
689 continue;
690 }
691 int pid_request = 0;
692 int hard_limit_request = 0;
693 const auto &binded_cdev_info =
694 sensor_info.throttling_info->binded_cdev_info_map.at(cdev_request_pair.first);
695 const auto cdev_ceiling =
696 binded_cdev_info.cdev_ceiling[static_cast<size_t>(sensor_status.severity)];
697 const auto cdev_floor =
698 binded_cdev_info
699 .cdev_floor_with_power_link[static_cast<size_t>(sensor_status.severity)];
700 release_step = 0;
701
702 if (sensor_status.pid_request_map.count(cdev_request_pair.first)) {
703 pid_request = sensor_status.pid_request_map.at(cdev_request_pair.first);
704 }
705
706 if (sensor_status.hard_limit_request_map.count(cdev_request_pair.first)) {
707 hard_limit_request = sensor_status.hard_limit_request_map.at(cdev_request_pair.first);
708 }
709
710 release_step = power_files_.getReleaseStep(sensor_name, cdev_request_pair.first);
711 LOG(VERBOSE) << "Sensor: " << sensor_name.data() << " binded cooling device "
712 << cdev_request_pair.first << "'s pid_request=" << pid_request
713 << " hard_limit_request=" << hard_limit_request
714 << " release_step=" << release_step
715 << " cdev_floor_with_power_link=" << cdev_floor
716 << " cdev_ceiling=" << cdev_ceiling;
717
718 auto request_state = std::max(pid_request, hard_limit_request);
719 if (release_step) {
720 if (release_step >= request_state) {
721 request_state = 0;
722 } else {
723 request_state = request_state - release_step;
724 }
725 // Only check the cdev_floor when release step is non zero
726 if (request_state < cdev_floor) {
727 request_state = cdev_floor;
728 }
729 }
730
731 if (request_state > cdev_ceiling) {
732 request_state = cdev_ceiling;
733 }
734 if (cdev_request_pair.second.at(sensor_name.data()) != request_state) {
735 cdev_request_pair.second.at(sensor_name.data()) = request_state;
736 cooling_devices_to_update->emplace_back(cdev_request_pair.first);
737 LOG(INFO) << "Sensor: " << sensor_name.data() << " request " << cdev_request_pair.first
738 << " to " << request_state;
739 }
740 }
741 }
742
updateCoolingDevices(const std::vector<std::string> & updated_cdev)743 void ThermalHelper::updateCoolingDevices(const std::vector<std::string> &updated_cdev) {
744 int max_state;
745
746 for (const auto &target_cdev : updated_cdev) {
747 max_state = 0;
748 const CdevRequestStatus &cdev_status = cdev_status_map_.at(target_cdev);
749 for (auto &sensor_request_pair : cdev_status) {
750 if (sensor_request_pair.second > max_state) {
751 max_state = sensor_request_pair.second;
752 }
753 }
754 if (cooling_devices_.writeCdevFile(target_cdev, std::to_string(max_state))) {
755 LOG(VERBOSE) << "Successfully update cdev " << target_cdev << " sysfs to " << max_state;
756 }
757 }
758 }
759
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) const760 std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelper::getSeverityFromThresholds(
761 const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
762 const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
763 ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
764 float value) const {
765 ThrottlingSeverity ret_hot = ThrottlingSeverity::NONE;
766 ThrottlingSeverity ret_hot_hysteresis = ThrottlingSeverity::NONE;
767 ThrottlingSeverity ret_cold = ThrottlingSeverity::NONE;
768 ThrottlingSeverity ret_cold_hysteresis = ThrottlingSeverity::NONE;
769
770 // Here we want to control the iteration from high to low, and hidl_enum_range doesn't support
771 // a reverse iterator yet.
772 for (size_t i = static_cast<size_t>(ThrottlingSeverity::SHUTDOWN);
773 i > static_cast<size_t>(ThrottlingSeverity::NONE); --i) {
774 if (!std::isnan(hot_thresholds[i]) && hot_thresholds[i] <= value &&
775 ret_hot == ThrottlingSeverity::NONE) {
776 ret_hot = static_cast<ThrottlingSeverity>(i);
777 }
778 if (!std::isnan(hot_thresholds[i]) && (hot_thresholds[i] - hot_hysteresis[i]) < value &&
779 ret_hot_hysteresis == ThrottlingSeverity::NONE) {
780 ret_hot_hysteresis = static_cast<ThrottlingSeverity>(i);
781 }
782 if (!std::isnan(cold_thresholds[i]) && cold_thresholds[i] >= value &&
783 ret_cold == ThrottlingSeverity::NONE) {
784 ret_cold = static_cast<ThrottlingSeverity>(i);
785 }
786 if (!std::isnan(cold_thresholds[i]) && (cold_thresholds[i] + cold_hysteresis[i]) > value &&
787 ret_cold_hysteresis == ThrottlingSeverity::NONE) {
788 ret_cold_hysteresis = static_cast<ThrottlingSeverity>(i);
789 }
790 }
791 if (static_cast<size_t>(ret_hot) < static_cast<size_t>(prev_hot_severity)) {
792 ret_hot = ret_hot_hysteresis;
793 }
794 if (static_cast<size_t>(ret_cold) < static_cast<size_t>(prev_cold_severity)) {
795 ret_cold = ret_cold_hysteresis;
796 }
797
798 return std::make_pair(ret_hot, ret_cold);
799 }
800
initializeSensorMap(const std::unordered_map<std::string,std::string> & path_map)801 bool ThermalHelper::initializeSensorMap(
802 const std::unordered_map<std::string, std::string> &path_map) {
803 for (const auto &sensor_info_pair : sensor_info_map_) {
804 std::string_view sensor_name = sensor_info_pair.first;
805 if (sensor_info_pair.second.virtual_sensor_info != nullptr) {
806 continue;
807 }
808 if (!path_map.count(sensor_name.data())) {
809 LOG(ERROR) << "Could not find " << sensor_name << " in sysfs";
810 return false;
811 }
812
813 std::string path;
814 if (sensor_info_pair.second.temp_path.empty()) {
815 path = android::base::StringPrintf("%s/%s", path_map.at(sensor_name.data()).c_str(),
816 kSensorTempSuffix.data());
817 } else {
818 path = sensor_info_pair.second.temp_path;
819 }
820
821 if (!thermal_sensors_.addThermalFile(sensor_name, path)) {
822 LOG(ERROR) << "Could not add " << sensor_name << "to sensors map";
823 return false;
824 }
825 }
826 return true;
827 }
828
initializeCoolingDevices(const std::unordered_map<std::string,std::string> & path_map)829 bool ThermalHelper::initializeCoolingDevices(
830 const std::unordered_map<std::string, std::string> &path_map) {
831 for (auto &cooling_device_info_pair : cooling_device_info_map_) {
832 std::string cooling_device_name = cooling_device_info_pair.first;
833 if (!path_map.count(cooling_device_name)) {
834 LOG(ERROR) << "Could not find " << cooling_device_name << " in sysfs";
835 continue;
836 }
837 // Add cooling device path for thermalHAL to get current state
838 std::string_view path = path_map.at(cooling_device_name);
839 std::string read_path;
840 if (!cooling_device_info_pair.second.read_path.empty()) {
841 read_path = cooling_device_info_pair.second.read_path.data();
842 } else {
843 read_path = android::base::StringPrintf("%s/%s", path.data(),
844 kCoolingDeviceCurStateSuffix.data());
845 }
846 if (!cooling_devices_.addThermalFile(cooling_device_name, read_path)) {
847 LOG(ERROR) << "Could not add " << cooling_device_name
848 << " read path to cooling device map";
849 continue;
850 }
851
852 std::string state2power_path = android::base::StringPrintf(
853 "%s/%s", path.data(), kCoolingDeviceState2powerSuffix.data());
854 std::string state2power_str;
855 if (android::base::ReadFileToString(state2power_path, &state2power_str)) {
856 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first
857 << " use state2power read from sysfs";
858 cooling_device_info_pair.second.state2power.clear();
859
860 std::stringstream power(state2power_str);
861 unsigned int power_number;
862 int i = 0;
863 while (power >> power_number) {
864 cooling_device_info_pair.second.state2power.push_back(
865 static_cast<float>(power_number));
866 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first << " state:" << i
867 << " power: " << power_number;
868 i++;
869 }
870 }
871
872 // Get max cooling device request state
873 std::string max_state;
874 std::string max_state_path = android::base::StringPrintf(
875 "%s/%s", path.data(), kCoolingDeviceMaxStateSuffix.data());
876 if (!android::base::ReadFileToString(max_state_path, &max_state)) {
877 LOG(ERROR) << cooling_device_info_pair.first
878 << " could not open max state file:" << max_state_path;
879 cooling_device_info_pair.second.max_state = std::numeric_limits<int>::max();
880 } else {
881 cooling_device_info_pair.second.max_state = std::stoi(android::base::Trim(max_state));
882 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first
883 << " max state: " << cooling_device_info_pair.second.max_state
884 << " state2power number: "
885 << cooling_device_info_pair.second.state2power.size();
886 if (cooling_device_info_pair.second.state2power.size() > 0 &&
887 cooling_device_info_pair.second.state2power.size() !=
888 (size_t)cooling_device_info_pair.second.max_state + 1) {
889 LOG(ERROR) << "Invalid state2power number: "
890 << cooling_device_info_pair.second.state2power.size()
891 << ", number should be " << cooling_device_info_pair.second.max_state + 1
892 << " (max_state + 1)";
893 }
894 }
895
896 // Add cooling device path for thermalHAL to request state
897 cooling_device_name =
898 android::base::StringPrintf("%s_%s", cooling_device_name.c_str(), "w");
899 std::string write_path;
900 if (!cooling_device_info_pair.second.write_path.empty()) {
901 write_path = cooling_device_info_pair.second.write_path.data();
902 } else {
903 write_path = android::base::StringPrintf("%s/%s", path.data(),
904 kCoolingDeviceCurStateSuffix.data());
905 }
906
907 if (!cooling_devices_.addThermalFile(cooling_device_name, write_path)) {
908 LOG(ERROR) << "Could not add " << cooling_device_name
909 << " write path to cooling device map";
910 continue;
911 }
912 }
913
914 if (cooling_device_info_map_.size() * 2 != cooling_devices_.getNumThermalFiles()) {
915 LOG(ERROR) << "Some cooling device can not be initialized";
916 }
917 return true;
918 }
919
setMinTimeout(SensorInfo * sensor_info)920 void ThermalHelper::setMinTimeout(SensorInfo *sensor_info) {
921 sensor_info->polling_delay = kMinPollIntervalMs;
922 sensor_info->passive_delay = kMinPollIntervalMs;
923 }
924
initializeTrip(const std::unordered_map<std::string,std::string> & path_map,std::set<std::string> * monitored_sensors,bool thermal_genl_enabled)925 void ThermalHelper::initializeTrip(const std::unordered_map<std::string, std::string> &path_map,
926 std::set<std::string> *monitored_sensors,
927 bool thermal_genl_enabled) {
928 for (auto &sensor_info : sensor_info_map_) {
929 if (!sensor_info.second.is_monitor || (sensor_info.second.virtual_sensor_info != nullptr)) {
930 continue;
931 }
932
933 bool trip_update = false;
934 std::string_view sensor_name = sensor_info.first;
935 std::string_view tz_path = path_map.at(sensor_name.data());
936 std::string tz_policy;
937 std::string path =
938 android::base::StringPrintf("%s/%s", (tz_path.data()), kSensorPolicyFile.data());
939
940 if (thermal_genl_enabled) {
941 trip_update = true;
942 } else {
943 // Check if thermal zone support uevent notify
944 if (!android::base::ReadFileToString(path, &tz_policy)) {
945 LOG(ERROR) << sensor_name << " could not open tz policy file:" << path;
946 } else {
947 tz_policy = android::base::Trim(tz_policy);
948 if (tz_policy != kUserSpaceSuffix) {
949 LOG(ERROR) << sensor_name << " does not support uevent notify";
950 } else {
951 trip_update = true;
952 }
953 }
954 }
955 if (trip_update) {
956 // Update thermal zone trip point
957 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
958 if (!std::isnan(sensor_info.second.hot_thresholds[i]) &&
959 !std::isnan(sensor_info.second.hot_hysteresis[i])) {
960 // Update trip_point_0_temp threshold
961 std::string threshold = std::to_string(static_cast<int>(
962 sensor_info.second.hot_thresholds[i] / sensor_info.second.multiplier));
963 path = android::base::StringPrintf("%s/%s", (tz_path.data()),
964 kSensorTripPointTempZeroFile.data());
965 if (!android::base::WriteStringToFile(threshold, path)) {
966 LOG(ERROR) << "fail to update " << sensor_name << " trip point: " << path
967 << " to " << threshold;
968 trip_update = false;
969 break;
970 }
971 // Update trip_point_0_hyst threshold
972 threshold = std::to_string(static_cast<int>(
973 sensor_info.second.hot_hysteresis[i] / sensor_info.second.multiplier));
974 path = android::base::StringPrintf("%s/%s", (tz_path.data()),
975 kSensorTripPointHystZeroFile.data());
976 if (!android::base::WriteStringToFile(threshold, path)) {
977 LOG(ERROR) << "fail to update " << sensor_name << "trip hyst" << threshold
978 << path;
979 trip_update = false;
980 break;
981 }
982 break;
983 } else if (i == kThrottlingSeverityCount - 1) {
984 LOG(ERROR) << sensor_name << ":all thresholds are NAN";
985 trip_update = false;
986 break;
987 }
988 }
989 monitored_sensors->insert(sensor_info.first);
990 }
991
992 if (!trip_update) {
993 LOG(INFO) << "config Sensor: " << sensor_info.first
994 << " to default polling interval: " << kMinPollIntervalMs.count();
995 setMinTimeout(&sensor_info.second);
996 }
997 }
998 }
999
fillTemperatures(hidl_vec<Temperature_1_0> * temperatures) const1000 bool ThermalHelper::fillTemperatures(hidl_vec<Temperature_1_0> *temperatures) const {
1001 temperatures->resize(sensor_info_map_.size());
1002 int current_index = 0;
1003 for (const auto &name_info_pair : sensor_info_map_) {
1004 Temperature_1_0 temp;
1005
1006 if (readTemperature(name_info_pair.first, &temp,
1007 name_info_pair.second.virtual_sensor_info != nullptr)) {
1008 (*temperatures)[current_index] = temp;
1009 } else {
1010 LOG(ERROR) << __func__
1011 << ": error reading temperature for sensor: " << name_info_pair.first;
1012 return false;
1013 }
1014 ++current_index;
1015 }
1016 return current_index > 0;
1017 }
1018
fillCurrentTemperatures(bool filterType,bool filterCallback,TemperatureType_2_0 type,hidl_vec<Temperature_2_0> * temperatures) const1019 bool ThermalHelper::fillCurrentTemperatures(bool filterType, bool filterCallback,
1020 TemperatureType_2_0 type,
1021 hidl_vec<Temperature_2_0> *temperatures) const {
1022 std::vector<Temperature_2_0> ret;
1023 for (const auto &name_info_pair : sensor_info_map_) {
1024 Temperature_2_0 temp;
1025 if (filterType && name_info_pair.second.type != type) {
1026 continue;
1027 }
1028 if (filterCallback && !name_info_pair.second.send_cb) {
1029 continue;
1030 }
1031 if (readTemperature(name_info_pair.first, &temp, nullptr,
1032 name_info_pair.second.virtual_sensor_info != nullptr)) {
1033 ret.emplace_back(std::move(temp));
1034 } else {
1035 LOG(ERROR) << __func__
1036 << ": error reading temperature for sensor: " << name_info_pair.first;
1037 }
1038 }
1039 *temperatures = ret;
1040 return ret.size() > 0;
1041 }
1042
fillTemperatureThresholds(bool filterType,TemperatureType_2_0 type,hidl_vec<TemperatureThreshold> * thresholds) const1043 bool ThermalHelper::fillTemperatureThresholds(bool filterType, TemperatureType_2_0 type,
1044 hidl_vec<TemperatureThreshold> *thresholds) const {
1045 std::vector<TemperatureThreshold> ret;
1046 for (const auto &name_info_pair : sensor_info_map_) {
1047 TemperatureThreshold temp;
1048 if (filterType && name_info_pair.second.type != type) {
1049 continue;
1050 }
1051 if (readTemperatureThreshold(name_info_pair.first, &temp)) {
1052 ret.emplace_back(std::move(temp));
1053 } else {
1054 LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
1055 << name_info_pair.first;
1056 return false;
1057 }
1058 }
1059 *thresholds = ret;
1060 return ret.size() > 0;
1061 }
1062
fillCurrentCoolingDevices(bool filterType,CoolingType type,hidl_vec<CoolingDevice_2_0> * cooling_devices) const1063 bool ThermalHelper::fillCurrentCoolingDevices(bool filterType, CoolingType type,
1064 hidl_vec<CoolingDevice_2_0> *cooling_devices) const {
1065 std::vector<CoolingDevice_2_0> ret;
1066 for (const auto &name_info_pair : cooling_device_info_map_) {
1067 CoolingDevice_2_0 value;
1068 if (filterType && name_info_pair.second.type != type) {
1069 continue;
1070 }
1071 if (readCoolingDevice(name_info_pair.first, &value)) {
1072 ret.emplace_back(std::move(value));
1073 } else {
1074 LOG(ERROR) << __func__ << ": error reading cooling device: " << name_info_pair.first;
1075 return false;
1076 }
1077 }
1078 *cooling_devices = ret;
1079 return ret.size() > 0;
1080 }
1081
fillCpuUsages(hidl_vec<CpuUsage> * cpu_usages) const1082 bool ThermalHelper::fillCpuUsages(hidl_vec<CpuUsage> *cpu_usages) const {
1083 cpu_usages->resize(kMaxCpus);
1084 for (int i = 0; i < kMaxCpus; i++) {
1085 (*cpu_usages)[i].name = StringPrintf("cpu%d", i);
1086 (*cpu_usages)[i].active = 0;
1087 (*cpu_usages)[i].total = 0;
1088 (*cpu_usages)[i].isOnline = false;
1089 }
1090 parseCpuUsagesFileAndAssignUsages(cpu_usages);
1091 return true;
1092 }
1093
checkVirtualSensor(std::string_view sensor_name,std::string * temp) const1094 bool ThermalHelper::checkVirtualSensor(std::string_view sensor_name, std::string *temp) const {
1095 float temp_val = 0.0;
1096
1097 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
1098 float offset = sensor_info.virtual_sensor_info->offset;
1099 for (size_t i = 0; i < sensor_info.virtual_sensor_info->linked_sensors.size(); i++) {
1100 std::string data;
1101 const auto &linked_sensor_info =
1102 sensor_info_map_.at(sensor_info.virtual_sensor_info->linked_sensors[i].data());
1103 if (linked_sensor_info.virtual_sensor_info == nullptr) {
1104 if (!thermal_sensors_.readThermalFile(
1105 sensor_info.virtual_sensor_info->linked_sensors[i], &data)) {
1106 continue;
1107 }
1108 } else if (!checkVirtualSensor(sensor_info.virtual_sensor_info->linked_sensors[i], &data)) {
1109 return false;
1110 }
1111
1112 LOG(VERBOSE) << sensor_name.data() << "'s linked sensor "
1113 << sensor_info.virtual_sensor_info->linked_sensors[i] << ": temp = " << data;
1114 data = ::android::base::Trim(data);
1115 float sensor_reading = std::stof(data);
1116 if (std::isnan(sensor_info.virtual_sensor_info->coefficients[i])) {
1117 return false;
1118 }
1119 float coefficient = sensor_info.virtual_sensor_info->coefficients[i];
1120 switch (sensor_info.virtual_sensor_info->formula) {
1121 case FormulaOption::COUNT_THRESHOLD:
1122 if ((coefficient < 0 && sensor_reading < -coefficient) ||
1123 (coefficient >= 0 && sensor_reading >= coefficient))
1124 temp_val += 1;
1125 break;
1126 case FormulaOption::WEIGHTED_AVG:
1127 temp_val += sensor_reading * coefficient;
1128 break;
1129 case FormulaOption::MAXIMUM:
1130 if (i == 0)
1131 temp_val = std::numeric_limits<float>::lowest();
1132 if (sensor_reading * coefficient > temp_val)
1133 temp_val = sensor_reading * coefficient;
1134 break;
1135 case FormulaOption::MINIMUM:
1136 if (i == 0)
1137 temp_val = std::numeric_limits<float>::max();
1138 if (sensor_reading * coefficient < temp_val)
1139 temp_val = sensor_reading * coefficient;
1140 break;
1141 default:
1142 break;
1143 }
1144 }
1145 *temp = std::to_string(temp_val + offset);
1146 return true;
1147 }
1148
1149 // This is called in the different thread context and will update sensor_status
1150 // uevent_sensors is the set of sensors which trigger uevent from thermal core driver.
thermalWatcherCallbackFunc(const std::set<std::string> & uevent_sensors)1151 std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc(
1152 const std::set<std::string> &uevent_sensors) {
1153 std::vector<Temperature_2_0> temps;
1154 std::vector<std::string> cooling_devices_to_update;
1155 std::set<std::string> updated_power_rails;
1156 boot_clock::time_point now = boot_clock::now();
1157 auto min_sleep_ms = std::chrono::milliseconds::max();
1158
1159 for (auto &name_status_pair : sensor_status_map_) {
1160 bool force_update = false;
1161 bool severity_changed = false;
1162 Temperature_2_0 temp;
1163 TemperatureThreshold threshold;
1164 SensorStatus &sensor_status = name_status_pair.second;
1165 const SensorInfo &sensor_info = sensor_info_map_.at(name_status_pair.first);
1166
1167 // Only handle the sensors in allow list
1168 if (!sensor_info.is_monitor) {
1169 continue;
1170 }
1171
1172 std::chrono::milliseconds time_elapsed_ms = std::chrono::milliseconds::zero();
1173 auto sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
1174 ? sensor_info.passive_delay
1175 : sensor_info.polling_delay;
1176 // Check if the sensor need to be updated
1177 if (sensor_status.last_update_time == boot_clock::time_point::min()) {
1178 force_update = true;
1179 LOG(VERBOSE) << "Force update " << name_status_pair.first
1180 << "'s temperature after booting";
1181 } else {
1182 time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
1183 now - sensor_status.last_update_time);
1184
1185 if (time_elapsed_ms > sleep_ms) {
1186 // Update the sensor because sleep timeout
1187 force_update = true;
1188 } else if (uevent_sensors.size() &&
1189 uevent_sensors.find((sensor_info.virtual_sensor_info != nullptr)
1190 ? sensor_info.virtual_sensor_info->trigger_sensor
1191 : name_status_pair.first) !=
1192 uevent_sensors.end()) {
1193 // Update the sensor from uevent
1194 force_update = true;
1195 } else if (sensor_info.virtual_sensor_info != nullptr) {
1196 // Update the virtual sensor if it's trigger sensor over the threshold
1197 const auto trigger_sensor_status =
1198 sensor_status_map_.at(sensor_info.virtual_sensor_info->trigger_sensor);
1199 if (trigger_sensor_status.severity != ThrottlingSeverity::NONE) {
1200 force_update = true;
1201 }
1202 }
1203 }
1204
1205 LOG(VERBOSE) << "sensor " << name_status_pair.first
1206 << ": time_elpased=" << time_elapsed_ms.count()
1207 << ", sleep_ms=" << sleep_ms.count() << ", force_update = " << force_update;
1208
1209 if (!force_update) {
1210 auto timeout_remaining = sleep_ms - time_elapsed_ms;
1211 if (min_sleep_ms > timeout_remaining) {
1212 min_sleep_ms = timeout_remaining;
1213 }
1214 LOG(VERBOSE) << "sensor " << name_status_pair.first
1215 << ": timeout_remaining=" << timeout_remaining.count();
1216 continue;
1217 }
1218
1219 std::pair<ThrottlingSeverity, ThrottlingSeverity> throtting_status;
1220 if (!readTemperature(name_status_pair.first, &temp, &throtting_status,
1221 (sensor_info.virtual_sensor_info != nullptr))) {
1222 LOG(ERROR) << __func__
1223 << ": error reading temperature for sensor: " << name_status_pair.first;
1224 continue;
1225 }
1226 if (!readTemperatureThreshold(name_status_pair.first, &threshold)) {
1227 LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
1228 << name_status_pair.first;
1229 continue;
1230 }
1231
1232 {
1233 // writer lock
1234 std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
1235 if (throtting_status.first != sensor_status.prev_hot_severity) {
1236 sensor_status.prev_hot_severity = throtting_status.first;
1237 }
1238 if (throtting_status.second != sensor_status.prev_cold_severity) {
1239 sensor_status.prev_cold_severity = throtting_status.second;
1240 }
1241 if (temp.throttlingStatus != sensor_status.severity) {
1242 temps.push_back(temp);
1243 severity_changed = true;
1244 sensor_status.severity = temp.throttlingStatus;
1245 sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
1246 ? sensor_info.passive_delay
1247 : sensor_info.polling_delay;
1248 }
1249 }
1250
1251 if (sensor_status.severity != ThrottlingSeverity::NONE) {
1252 LOG(INFO) << temp.name << ": " << temp.value << " degC";
1253 } else {
1254 LOG(VERBOSE) << temp.name << ": " << temp.value << " degC";
1255 }
1256
1257 // Start PID computation
1258 if (sensor_status.pid_request_map.size()) {
1259 size_t target_state = getTargetStateOfPID(sensor_info, sensor_status);
1260 float power_budget = pidPowerCalculator(temp, sensor_info, &sensor_status,
1261 time_elapsed_ms, target_state);
1262 if (!requestCdevByPower(name_status_pair.first, &sensor_status, sensor_info,
1263 power_budget, target_state)) {
1264 LOG(ERROR) << "Sensor " << temp.name << " PID request cdev failed";
1265 }
1266 }
1267
1268 if (sensor_status.hard_limit_request_map.size()) {
1269 // Start hard limit computation
1270 requestCdevBySeverity(name_status_pair.first, &sensor_status, sensor_info);
1271 }
1272
1273 // Aggregate cooling device request
1274 if (sensor_status.pid_request_map.size() || sensor_status.hard_limit_request_map.size()) {
1275 if (sensor_status.severity == ThrottlingSeverity::NONE) {
1276 power_files_.setPowerDataToDefault(name_status_pair.first);
1277 } else {
1278 for (const auto &binded_cdev_info_pair :
1279 sensor_info.throttling_info->binded_cdev_info_map) {
1280 if (binded_cdev_info_pair.second.power_rail != "") {
1281 const auto &power_rail_info =
1282 power_rail_info_map_.at(binded_cdev_info_pair.second.power_rail);
1283
1284 if (power_files_.throttlingReleaseUpdate(
1285 name_status_pair.first, binded_cdev_info_pair.first,
1286 sensor_status.severity, time_elapsed_ms,
1287 binded_cdev_info_pair.second, power_rail_info,
1288 !updated_power_rails.count(
1289 binded_cdev_info_pair.second.power_rail),
1290 severity_changed)) {
1291 updated_power_rails.insert(binded_cdev_info_pair.second.power_rail);
1292 }
1293 }
1294 }
1295 }
1296 computeCoolingDevicesRequest(name_status_pair.first, sensor_info, sensor_status,
1297 &cooling_devices_to_update);
1298 }
1299
1300 if (min_sleep_ms > sleep_ms) {
1301 min_sleep_ms = sleep_ms;
1302 }
1303 LOG(VERBOSE) << "Sensor " << name_status_pair.first << ": sleep_ms=" << sleep_ms.count()
1304 << ", min_sleep_ms voting result=" << min_sleep_ms.count();
1305 sensor_status.last_update_time = now;
1306 }
1307
1308 if (!cooling_devices_to_update.empty()) {
1309 updateCoolingDevices(cooling_devices_to_update);
1310 }
1311
1312 if (!temps.empty()) {
1313 for (const auto &t : temps) {
1314 if (sensor_info_map_.at(t.name).send_cb && cb_) {
1315 cb_(t);
1316 }
1317
1318 if (sensor_info_map_.at(t.name).send_powerhint && isAidlPowerHalExist()) {
1319 sendPowerExtHint(t);
1320 }
1321 }
1322 }
1323
1324 power_files_.clearEnergyInfoMap();
1325 return min_sleep_ms < kMinPollIntervalMs ? kMinPollIntervalMs : min_sleep_ms;
1326 }
1327
connectToPowerHal()1328 bool ThermalHelper::connectToPowerHal() {
1329 return power_hal_service_.connect();
1330 }
1331
updateSupportedPowerHints()1332 void ThermalHelper::updateSupportedPowerHints() {
1333 for (auto const &name_status_pair : sensor_info_map_) {
1334 if (!(name_status_pair.second.send_powerhint)) {
1335 continue;
1336 }
1337 ThrottlingSeverity current_severity = ThrottlingSeverity::NONE;
1338 for (const auto &severity : hidl_enum_range<ThrottlingSeverity>()) {
1339 if (severity == ThrottlingSeverity::NONE) {
1340 supported_powerhint_map_[name_status_pair.first][ThrottlingSeverity::NONE] =
1341 ThrottlingSeverity::NONE;
1342 continue;
1343 }
1344
1345 bool isSupported = false;
1346 ndk::ScopedAStatus isSupportedResult;
1347
1348 if (power_hal_service_.isPowerHalExtConnected()) {
1349 isSupported = power_hal_service_.isModeSupported(name_status_pair.first, severity);
1350 }
1351 if (isSupported)
1352 current_severity = severity;
1353 supported_powerhint_map_[name_status_pair.first][severity] = current_severity;
1354 }
1355 }
1356 }
1357
sendPowerExtHint(const Temperature_2_0 & t)1358 void ThermalHelper::sendPowerExtHint(const Temperature_2_0 &t) {
1359 std::lock_guard<std::shared_mutex> lock(sensor_status_map_mutex_);
1360
1361 ThrottlingSeverity prev_hint_severity;
1362 prev_hint_severity = sensor_status_map_.at(t.name).prev_hint_severity;
1363 ThrottlingSeverity current_hint_severity = supported_powerhint_map_[t.name][t.throttlingStatus];
1364
1365 if (prev_hint_severity == current_hint_severity)
1366 return;
1367
1368 if (prev_hint_severity != ThrottlingSeverity::NONE) {
1369 power_hal_service_.setMode(t.name, prev_hint_severity, false);
1370 }
1371
1372 if (current_hint_severity != ThrottlingSeverity::NONE) {
1373 power_hal_service_.setMode(t.name, current_hint_severity, true);
1374 }
1375
1376 sensor_status_map_[t.name].prev_hint_severity = current_hint_severity;
1377 }
1378 } // namespace implementation
1379 } // namespace V2_0
1380 } // namespace thermal
1381 } // namespace hardware
1382 } // namespace android
1383