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 #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 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
63 /*
64 * Pixel don't offline CPU, so std::thread::hardware_concurrency(); should work.
65 * However /sys/devices/system/cpu/present is preferred.
66 * The file is expected to contain single text line with two numbers %d-%d,
67 * which is a range of available cpu numbers, e.g. 0-7 would mean there
68 * are 8 cores number from 0 to 7.
69 * For Android systems this approach is safer than using cpufeatures, see bug
70 * b/36941727.
71 */
getNumberOfCores()72 static int getNumberOfCores() {
73 std::string file;
74 if (!android::base::ReadFileToString(kCpuPresentFile.data(), &file)) {
75 LOG(ERROR) << "Error reading CPU present file: " << kCpuPresentFile;
76 return 0;
77 }
78 std::vector<std::string> pieces = android::base::Split(file, "-");
79 if (pieces.size() != 2) {
80 LOG(ERROR) << "Error parsing CPU present file content: " << file;
81 return 0;
82 }
83 auto min_core = std::stoul(pieces[0]);
84 auto max_core = std::stoul(pieces[1]);
85 if (max_core < min_core) {
86 LOG(ERROR) << "Error parsing CPU present min and max: " << min_core << " - " << max_core;
87 return 0;
88 }
89 return static_cast<std::size_t>(max_core - min_core + 1);
90 }
91 const int kMaxCpus = getNumberOfCores();
92
parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> * cpu_usages)93 void parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> *cpu_usages) {
94 std::string data;
95 if (!android::base::ReadFileToString(kCpuUsageFile.data(), &data)) {
96 LOG(ERROR) << "Error reading CPU usage file: " << kCpuUsageFile;
97 return;
98 }
99
100 std::istringstream stat_data(data);
101 std::string line;
102 while (std::getline(stat_data, line)) {
103 if (!line.find("cpu") && isdigit(line[3])) {
104 // Split the string using spaces.
105 std::vector<std::string> words = android::base::Split(line, " ");
106 std::string cpu_name = words[0];
107 int cpu_num = std::stoi(cpu_name.substr(3));
108
109 if (cpu_num < kMaxCpus) {
110 uint64_t user = std::stoull(words[1]);
111 uint64_t nice = std::stoull(words[2]);
112 uint64_t system = std::stoull(words[3]);
113 uint64_t idle = std::stoull(words[4]);
114
115 // Check if the CPU is online by reading the online file.
116 std::string cpu_online_path =
117 StringPrintf("%s/%s/%s", kCpuOnlineRoot.data(), cpu_name.c_str(),
118 kCpuOnlineFileSuffix.data());
119 std::string is_online;
120 if (!android::base::ReadFileToString(cpu_online_path, &is_online)) {
121 LOG(ERROR) << "Could not open CPU online file: " << cpu_online_path;
122 if (cpu_num != 0) {
123 return;
124 }
125 // Some architecture cannot offline cpu0, so assuming it is online
126 is_online = "1";
127 }
128 is_online = android::base::Trim(is_online);
129
130 (*cpu_usages)[cpu_num].active = user + nice + system;
131 (*cpu_usages)[cpu_num].total = user + nice + system + idle;
132 (*cpu_usages)[cpu_num].isOnline = (is_online == "1") ? true : false;
133 } else {
134 LOG(ERROR) << "Unexpected CPU number: " << words[0];
135 return;
136 }
137 }
138 }
139 }
140
parseThermalPathMap(std::string_view prefix)141 std::unordered_map<std::string, std::string> parseThermalPathMap(std::string_view prefix) {
142 std::unordered_map<std::string, std::string> path_map;
143 std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(kThermalSensorsRoot.data()), closedir);
144 if (!dir) {
145 return path_map;
146 }
147
148 // std::filesystem is not available for vendor yet
149 // see discussion: aosp/894015
150 while (struct dirent *dp = readdir(dir.get())) {
151 if (dp->d_type != DT_DIR) {
152 continue;
153 }
154
155 if (!android::base::StartsWith(dp->d_name, prefix.data())) {
156 continue;
157 }
158
159 std::string path = android::base::StringPrintf("%s/%s/%s", kThermalSensorsRoot.data(),
160 dp->d_name, kThermalNameFile.data());
161 std::string name;
162 if (!android::base::ReadFileToString(path, &name)) {
163 PLOG(ERROR) << "Failed to read from " << path;
164 continue;
165 }
166
167 path_map.emplace(
168 android::base::Trim(name),
169 android::base::StringPrintf("%s/%s", kThermalSensorsRoot.data(), dp->d_name));
170 }
171
172 return path_map;
173 }
174
175 } // namespace
176
177 /*
178 * Populate the sensor_name_to_file_map_ map by walking through the file tree,
179 * reading the type file and assigning the temp file path to the map. If we do
180 * not succeed, abort.
181 */
ThermalHelper(const NotificationCallback & cb)182 ThermalHelper::ThermalHelper(const NotificationCallback &cb)
183 : thermal_watcher_(new ThermalWatcher(
184 std::bind(&ThermalHelper::thermalWatcherCallbackFunc, this, std::placeholders::_1))),
185 cb_(cb) {
186 const std::string config_path =
187 "/vendor/etc/" +
188 android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data());
189 bool thermal_throttling_disabled =
190 android::base::GetBoolProperty(kThermalDisabledProperty.data(), false);
191
192 is_initialized_ = ParseCoolingDevice(config_path, &cooling_device_info_map_) &&
193 ParseSensorInfo(config_path, &sensor_info_map_);
194
195 if (thermal_throttling_disabled) {
196 return;
197 }
198
199 if (!is_initialized_) {
200 LOG(FATAL) << "Failed to parse thermal configs";
201 }
202
203 auto tz_map = parseThermalPathMap(kSensorPrefix.data());
204 auto cdev_map = parseThermalPathMap(kCoolingDevicePrefix.data());
205
206 is_initialized_ = initializeSensorMap(tz_map) && initializeCoolingDevices(cdev_map);
207
208 if (!is_initialized_) {
209 LOG(FATAL) << "ThermalHAL could not be initialized properly.";
210 }
211
212 if (!power_files_.registerPowerRailsToWatch(config_path)) {
213 LOG(FATAL) << "Failed to register power rails";
214 }
215
216 for (auto const &name_status_pair : sensor_info_map_) {
217 sensor_status_map_[name_status_pair.first] = {
218 .severity = ThrottlingSeverity::NONE,
219 .prev_hot_severity = ThrottlingSeverity::NONE,
220 .prev_cold_severity = ThrottlingSeverity::NONE,
221 .prev_hint_severity = ThrottlingSeverity::NONE,
222 .last_update_time = boot_clock::time_point::min(),
223 .thermal_cached = {NAN, boot_clock::time_point::min()},
224 };
225
226 if (name_status_pair.second.throttling_info != nullptr) {
227 if (!thermal_throttling_.registerThermalThrottling(
228 name_status_pair.first, name_status_pair.second.throttling_info,
229 cooling_device_info_map_)) {
230 LOG(FATAL) << name_status_pair.first << " failed to register thermal throttling";
231 }
232 }
233
234 // Update cooling device max state
235 for (auto &binded_cdev_pair :
236 name_status_pair.second.throttling_info->binded_cdev_info_map) {
237 const auto &cdev_info = cooling_device_info_map_.at(binded_cdev_pair.first);
238
239 for (auto &cdev_ceiling : binded_cdev_pair.second.cdev_ceiling) {
240 if (cdev_ceiling > cdev_info.max_state) {
241 if (cdev_ceiling != std::numeric_limits<int>::max()) {
242 LOG(ERROR) << "Sensor " << name_status_pair.first << "'s "
243 << binded_cdev_pair.first << " cdev_ceiling:" << cdev_ceiling
244 << " is higher than max state:" << cdev_info.max_state;
245 }
246 cdev_ceiling = cdev_info.max_state;
247 }
248 }
249 }
250
251 if (name_status_pair.second.virtual_sensor_info != nullptr &&
252 !name_status_pair.second.virtual_sensor_info->trigger_sensor.empty() &&
253 name_status_pair.second.is_watch) {
254 if (sensor_info_map_.count(
255 name_status_pair.second.virtual_sensor_info->trigger_sensor)) {
256 sensor_info_map_[name_status_pair.second.virtual_sensor_info->trigger_sensor]
257 .is_watch = true;
258 } else {
259 LOG(FATAL) << name_status_pair.first << "'s trigger sensor: "
260 << name_status_pair.second.virtual_sensor_info->trigger_sensor
261 << " is invalid";
262 }
263 }
264 }
265
266 const bool thermal_genl_enabled =
267 android::base::GetBoolProperty(kThermalGenlProperty.data(), false);
268
269 std::set<std::string> monitored_sensors;
270 initializeTrip(tz_map, &monitored_sensors, thermal_genl_enabled);
271
272 if (thermal_genl_enabled) {
273 thermal_watcher_->registerFilesToWatchNl(monitored_sensors);
274 } else {
275 thermal_watcher_->registerFilesToWatch(monitored_sensors);
276 }
277
278 // Need start watching after status map initialized
279 is_initialized_ = thermal_watcher_->startWatchingDeviceFiles();
280 if (!is_initialized_) {
281 LOG(FATAL) << "ThermalHAL could not start watching thread properly.";
282 }
283
284 if (!connectToPowerHal()) {
285 LOG(ERROR) << "Fail to connect to Power Hal";
286 } else {
287 updateSupportedPowerHints();
288 }
289 }
290
getThermalZoneTypeById(int tz_id,std::string * type)291 bool getThermalZoneTypeById(int tz_id, std::string *type) {
292 std::string tz_type;
293 std::string path =
294 android::base::StringPrintf("%s/%s%d/%s", kThermalSensorsRoot.data(),
295 kSensorPrefix.data(), tz_id, kThermalNameFile.data());
296 LOG(INFO) << "TZ Path: " << path;
297 if (!::android::base::ReadFileToString(path, &tz_type)) {
298 LOG(ERROR) << "Failed to read sensor: " << tz_type;
299 return false;
300 }
301
302 // Strip the newline.
303 *type = ::android::base::Trim(tz_type);
304 LOG(INFO) << "TZ type: " << *type;
305 return true;
306 }
307
readCoolingDevice(std::string_view cooling_device,CoolingDevice_2_0 * out) const308 bool ThermalHelper::readCoolingDevice(std::string_view cooling_device,
309 CoolingDevice_2_0 *out) const {
310 // Read the file. If the file can't be read temp will be empty string.
311 std::string data;
312
313 if (!cooling_devices_.readThermalFile(cooling_device, &data)) {
314 LOG(ERROR) << "readCoolingDevice: failed to read cooling_device: " << cooling_device;
315 return false;
316 }
317
318 const CdevInfo &cdev_info = cooling_device_info_map_.at(cooling_device.data());
319 const CoolingType &type = cdev_info.type;
320
321 out->type = type;
322 out->name = cooling_device.data();
323 out->value = std::stoi(data);
324
325 return true;
326 }
327
readTemperature(std::string_view sensor_name,Temperature_1_0 * out)328 bool ThermalHelper::readTemperature(std::string_view sensor_name, Temperature_1_0 *out) {
329 // Return fail if the thermal sensor cannot be read.
330 float temp;
331 if (!readThermalSensor(sensor_name, &temp, false)) {
332 LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
333 return false;
334 }
335
336 const SensorInfo &sensor_info = sensor_info_map_.at(sensor_name.data());
337 TemperatureType_1_0 type =
338 (static_cast<int>(sensor_info.type) > static_cast<int>(TemperatureType_1_0::SKIN))
339 ? TemperatureType_1_0::UNKNOWN
340 : static_cast<TemperatureType_1_0>(sensor_info.type);
341 out->type = type;
342 out->name = sensor_name.data();
343 out->currentValue = temp * sensor_info.multiplier;
344 out->throttlingThreshold =
345 sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)];
346 out->shutdownThreshold =
347 sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SHUTDOWN)];
348 out->vrThrottlingThreshold = sensor_info.vr_threshold;
349
350 return true;
351 }
352
readTemperature(std::string_view sensor_name,Temperature_2_0 * out,std::pair<ThrottlingSeverity,ThrottlingSeverity> * throtting_status,const bool force_sysfs)353 bool ThermalHelper::readTemperature(
354 std::string_view sensor_name, Temperature_2_0 *out,
355 std::pair<ThrottlingSeverity, ThrottlingSeverity> *throtting_status,
356 const bool force_sysfs) {
357 // Return fail if the thermal sensor cannot be read.
358 float temp;
359
360 if (!readThermalSensor(sensor_name, &temp, force_sysfs)) {
361 LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
362 return false;
363 }
364
365 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
366 out->type = sensor_info.type;
367 out->name = sensor_name.data();
368 out->value = temp * sensor_info.multiplier;
369
370 std::pair<ThrottlingSeverity, ThrottlingSeverity> status =
371 std::make_pair(ThrottlingSeverity::NONE, ThrottlingSeverity::NONE);
372 // Only update status if the thermal sensor is being monitored
373 if (sensor_info.is_watch) {
374 ThrottlingSeverity prev_hot_severity, prev_cold_severity;
375 {
376 // reader lock, readTemperature will be called in Binder call and the watcher thread.
377 std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
378 prev_hot_severity = sensor_status_map_.at(sensor_name.data()).prev_hot_severity;
379 prev_cold_severity = sensor_status_map_.at(sensor_name.data()).prev_cold_severity;
380 }
381 status = getSeverityFromThresholds(sensor_info.hot_thresholds, sensor_info.cold_thresholds,
382 sensor_info.hot_hysteresis, sensor_info.cold_hysteresis,
383 prev_hot_severity, prev_cold_severity, out->value);
384 }
385 if (throtting_status) {
386 *throtting_status = status;
387 }
388
389 out->throttlingStatus = static_cast<size_t>(status.first) > static_cast<size_t>(status.second)
390 ? status.first
391 : status.second;
392
393 return true;
394 }
395
readTemperatureThreshold(std::string_view sensor_name,TemperatureThreshold * out) const396 bool ThermalHelper::readTemperatureThreshold(std::string_view sensor_name,
397 TemperatureThreshold *out) const {
398 // Read the file. If the file can't be read temp will be empty string.
399 std::string temp;
400 std::string path;
401
402 if (!sensor_info_map_.count(sensor_name.data())) {
403 LOG(ERROR) << __func__ << ": sensor not found: " << sensor_name;
404 return false;
405 }
406
407 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
408
409 out->type = sensor_info.type;
410 out->name = sensor_name.data();
411 out->hotThrottlingThresholds = sensor_info.hot_thresholds;
412 out->coldThrottlingThresholds = sensor_info.cold_thresholds;
413 out->vrThrottlingThreshold = sensor_info.vr_threshold;
414 return true;
415 }
416
updateCoolingDevices(const std::vector<std::string> & updated_cdev)417 void ThermalHelper::updateCoolingDevices(const std::vector<std::string> &updated_cdev) {
418 int max_state;
419
420 const auto &thermal_throttling_status_map = thermal_throttling_.GetThermalThrottlingStatusMap();
421
422 for (const auto &target_cdev : updated_cdev) {
423 max_state = 0;
424 for (const auto &thermal_throttling_status_pair : thermal_throttling_status_map) {
425 if (!thermal_throttling_status_pair.second.cdev_status_map.count(target_cdev)) {
426 continue;
427 }
428 const auto state =
429 thermal_throttling_status_pair.second.cdev_status_map.at(target_cdev);
430 if (state > max_state) {
431 max_state = state;
432 }
433 }
434 if (cooling_devices_.writeCdevFile(target_cdev, std::to_string(max_state))) {
435 LOG(INFO) << "Successfully update cdev " << target_cdev << " sysfs to " << max_state;
436 }
437 }
438 }
439
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) const440 std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelper::getSeverityFromThresholds(
441 const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
442 const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
443 ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
444 float value) const {
445 ThrottlingSeverity ret_hot = ThrottlingSeverity::NONE;
446 ThrottlingSeverity ret_hot_hysteresis = ThrottlingSeverity::NONE;
447 ThrottlingSeverity ret_cold = ThrottlingSeverity::NONE;
448 ThrottlingSeverity ret_cold_hysteresis = ThrottlingSeverity::NONE;
449
450 // Here we want to control the iteration from high to low, and hidl_enum_range doesn't support
451 // a reverse iterator yet.
452 for (size_t i = static_cast<size_t>(ThrottlingSeverity::SHUTDOWN);
453 i > static_cast<size_t>(ThrottlingSeverity::NONE); --i) {
454 if (!std::isnan(hot_thresholds[i]) && hot_thresholds[i] <= value &&
455 ret_hot == ThrottlingSeverity::NONE) {
456 ret_hot = static_cast<ThrottlingSeverity>(i);
457 }
458 if (!std::isnan(hot_thresholds[i]) && (hot_thresholds[i] - hot_hysteresis[i]) < value &&
459 ret_hot_hysteresis == ThrottlingSeverity::NONE) {
460 ret_hot_hysteresis = static_cast<ThrottlingSeverity>(i);
461 }
462 if (!std::isnan(cold_thresholds[i]) && cold_thresholds[i] >= value &&
463 ret_cold == ThrottlingSeverity::NONE) {
464 ret_cold = static_cast<ThrottlingSeverity>(i);
465 }
466 if (!std::isnan(cold_thresholds[i]) && (cold_thresholds[i] + cold_hysteresis[i]) > value &&
467 ret_cold_hysteresis == ThrottlingSeverity::NONE) {
468 ret_cold_hysteresis = static_cast<ThrottlingSeverity>(i);
469 }
470 }
471 if (static_cast<size_t>(ret_hot) < static_cast<size_t>(prev_hot_severity)) {
472 ret_hot = ret_hot_hysteresis;
473 }
474 if (static_cast<size_t>(ret_cold) < static_cast<size_t>(prev_cold_severity)) {
475 ret_cold = ret_cold_hysteresis;
476 }
477
478 return std::make_pair(ret_hot, ret_cold);
479 }
480
initializeSensorMap(const std::unordered_map<std::string,std::string> & path_map)481 bool ThermalHelper::initializeSensorMap(
482 const std::unordered_map<std::string, std::string> &path_map) {
483 for (const auto &sensor_info_pair : sensor_info_map_) {
484 std::string_view sensor_name = sensor_info_pair.first;
485 if (sensor_info_pair.second.virtual_sensor_info != nullptr) {
486 continue;
487 }
488 if (!path_map.count(sensor_name.data())) {
489 LOG(ERROR) << "Could not find " << sensor_name << " in sysfs";
490 return false;
491 }
492
493 std::string path;
494 if (sensor_info_pair.second.temp_path.empty()) {
495 path = android::base::StringPrintf("%s/%s", path_map.at(sensor_name.data()).c_str(),
496 kSensorTempSuffix.data());
497 } else {
498 path = sensor_info_pair.second.temp_path;
499 }
500
501 if (!thermal_sensors_.addThermalFile(sensor_name, path)) {
502 LOG(ERROR) << "Could not add " << sensor_name << "to sensors map";
503 return false;
504 }
505 }
506 return true;
507 }
508
initializeCoolingDevices(const std::unordered_map<std::string,std::string> & path_map)509 bool ThermalHelper::initializeCoolingDevices(
510 const std::unordered_map<std::string, std::string> &path_map) {
511 for (auto &cooling_device_info_pair : cooling_device_info_map_) {
512 std::string cooling_device_name = cooling_device_info_pair.first;
513 if (!path_map.count(cooling_device_name)) {
514 LOG(ERROR) << "Could not find " << cooling_device_name << " in sysfs";
515 return false;
516 }
517 // Add cooling device path for thermalHAL to get current state
518 std::string_view path = path_map.at(cooling_device_name);
519 std::string read_path;
520 if (!cooling_device_info_pair.second.read_path.empty()) {
521 read_path = cooling_device_info_pair.second.read_path.data();
522 } else {
523 read_path = android::base::StringPrintf("%s/%s", path.data(),
524 kCoolingDeviceCurStateSuffix.data());
525 }
526 if (!cooling_devices_.addThermalFile(cooling_device_name, read_path)) {
527 LOG(ERROR) << "Could not add " << cooling_device_name
528 << " read path to cooling device map";
529 return false;
530 }
531
532 std::string state2power_path = android::base::StringPrintf(
533 "%s/%s", path.data(), kCoolingDeviceState2powerSuffix.data());
534 std::string state2power_str;
535 if (android::base::ReadFileToString(state2power_path, &state2power_str)) {
536 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first
537 << " use state2power read from sysfs";
538 cooling_device_info_pair.second.state2power.clear();
539
540 std::stringstream power(state2power_str);
541 unsigned int power_number;
542 int i = 0;
543 while (power >> power_number) {
544 cooling_device_info_pair.second.state2power.push_back(
545 static_cast<float>(power_number));
546 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first << " state:" << i
547 << " power: " << power_number;
548 i++;
549 }
550 }
551
552 // Get max cooling device request state
553 std::string max_state;
554 std::string max_state_path = android::base::StringPrintf(
555 "%s/%s", path.data(), kCoolingDeviceMaxStateSuffix.data());
556 if (!android::base::ReadFileToString(max_state_path, &max_state)) {
557 LOG(ERROR) << cooling_device_info_pair.first
558 << " could not open max state file:" << max_state_path;
559 cooling_device_info_pair.second.max_state = std::numeric_limits<int>::max();
560 } else {
561 cooling_device_info_pair.second.max_state = std::stoi(android::base::Trim(max_state));
562 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first
563 << " max state: " << cooling_device_info_pair.second.max_state
564 << " state2power number: "
565 << cooling_device_info_pair.second.state2power.size();
566 if (cooling_device_info_pair.second.state2power.size() > 0 &&
567 static_cast<int>(cooling_device_info_pair.second.state2power.size()) !=
568 (cooling_device_info_pair.second.max_state + 1)) {
569 LOG(ERROR) << "Invalid state2power number: "
570 << cooling_device_info_pair.second.state2power.size()
571 << ", number should be " << cooling_device_info_pair.second.max_state + 1
572 << " (max_state + 1)";
573 return false;
574 }
575 }
576
577 // Add cooling device path for thermalHAL to request state
578 cooling_device_name =
579 android::base::StringPrintf("%s_%s", cooling_device_name.c_str(), "w");
580 std::string write_path;
581 if (!cooling_device_info_pair.second.write_path.empty()) {
582 write_path = cooling_device_info_pair.second.write_path.data();
583 } else {
584 write_path = android::base::StringPrintf("%s/%s", path.data(),
585 kCoolingDeviceCurStateSuffix.data());
586 }
587
588 if (!cooling_devices_.addThermalFile(cooling_device_name, write_path)) {
589 LOG(ERROR) << "Could not add " << cooling_device_name
590 << " write path to cooling device map";
591 return false;
592 }
593 }
594 return true;
595 }
596
setMinTimeout(SensorInfo * sensor_info)597 void ThermalHelper::setMinTimeout(SensorInfo *sensor_info) {
598 sensor_info->polling_delay = kMinPollIntervalMs;
599 sensor_info->passive_delay = kMinPollIntervalMs;
600 }
601
initializeTrip(const std::unordered_map<std::string,std::string> & path_map,std::set<std::string> * monitored_sensors,bool thermal_genl_enabled)602 void ThermalHelper::initializeTrip(const std::unordered_map<std::string, std::string> &path_map,
603 std::set<std::string> *monitored_sensors,
604 bool thermal_genl_enabled) {
605 for (auto &sensor_info : sensor_info_map_) {
606 if (!sensor_info.second.is_watch || (sensor_info.second.virtual_sensor_info != nullptr)) {
607 continue;
608 }
609
610 bool trip_update = false;
611 std::string_view sensor_name = sensor_info.first;
612 std::string_view tz_path = path_map.at(sensor_name.data());
613 std::string tz_policy;
614 std::string path =
615 android::base::StringPrintf("%s/%s", (tz_path.data()), kSensorPolicyFile.data());
616
617 if (thermal_genl_enabled) {
618 trip_update = true;
619 } else {
620 // Check if thermal zone support uevent notify
621 if (!android::base::ReadFileToString(path, &tz_policy)) {
622 LOG(ERROR) << sensor_name << " could not open tz policy file:" << path;
623 } else {
624 tz_policy = android::base::Trim(tz_policy);
625 if (tz_policy != kUserSpaceSuffix) {
626 LOG(ERROR) << sensor_name << " does not support uevent notify";
627 } else {
628 trip_update = true;
629 }
630 }
631 }
632 if (trip_update) {
633 // Update thermal zone trip point
634 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
635 if (!std::isnan(sensor_info.second.hot_thresholds[i]) &&
636 !std::isnan(sensor_info.second.hot_hysteresis[i])) {
637 // Update trip_point_0_temp threshold
638 std::string threshold = std::to_string(static_cast<int>(
639 sensor_info.second.hot_thresholds[i] / sensor_info.second.multiplier));
640 path = android::base::StringPrintf("%s/%s", (tz_path.data()),
641 kSensorTripPointTempZeroFile.data());
642 if (!android::base::WriteStringToFile(threshold, path)) {
643 LOG(ERROR) << "fail to update " << sensor_name << " trip point: " << path
644 << " to " << threshold;
645 trip_update = false;
646 break;
647 }
648 // Update trip_point_0_hyst threshold
649 threshold = std::to_string(static_cast<int>(
650 sensor_info.second.hot_hysteresis[i] / sensor_info.second.multiplier));
651 path = android::base::StringPrintf("%s/%s", (tz_path.data()),
652 kSensorTripPointHystZeroFile.data());
653 if (!android::base::WriteStringToFile(threshold, path)) {
654 LOG(ERROR) << "fail to update " << sensor_name << "trip hyst" << threshold
655 << path;
656 trip_update = false;
657 break;
658 }
659 break;
660 } else if (i == kThrottlingSeverityCount - 1) {
661 LOG(ERROR) << sensor_name << ":all thresholds are NAN";
662 trip_update = false;
663 break;
664 }
665 }
666 monitored_sensors->insert(sensor_info.first);
667 }
668
669 if (!trip_update) {
670 LOG(INFO) << "config Sensor: " << sensor_info.first
671 << " to default polling interval: " << kMinPollIntervalMs.count();
672 setMinTimeout(&sensor_info.second);
673 }
674 }
675 }
676
fillTemperatures(hidl_vec<Temperature_1_0> * temperatures)677 bool ThermalHelper::fillTemperatures(hidl_vec<Temperature_1_0> *temperatures) {
678 std::vector<Temperature_1_0> ret;
679 for (const auto &name_info_pair : sensor_info_map_) {
680 Temperature_1_0 temp;
681
682 if (name_info_pair.second.is_hidden) {
683 continue;
684 }
685
686 if (readTemperature(name_info_pair.first, &temp)) {
687 ret.emplace_back(std::move(temp));
688 } else {
689 LOG(ERROR) << __func__
690 << ": error reading temperature for sensor: " << name_info_pair.first;
691 return false;
692 }
693 }
694 *temperatures = ret;
695 return ret.size() > 0;
696 }
697
fillCurrentTemperatures(bool filterType,bool filterCallback,TemperatureType_2_0 type,hidl_vec<Temperature_2_0> * temperatures)698 bool ThermalHelper::fillCurrentTemperatures(bool filterType, bool filterCallback,
699 TemperatureType_2_0 type,
700 hidl_vec<Temperature_2_0> *temperatures) {
701 std::vector<Temperature_2_0> ret;
702 for (const auto &name_info_pair : sensor_info_map_) {
703 Temperature_2_0 temp;
704 if (name_info_pair.second.is_hidden) {
705 continue;
706 }
707 if (filterType && name_info_pair.second.type != type) {
708 continue;
709 }
710 if (filterCallback && !name_info_pair.second.send_cb) {
711 continue;
712 }
713 if (readTemperature(name_info_pair.first, &temp, nullptr, false)) {
714 ret.emplace_back(std::move(temp));
715 } else {
716 LOG(ERROR) << __func__
717 << ": error reading temperature for sensor: " << name_info_pair.first;
718 }
719 }
720 *temperatures = ret;
721 return ret.size() > 0;
722 }
723
fillTemperatureThresholds(bool filterType,TemperatureType_2_0 type,hidl_vec<TemperatureThreshold> * thresholds) const724 bool ThermalHelper::fillTemperatureThresholds(bool filterType, TemperatureType_2_0 type,
725 hidl_vec<TemperatureThreshold> *thresholds) const {
726 std::vector<TemperatureThreshold> ret;
727 for (const auto &name_info_pair : sensor_info_map_) {
728 TemperatureThreshold temp;
729 if (name_info_pair.second.is_hidden) {
730 continue;
731 }
732 if (filterType && name_info_pair.second.type != type) {
733 continue;
734 }
735 if (readTemperatureThreshold(name_info_pair.first, &temp)) {
736 ret.emplace_back(std::move(temp));
737 } else {
738 LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
739 << name_info_pair.first;
740 return false;
741 }
742 }
743 *thresholds = ret;
744 return ret.size() > 0;
745 }
746
fillCurrentCoolingDevices(bool filterType,CoolingType type,hidl_vec<CoolingDevice_2_0> * cooling_devices) const747 bool ThermalHelper::fillCurrentCoolingDevices(bool filterType, CoolingType type,
748 hidl_vec<CoolingDevice_2_0> *cooling_devices) const {
749 std::vector<CoolingDevice_2_0> ret;
750 for (const auto &name_info_pair : cooling_device_info_map_) {
751 CoolingDevice_2_0 value;
752 if (filterType && name_info_pair.second.type != type) {
753 continue;
754 }
755 if (readCoolingDevice(name_info_pair.first, &value)) {
756 ret.emplace_back(std::move(value));
757 } else {
758 LOG(ERROR) << __func__ << ": error reading cooling device: " << name_info_pair.first;
759 return false;
760 }
761 }
762 *cooling_devices = ret;
763 return ret.size() > 0;
764 }
765
fillCpuUsages(hidl_vec<CpuUsage> * cpu_usages) const766 bool ThermalHelper::fillCpuUsages(hidl_vec<CpuUsage> *cpu_usages) const {
767 cpu_usages->resize(kMaxCpus);
768 for (int i = 0; i < kMaxCpus; i++) {
769 (*cpu_usages)[i].name = StringPrintf("cpu%d", i);
770 (*cpu_usages)[i].active = 0;
771 (*cpu_usages)[i].total = 0;
772 (*cpu_usages)[i].isOnline = false;
773 }
774 parseCpuUsagesFileAndAssignUsages(cpu_usages);
775 return true;
776 }
777
readThermalSensor(std::string_view sensor_name,float * temp,const bool force_sysfs)778 bool ThermalHelper::readThermalSensor(std::string_view sensor_name, float *temp,
779 const bool force_sysfs) {
780 float temp_val = 0.0;
781 std::string file_reading;
782 std::string log_buf;
783 boot_clock::time_point now = boot_clock::now();
784
785 ATRACE_NAME(StringPrintf("ThermalHelper::readThermalSensor - %s", sensor_name.data()).c_str());
786 if (!(sensor_info_map_.count(sensor_name.data()) &&
787 sensor_status_map_.count(sensor_name.data()))) {
788 return false;
789 }
790
791 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
792 auto &sensor_status = sensor_status_map_.at(sensor_name.data());
793
794 // Check if thermal data need to be read from buffer
795 if (!force_sysfs && (sensor_status.thermal_cached.timestamp != boot_clock::time_point::min()) &&
796 (std::chrono::duration_cast<std::chrono::milliseconds>(
797 now - sensor_status.thermal_cached.timestamp) < sensor_info.time_resolution) &&
798 !isnan(sensor_status.thermal_cached.temp)) {
799 *temp = sensor_status.thermal_cached.temp;
800 LOG(VERBOSE) << "read " << sensor_name.data() << " from buffer, value:" << *temp;
801 return true;
802 }
803
804 // Reading thermal sensor according to it's composition
805 if (sensor_info.virtual_sensor_info == nullptr) {
806 if (!thermal_sensors_.readThermalFile(sensor_name.data(), &file_reading)) {
807 return false;
808 }
809
810 if (file_reading.empty()) {
811 LOG(ERROR) << "failed to read sensor: " << sensor_name;
812 return false;
813 }
814 *temp = std::stof(::android::base::Trim(file_reading));
815 } else {
816 for (size_t i = 0; i < sensor_info.virtual_sensor_info->linked_sensors.size(); i++) {
817 float sensor_reading = 0.0;
818 if (!readThermalSensor(sensor_info.virtual_sensor_info->linked_sensors[i],
819 &sensor_reading, force_sysfs)) {
820 return false;
821 }
822 log_buf.append(StringPrintf("(%s: %0.2f)",
823 sensor_info.virtual_sensor_info->linked_sensors[i].c_str(),
824 sensor_reading));
825 if (std::isnan(sensor_info.virtual_sensor_info->coefficients[i])) {
826 return false;
827 }
828
829 float coefficient = sensor_info.virtual_sensor_info->coefficients[i];
830 switch (sensor_info.virtual_sensor_info->formula) {
831 case FormulaOption::COUNT_THRESHOLD:
832 if ((coefficient < 0 && sensor_reading < -coefficient) ||
833 (coefficient >= 0 && sensor_reading >= coefficient))
834 temp_val += 1;
835 break;
836 case FormulaOption::WEIGHTED_AVG:
837 temp_val += sensor_reading * coefficient;
838 break;
839 case FormulaOption::MAXIMUM:
840 if (i == 0)
841 temp_val = std::numeric_limits<float>::lowest();
842 if (sensor_reading * coefficient > temp_val)
843 temp_val = sensor_reading * coefficient;
844 break;
845 case FormulaOption::MINIMUM:
846 if (i == 0)
847 temp_val = std::numeric_limits<float>::max();
848 if (sensor_reading * coefficient < temp_val)
849 temp_val = sensor_reading * coefficient;
850 break;
851 default:
852 break;
853 }
854 }
855 LOG(VERBOSE) << sensor_name.data() << "'s sub sensors:" << log_buf;
856 *temp = (temp_val + sensor_info.virtual_sensor_info->offset);
857 }
858
859 {
860 std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
861 sensor_status.thermal_cached.temp = *temp;
862 sensor_status.thermal_cached.timestamp = now;
863 }
864
865 return true;
866 }
867
868 // This is called in the different thread context and will update sensor_status
869 // uevent_sensors is the set of sensors which trigger uevent from thermal core driver.
thermalWatcherCallbackFunc(const std::set<std::string> & uevent_sensors)870 std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc(
871 const std::set<std::string> &uevent_sensors) {
872 std::vector<Temperature_2_0> temps;
873 std::vector<std::string> cooling_devices_to_update;
874 boot_clock::time_point now = boot_clock::now();
875 auto min_sleep_ms = std::chrono::milliseconds::max();
876 bool power_data_is_updated = false;
877
878 ATRACE_CALL();
879 for (auto &name_status_pair : sensor_status_map_) {
880 bool force_update = false;
881 bool force_sysfs = false;
882 Temperature_2_0 temp;
883 TemperatureThreshold threshold;
884 SensorStatus &sensor_status = name_status_pair.second;
885 const SensorInfo &sensor_info = sensor_info_map_.at(name_status_pair.first);
886
887 // Only handle the sensors in allow list
888 if (!sensor_info.is_watch) {
889 continue;
890 }
891
892 ATRACE_NAME(StringPrintf("ThermalHelper::thermalWatcherCallbackFunc - %s",
893 name_status_pair.first.data())
894 .c_str());
895
896 std::chrono::milliseconds time_elapsed_ms = std::chrono::milliseconds::zero();
897 auto sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
898 ? sensor_info.passive_delay
899 : sensor_info.polling_delay;
900
901 if (sensor_info.virtual_sensor_info != nullptr &&
902 !sensor_info.virtual_sensor_info->trigger_sensor.empty()) {
903 const auto trigger_sensor_status =
904 sensor_status_map_.at(sensor_info.virtual_sensor_info->trigger_sensor);
905 if (trigger_sensor_status.severity != ThrottlingSeverity::NONE) {
906 sleep_ms = sensor_info.passive_delay;
907 }
908 }
909 // Check if the sensor need to be updated
910 if (sensor_status.last_update_time == boot_clock::time_point::min()) {
911 force_update = true;
912 LOG(VERBOSE) << "Force update " << name_status_pair.first
913 << "'s temperature after booting";
914 } else {
915 time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
916 now - sensor_status.last_update_time);
917 if (time_elapsed_ms > sleep_ms) {
918 // Update the sensor because sleep timeout
919 force_update = true;
920 } else if (uevent_sensors.size() &&
921 uevent_sensors.find((sensor_info.virtual_sensor_info != nullptr)
922 ? sensor_info.virtual_sensor_info->trigger_sensor
923 : name_status_pair.first) !=
924 uevent_sensors.end()) {
925 // Force update the sensor from sysfs
926 force_update = true;
927 force_sysfs = true;
928 }
929 }
930
931 LOG(VERBOSE) << "sensor " << name_status_pair.first
932 << ": time_elapsed=" << time_elapsed_ms.count()
933 << ", sleep_ms=" << sleep_ms.count() << ", force_update = " << force_update
934 << ", force_sysfs = " << force_sysfs;
935
936 if (!force_update) {
937 auto timeout_remaining = sleep_ms - time_elapsed_ms;
938 if (min_sleep_ms > timeout_remaining) {
939 min_sleep_ms = timeout_remaining;
940 }
941 LOG(VERBOSE) << "sensor " << name_status_pair.first
942 << ": timeout_remaining=" << timeout_remaining.count();
943 continue;
944 }
945
946 std::pair<ThrottlingSeverity, ThrottlingSeverity> throtting_status;
947 if (!readTemperature(name_status_pair.first, &temp, &throtting_status, force_sysfs)) {
948 LOG(ERROR) << __func__
949 << ": error reading temperature for sensor: " << name_status_pair.first;
950 continue;
951 }
952 if (!readTemperatureThreshold(name_status_pair.first, &threshold)) {
953 LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
954 << name_status_pair.first;
955 continue;
956 }
957
958 {
959 // writer lock
960 std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
961 if (throtting_status.first != sensor_status.prev_hot_severity) {
962 sensor_status.prev_hot_severity = throtting_status.first;
963 }
964 if (throtting_status.second != sensor_status.prev_cold_severity) {
965 sensor_status.prev_cold_severity = throtting_status.second;
966 }
967 if (temp.throttlingStatus != sensor_status.severity) {
968 temps.push_back(temp);
969 sensor_status.severity = temp.throttlingStatus;
970 sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
971 ? sensor_info.passive_delay
972 : sensor_info.polling_delay;
973 }
974 }
975
976 if (!power_data_is_updated) {
977 power_files_.refreshPowerStatus();
978 power_data_is_updated = true;
979 }
980
981 if (sensor_status.severity == ThrottlingSeverity::NONE) {
982 LOG(VERBOSE) << temp.name << ": " << temp.value;
983 thermal_throttling_.clearThrottlingData(name_status_pair.first, sensor_info);
984 } else {
985 LOG(INFO) << temp.name << ": " << temp.value;
986 // update thermal throttling request
987 thermal_throttling_.thermalThrottlingUpdate(
988 temp, sensor_info, sensor_status.severity, time_elapsed_ms,
989 power_files_.GetPowerStatusMap(), cooling_device_info_map_);
990 }
991
992 thermal_throttling_.computeCoolingDevicesRequest(name_status_pair.first, sensor_info,
993 sensor_status.severity,
994 &cooling_devices_to_update);
995 if (min_sleep_ms > sleep_ms) {
996 min_sleep_ms = sleep_ms;
997 }
998
999 LOG(VERBOSE) << "Sensor " << name_status_pair.first << ": sleep_ms=" << sleep_ms.count()
1000 << ", min_sleep_ms voting result=" << min_sleep_ms.count();
1001 sensor_status.last_update_time = now;
1002 }
1003
1004 if (!cooling_devices_to_update.empty()) {
1005 updateCoolingDevices(cooling_devices_to_update);
1006 }
1007
1008 if (!temps.empty()) {
1009 for (const auto &t : temps) {
1010 if (sensor_info_map_.at(t.name).send_cb && cb_) {
1011 cb_(t);
1012 }
1013
1014 if (sensor_info_map_.at(t.name).send_powerhint && isAidlPowerHalExist()) {
1015 sendPowerExtHint(t);
1016 }
1017 }
1018 }
1019
1020 return min_sleep_ms;
1021 }
1022
connectToPowerHal()1023 bool ThermalHelper::connectToPowerHal() {
1024 return power_hal_service_.connect();
1025 }
1026
updateSupportedPowerHints()1027 void ThermalHelper::updateSupportedPowerHints() {
1028 for (auto const &name_status_pair : sensor_info_map_) {
1029 if (!(name_status_pair.second.send_powerhint)) {
1030 continue;
1031 }
1032 ThrottlingSeverity current_severity = ThrottlingSeverity::NONE;
1033 for (const auto &severity : hidl_enum_range<ThrottlingSeverity>()) {
1034 if (severity == ThrottlingSeverity::NONE) {
1035 supported_powerhint_map_[name_status_pair.first][ThrottlingSeverity::NONE] =
1036 ThrottlingSeverity::NONE;
1037 continue;
1038 }
1039
1040 bool isSupported = false;
1041 ndk::ScopedAStatus isSupportedResult;
1042
1043 if (power_hal_service_.isPowerHalExtConnected()) {
1044 isSupported = power_hal_service_.isModeSupported(name_status_pair.first, severity);
1045 }
1046 if (isSupported)
1047 current_severity = severity;
1048 supported_powerhint_map_[name_status_pair.first][severity] = current_severity;
1049 }
1050 }
1051 }
1052
sendPowerExtHint(const Temperature_2_0 & t)1053 void ThermalHelper::sendPowerExtHint(const Temperature_2_0 &t) {
1054 ATRACE_CALL();
1055 std::lock_guard<std::shared_mutex> lock(sensor_status_map_mutex_);
1056 ThrottlingSeverity prev_hint_severity;
1057 prev_hint_severity = sensor_status_map_.at(t.name).prev_hint_severity;
1058 ThrottlingSeverity current_hint_severity = supported_powerhint_map_[t.name][t.throttlingStatus];
1059
1060 if (prev_hint_severity == current_hint_severity)
1061 return;
1062
1063 if (prev_hint_severity != ThrottlingSeverity::NONE) {
1064 power_hal_service_.setMode(t.name, prev_hint_severity, false);
1065 }
1066
1067 if (current_hint_severity != ThrottlingSeverity::NONE) {
1068 power_hal_service_.setMode(t.name, current_hint_severity, true);
1069 }
1070
1071 sensor_status_map_[t.name].prev_hint_severity = current_hint_severity;
1072 }
1073 } // namespace implementation
1074 } // namespace V2_0
1075 } // namespace thermal
1076 } // namespace hardware
1077 } // namespace android
1078