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 kConfigProperty("vendor.thermal.config");
54 constexpr std::string_view kConfigDefaultFileName("thermal_info_config.json");
55
56 namespace {
57 using android::base::StringPrintf;
58 using android::hardware::thermal::V2_0::toString;
59
60 /*
61 * Pixel don't offline CPU, so std::thread::hardware_concurrency(); should work.
62 * However /sys/devices/system/cpu/present is preferred.
63 * The file is expected to contain single text line with two numbers %d-%d,
64 * which is a range of available cpu numbers, e.g. 0-7 would mean there
65 * are 8 cores number from 0 to 7.
66 * For Android systems this approach is safer than using cpufeatures, see bug
67 * b/36941727.
68 */
getNumberOfCores()69 std::size_t getNumberOfCores() {
70 std::string file;
71 if (!android::base::ReadFileToString(kCpuPresentFile.data(), &file)) {
72 LOG(ERROR) << "Error reading Cpu present file: " << kCpuPresentFile;
73 return 0;
74 }
75 std::vector<std::string> pieces = android::base::Split(file, "-");
76 if (pieces.size() != 2) {
77 LOG(ERROR) << "Error parsing Cpu present file content: " << file;
78 return 0;
79 }
80 auto min_core = std::stoul(pieces[0]);
81 auto max_core = std::stoul(pieces[1]);
82 if (max_core < min_core) {
83 LOG(ERROR) << "Error parsing Cpu present min and max: " << min_core << " - " << max_core;
84 return 0;
85 }
86 return static_cast<std::size_t>(max_core - min_core + 1);
87 }
88 const std::size_t kMaxCpus = getNumberOfCores();
89
parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> * cpu_usages)90 void parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> *cpu_usages) {
91 uint64_t cpu_num, user, nice, system, idle;
92 std::string cpu_name;
93 std::string data;
94 if (!android::base::ReadFileToString(kCpuUsageFile.data(), &data)) {
95 LOG(ERROR) << "Error reading Cpu usage file: " << kCpuUsageFile;
96 return;
97 }
98
99 std::istringstream stat_data(data);
100 std::string line;
101 while (std::getline(stat_data, line)) {
102 if (line.find("cpu") == 0 && isdigit(line[3])) {
103 // Split the string using spaces.
104 std::vector<std::string> words = android::base::Split(line, " ");
105 cpu_name = words[0];
106 cpu_num = std::stoi(cpu_name.substr(3));
107
108 if (cpu_num < kMaxCpus) {
109 user = std::stoi(words[1]);
110 nice = std::stoi(words[2]);
111 system = std::stoi(words[3]);
112 idle = std::stoi(words[4]);
113
114 // Check if the CPU is online by reading the online file.
115 std::string cpu_online_path =
116 StringPrintf("%s/%s/%s", kCpuOnlineRoot.data(), cpu_name.c_str(),
117 kCpuOnlineFileSuffix.data());
118 std::string is_online;
119 if (!android::base::ReadFileToString(cpu_online_path, &is_online)) {
120 LOG(ERROR) << "Could not open Cpu online file: " << cpu_online_path;
121 return;
122 }
123 is_online = android::base::Trim(is_online);
124
125 (*cpu_usages)[cpu_num].name = cpu_name;
126 (*cpu_usages)[cpu_num].active = user + nice + system;
127 (*cpu_usages)[cpu_num].total = user + nice + system + idle;
128 (*cpu_usages)[cpu_num].isOnline = (is_online == "1") ? true : false;
129 } else {
130 LOG(ERROR) << "Unexpected cpu number: " << words[0];
131 return;
132 }
133 }
134 }
135 }
136
parseThermalPathMap(std::string_view prefix)137 std::map<std::string, std::string> parseThermalPathMap(std::string_view prefix) {
138 std::map<std::string, std::string> path_map;
139 std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(kThermalSensorsRoot.data()), closedir);
140 if (!dir) {
141 return path_map;
142 }
143
144 // std::filesystem is not available for vendor yet
145 // see discussion: aosp/894015
146 while (struct dirent *dp = readdir(dir.get())) {
147 if (dp->d_type != DT_DIR) {
148 continue;
149 }
150
151 if (!android::base::StartsWith(dp->d_name, prefix.data())) {
152 continue;
153 }
154
155 std::string path = android::base::StringPrintf("%s/%s/%s", kThermalSensorsRoot.data(),
156 dp->d_name, kThermalNameFile.data());
157 std::string name;
158 if (!android::base::ReadFileToString(path, &name)) {
159 PLOG(ERROR) << "Failed to read from " << path;
160 continue;
161 }
162
163 path_map.emplace(
164 android::base::Trim(name),
165 android::base::StringPrintf("%s/%s", kThermalSensorsRoot.data(), dp->d_name));
166 }
167
168 return path_map;
169 }
170
171 } // namespace
PowerHalService()172 PowerHalService::PowerHalService()
173 : power_hal_aidl_exist_(true), power_hal_aidl_(nullptr), power_hal_ext_aidl_(nullptr) {
174 connect();
175 }
176
connect()177 bool PowerHalService::connect() {
178 std::lock_guard<std::mutex> lock(lock_);
179 if (!power_hal_aidl_exist_)
180 return false;
181
182 if (power_hal_aidl_ != nullptr)
183 return true;
184
185 const std::string kInstance = std::string(IPower::descriptor) + "/default";
186 ndk::SpAIBinder power_binder = ndk::SpAIBinder(AServiceManager_getService(kInstance.c_str()));
187 ndk::SpAIBinder ext_power_binder;
188
189 if (power_binder.get() == nullptr) {
190 LOG(ERROR) << "Cannot get Power Hal Binder";
191 power_hal_aidl_exist_ = false;
192 return false;
193 }
194
195 power_hal_aidl_ = IPower::fromBinder(power_binder);
196
197 if (power_hal_aidl_ == nullptr) {
198 power_hal_aidl_exist_ = false;
199 LOG(ERROR) << "Cannot get Power Hal AIDL" << kInstance.c_str();
200 return false;
201 }
202
203 if (STATUS_OK != AIBinder_getExtension(power_binder.get(), ext_power_binder.getR()) ||
204 ext_power_binder.get() == nullptr) {
205 LOG(ERROR) << "Cannot get Power Hal Extension Binder";
206 power_hal_aidl_exist_ = false;
207 return false;
208 }
209
210 power_hal_ext_aidl_ = IPowerExt::fromBinder(ext_power_binder);
211 if (power_hal_ext_aidl_ == nullptr) {
212 LOG(ERROR) << "Cannot get Power Hal Extension AIDL";
213 power_hal_aidl_exist_ = false;
214 }
215
216 return true;
217 }
218
isModeSupported(const std::string & type,const ThrottlingSeverity & t)219 bool PowerHalService::isModeSupported(const std::string &type, const ThrottlingSeverity &t) {
220 bool isSupported = false;
221 if (!isPowerHalConnected()) {
222 return false;
223 }
224 std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str());
225 lock_.lock();
226 if (!power_hal_ext_aidl_->isModeSupported(power_hint, &isSupported).isOk()) {
227 LOG(ERROR) << "Fail to check supported mode, Hint: " << power_hint;
228 power_hal_aidl_exist_ = false;
229 power_hal_ext_aidl_ = nullptr;
230 power_hal_aidl_ = nullptr;
231 lock_.unlock();
232 return false;
233 }
234 lock_.unlock();
235 return isSupported;
236 }
237
setMode(const std::string & type,const ThrottlingSeverity & t,const bool & enable)238 void PowerHalService::setMode(const std::string &type, const ThrottlingSeverity &t,
239 const bool &enable) {
240 if (!isPowerHalConnected()) {
241 return;
242 }
243
244 std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str());
245 LOG(INFO) << "Send Hint " << power_hint << " Enable: " << std::boolalpha << enable;
246 lock_.lock();
247 if (!power_hal_ext_aidl_->setMode(power_hint, enable).isOk()) {
248 LOG(ERROR) << "Fail to set mode, Hint: " << power_hint;
249 power_hal_aidl_exist_ = false;
250 power_hal_ext_aidl_ = nullptr;
251 power_hal_aidl_ = nullptr;
252 lock_.unlock();
253 return;
254 }
255 lock_.unlock();
256 }
257
258 /*
259 * Populate the sensor_name_to_file_map_ map by walking through the file tree,
260 * reading the type file and assigning the temp file path to the map. If we do
261 * not succeed, abort.
262 */
ThermalHelper(const NotificationCallback & cb)263 ThermalHelper::ThermalHelper(const NotificationCallback &cb)
264 : thermal_watcher_(new ThermalWatcher(
265 std::bind(&ThermalHelper::thermalWatcherCallbackFunc, this, std::placeholders::_1))),
266 cb_(cb),
267 cooling_device_info_map_(ParseCoolingDevice(
268 "/vendor/etc/" +
269 android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data()))),
270 sensor_info_map_(ParseSensorInfo(
271 "/vendor/etc/" +
272 android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data()))) {
273 for (auto const &name_status_pair : sensor_info_map_) {
274 sensor_status_map_[name_status_pair.first] = {
275 .severity = ThrottlingSeverity::NONE,
276 .prev_hot_severity = ThrottlingSeverity::NONE,
277 .prev_cold_severity = ThrottlingSeverity::NONE,
278 .prev_hint_severity = ThrottlingSeverity::NONE,
279 };
280 }
281
282 auto tz_map = parseThermalPathMap(kSensorPrefix.data());
283 auto cdev_map = parseThermalPathMap(kCoolingDevicePrefix.data());
284
285 is_initialized_ = initializeSensorMap(tz_map) && initializeCoolingDevices(cdev_map);
286 if (!is_initialized_) {
287 LOG(FATAL) << "ThermalHAL could not be initialized properly.";
288 }
289 std::set<std::string> monitored_sensors;
290 std::transform(sensor_info_map_.cbegin(), sensor_info_map_.cend(),
291 std::inserter(monitored_sensors, monitored_sensors.begin()),
292 [](std::pair<std::string, SensorInfo> const &sensor) {
293 if (sensor.second.is_monitor)
294 return sensor.first;
295 else
296 return std::string();
297 });
298
299 thermal_watcher_->registerFilesToWatch(monitored_sensors, initializeTrip(tz_map));
300
301 // Need start watching after status map initialized
302 is_initialized_ = thermal_watcher_->startWatchingDeviceFiles();
303 if (!is_initialized_) {
304 LOG(FATAL) << "ThermalHAL could not start watching thread properly.";
305 }
306
307 if (!connectToPowerHal()) {
308 LOG(ERROR) << "Fail to connect to Power Hal";
309 } else {
310 updateSupportedPowerHints();
311 }
312 }
313
readCoolingDevice(std::string_view cooling_device,CoolingDevice_2_0 * out) const314 bool ThermalHelper::readCoolingDevice(std::string_view cooling_device,
315 CoolingDevice_2_0 *out) const {
316 // Read the file. If the file can't be read temp will be empty string.
317 std::string data;
318
319 if (!cooling_devices_.readThermalFile(cooling_device, &data)) {
320 LOG(ERROR) << "readCoolingDevice: failed to read cooling_device: " << cooling_device;
321 return false;
322 }
323
324 const CoolingType &type = cooling_device_info_map_.at(cooling_device.data());
325
326 out->type = type;
327 out->name = cooling_device.data();
328 out->value = std::stoi(data);
329
330 return true;
331 }
332
readTemperature(std::string_view sensor_name,Temperature_1_0 * out) const333 bool ThermalHelper::readTemperature(std::string_view sensor_name, Temperature_1_0 *out) const {
334 // Read the file. If the file can't be read temp will be empty string.
335 std::string temp;
336
337 if (!thermal_sensors_.readThermalFile(sensor_name, &temp)) {
338 LOG(ERROR) << "readTemperature: sensor not found: " << sensor_name;
339 return false;
340 }
341
342 if (temp.empty()) {
343 LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
344 return false;
345 }
346
347 const SensorInfo &sensor_info = sensor_info_map_.at(sensor_name.data());
348 TemperatureType_1_0 type =
349 (static_cast<int>(sensor_info.type) > static_cast<int>(TemperatureType_1_0::SKIN))
350 ? TemperatureType_1_0::UNKNOWN
351 : static_cast<TemperatureType_1_0>(sensor_info.type);
352 out->type = type;
353 out->name = sensor_name.data();
354 out->currentValue = std::stof(temp) * sensor_info.multiplier;
355 out->throttlingThreshold =
356 sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)];
357 out->shutdownThreshold =
358 sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SHUTDOWN)];
359 out->vrThrottlingThreshold = sensor_info.vr_threshold;
360
361 return true;
362 }
363
readTemperature(std::string_view sensor_name,Temperature_2_0 * out,std::pair<ThrottlingSeverity,ThrottlingSeverity> * throtting_status) const364 bool ThermalHelper::readTemperature(
365 std::string_view sensor_name, Temperature_2_0 *out,
366 std::pair<ThrottlingSeverity, ThrottlingSeverity> *throtting_status) const {
367 // Read the file. If the file can't be read temp will be empty string.
368 std::string temp;
369
370 if (!thermal_sensors_.readThermalFile(sensor_name, &temp)) {
371 LOG(ERROR) << "readTemperature: sensor not found: " << sensor_name;
372 return false;
373 }
374
375 if (temp.empty()) {
376 LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
377 return false;
378 }
379
380 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
381 out->type = sensor_info.type;
382 out->name = sensor_name.data();
383 out->value = std::stof(temp) * sensor_info.multiplier;
384
385 std::pair<ThrottlingSeverity, ThrottlingSeverity> status =
386 std::make_pair(ThrottlingSeverity::NONE, ThrottlingSeverity::NONE);
387 // Only update status if the thermal sensor is being monitored
388 if (sensor_info.is_monitor) {
389 ThrottlingSeverity prev_hot_severity, prev_cold_severity;
390 {
391 // reader lock, readTemperature will be called in Binder call and the watcher thread.
392 std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
393 prev_hot_severity = sensor_status_map_.at(sensor_name.data()).prev_hot_severity;
394 prev_cold_severity = sensor_status_map_.at(sensor_name.data()).prev_cold_severity;
395 }
396 status = getSeverityFromThresholds(sensor_info.hot_thresholds, sensor_info.cold_thresholds,
397 sensor_info.hot_hysteresis, sensor_info.cold_hysteresis,
398 prev_hot_severity, prev_cold_severity, out->value);
399 }
400 if (throtting_status) {
401 *throtting_status = status;
402 }
403
404 out->throttlingStatus = static_cast<size_t>(status.first) > static_cast<size_t>(status.second)
405 ? status.first
406 : status.second;
407
408 return true;
409 }
410
readTemperatureThreshold(std::string_view sensor_name,TemperatureThreshold * out) const411 bool ThermalHelper::readTemperatureThreshold(std::string_view sensor_name,
412 TemperatureThreshold *out) const {
413 // Read the file. If the file can't be read temp will be empty string.
414 std::string temp;
415 std::string path;
416
417 if (!sensor_info_map_.count(sensor_name.data())) {
418 LOG(ERROR) << __func__ << ": sensor not found: " << sensor_name;
419 return false;
420 }
421
422 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
423
424 out->type = sensor_info.type;
425 out->name = sensor_name.data();
426 out->hotThrottlingThresholds = sensor_info.hot_thresholds;
427 out->coldThrottlingThresholds = sensor_info.cold_thresholds;
428 out->vrThrottlingThreshold = sensor_info.vr_threshold;
429 return true;
430 }
431
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) const432 std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelper::getSeverityFromThresholds(
433 const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
434 const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
435 ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
436 float value) const {
437 ThrottlingSeverity ret_hot = ThrottlingSeverity::NONE;
438 ThrottlingSeverity ret_hot_hysteresis = ThrottlingSeverity::NONE;
439 ThrottlingSeverity ret_cold = ThrottlingSeverity::NONE;
440 ThrottlingSeverity ret_cold_hysteresis = ThrottlingSeverity::NONE;
441
442 // Here we want to control the iteration from high to low, and hidl_enum_range doesn't support
443 // a reverse iterator yet.
444 for (size_t i = static_cast<size_t>(ThrottlingSeverity::SHUTDOWN);
445 i > static_cast<size_t>(ThrottlingSeverity::NONE); --i) {
446 if (!std::isnan(hot_thresholds[i]) && hot_thresholds[i] <= value &&
447 ret_hot == ThrottlingSeverity::NONE) {
448 ret_hot = static_cast<ThrottlingSeverity>(i);
449 }
450 if (!std::isnan(hot_thresholds[i]) && (hot_thresholds[i] - hot_hysteresis[i]) < value &&
451 ret_hot_hysteresis == ThrottlingSeverity::NONE) {
452 ret_hot_hysteresis = static_cast<ThrottlingSeverity>(i);
453 }
454 if (!std::isnan(cold_thresholds[i]) && cold_thresholds[i] >= value &&
455 ret_cold == ThrottlingSeverity::NONE) {
456 ret_cold = static_cast<ThrottlingSeverity>(i);
457 }
458 if (!std::isnan(cold_thresholds[i]) && (cold_thresholds[i] + cold_hysteresis[i]) > value &&
459 ret_cold_hysteresis == ThrottlingSeverity::NONE) {
460 ret_cold_hysteresis = static_cast<ThrottlingSeverity>(i);
461 }
462 }
463 if (static_cast<size_t>(ret_hot) < static_cast<size_t>(prev_hot_severity)) {
464 ret_hot = ret_hot_hysteresis;
465 }
466 if (static_cast<size_t>(ret_cold) < static_cast<size_t>(prev_cold_severity)) {
467 ret_cold = ret_cold_hysteresis;
468 }
469
470 return std::make_pair(ret_hot, ret_cold);
471 }
472
initializeSensorMap(const std::map<std::string,std::string> & path_map)473 bool ThermalHelper::initializeSensorMap(const std::map<std::string, std::string> &path_map) {
474 for (const auto &sensor_info_pair : sensor_info_map_) {
475 std::string_view sensor_name = sensor_info_pair.first;
476 if (!path_map.count(sensor_name.data())) {
477 LOG(ERROR) << "Could not find " << sensor_name << " in sysfs";
478 continue;
479 }
480 std::string path = android::base::StringPrintf(
481 "%s/%s", path_map.at(sensor_name.data()).c_str(), kSensorTempSuffix.data());
482 if (!thermal_sensors_.addThermalFile(sensor_name, path)) {
483 LOG(ERROR) << "Could not add " << sensor_name << "to sensors map";
484 }
485 }
486 if (sensor_info_map_.size() == thermal_sensors_.getNumThermalFiles()) {
487 return true;
488 }
489 return false;
490 }
491
initializeCoolingDevices(const std::map<std::string,std::string> & path_map)492 bool ThermalHelper::initializeCoolingDevices(const std::map<std::string, std::string> &path_map) {
493 for (const auto &cooling_device_info_pair : cooling_device_info_map_) {
494 std::string_view cooling_device_name = cooling_device_info_pair.first;
495 if (!path_map.count(cooling_device_name.data())) {
496 LOG(ERROR) << "Could not find " << cooling_device_name << " in sysfs";
497 continue;
498 }
499 std::string path = android::base::StringPrintf(
500 "%s/%s", path_map.at(cooling_device_name.data()).c_str(),
501 kCoolingDeviceCurStateSuffix.data());
502 if (!cooling_devices_.addThermalFile(cooling_device_name, path)) {
503 LOG(ERROR) << "Could not add " << cooling_device_name << "to cooling device map";
504 continue;
505 }
506 }
507
508 if (cooling_device_info_map_.size() == cooling_devices_.getNumThermalFiles()) {
509 return true;
510 }
511 return false;
512 }
513
initializeTrip(const std::map<std::string,std::string> & path_map)514 bool ThermalHelper::initializeTrip(const std::map<std::string, std::string> &path_map) {
515 for (const auto &sensor_info : sensor_info_map_) {
516 if (sensor_info.second.is_monitor) {
517 std::string_view sensor_name = sensor_info.first;
518 std::string_view tz_path = path_map.at(sensor_name.data());
519 std::string tz_policy;
520 std::string path = android::base::StringPrintf("%s/%s", (tz_path.data()),
521 kSensorPolicyFile.data());
522 if (!android::base::ReadFileToString(path, &tz_policy)) {
523 LOG(ERROR) << sensor_name << " could not open tz policy file:" << path;
524 return false;
525 }
526 // Check if thermal zone support uevent notify
527 tz_policy = android::base::Trim(tz_policy);
528 if (tz_policy != kUserSpaceSuffix) {
529 LOG(ERROR) << sensor_name << " does not support uevent notify";
530 return false;
531 }
532
533 // Update thermal zone trip point
534 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
535 if (!std::isnan(sensor_info.second.hot_thresholds[i]) &&
536 !std::isnan(sensor_info.second.hot_hysteresis[i])) {
537 // Update trip_point_0_temp threshold
538 std::string threshold = std::to_string(static_cast<int>(
539 sensor_info.second.hot_thresholds[i] / sensor_info.second.multiplier));
540 path = android::base::StringPrintf("%s/%s", (tz_path.data()),
541 kSensorTripPointTempZeroFile.data());
542 if (!android::base::WriteStringToFile(threshold, path)) {
543 LOG(ERROR) << "fail to update " << sensor_name
544 << " trip point: " << threshold << path;
545 return false;
546 }
547 // Update trip_point_0_hyst threshold
548 threshold = std::to_string(static_cast<int>(
549 sensor_info.second.hot_hysteresis[i] / sensor_info.second.multiplier));
550 path = android::base::StringPrintf("%s/%s", (tz_path.data()),
551 kSensorTripPointHystZeroFile.data());
552 if (!android::base::WriteStringToFile(threshold, path)) {
553 LOG(ERROR) << "fail to update " << sensor_name << "trip hyst" << threshold
554 << path;
555 return false;
556 }
557 break;
558 } else if (i == kThrottlingSeverityCount - 1) {
559 LOG(ERROR) << sensor_name << ":all thresholds are NAN";
560 return false;
561 }
562 }
563 }
564 }
565 return true;
566 }
fillTemperatures(hidl_vec<Temperature_1_0> * temperatures) const567 bool ThermalHelper::fillTemperatures(hidl_vec<Temperature_1_0> *temperatures) const {
568 temperatures->resize(sensor_info_map_.size());
569 int current_index = 0;
570 for (const auto &name_info_pair : sensor_info_map_) {
571 Temperature_1_0 temp;
572
573 if (readTemperature(name_info_pair.first, &temp)) {
574 (*temperatures)[current_index] = temp;
575 } else {
576 LOG(ERROR) << __func__
577 << ": error reading temperature for sensor: " << name_info_pair.first;
578 return false;
579 }
580 ++current_index;
581 }
582 return current_index > 0;
583 }
584
fillCurrentTemperatures(bool filterType,TemperatureType_2_0 type,hidl_vec<Temperature_2_0> * temperatures) const585 bool ThermalHelper::fillCurrentTemperatures(bool filterType, TemperatureType_2_0 type,
586 hidl_vec<Temperature_2_0> *temperatures) const {
587 std::vector<Temperature_2_0> ret;
588 for (const auto &name_info_pair : sensor_info_map_) {
589 Temperature_2_0 temp;
590 if (filterType && name_info_pair.second.type != type) {
591 continue;
592 }
593 if (readTemperature(name_info_pair.first, &temp)) {
594 ret.emplace_back(std::move(temp));
595 } else {
596 LOG(ERROR) << __func__
597 << ": error reading temperature for sensor: " << name_info_pair.first;
598 return false;
599 }
600 }
601 *temperatures = ret;
602 return ret.size() > 0;
603 }
604
fillTemperatureThresholds(bool filterType,TemperatureType_2_0 type,hidl_vec<TemperatureThreshold> * thresholds) const605 bool ThermalHelper::fillTemperatureThresholds(bool filterType, TemperatureType_2_0 type,
606 hidl_vec<TemperatureThreshold> *thresholds) const {
607 std::vector<TemperatureThreshold> ret;
608 for (const auto &name_info_pair : sensor_info_map_) {
609 TemperatureThreshold temp;
610 if (filterType && name_info_pair.second.type != type) {
611 continue;
612 }
613 if (readTemperatureThreshold(name_info_pair.first, &temp)) {
614 ret.emplace_back(std::move(temp));
615 } else {
616 LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
617 << name_info_pair.first;
618 return false;
619 }
620 }
621 *thresholds = ret;
622 return ret.size() > 0;
623 }
624
fillCurrentCoolingDevices(bool filterType,CoolingType type,hidl_vec<CoolingDevice_2_0> * cooling_devices) const625 bool ThermalHelper::fillCurrentCoolingDevices(bool filterType, CoolingType type,
626 hidl_vec<CoolingDevice_2_0> *cooling_devices) const {
627 std::vector<CoolingDevice_2_0> ret;
628 for (const auto &name_info_pair : cooling_device_info_map_) {
629 CoolingDevice_2_0 value;
630 if (filterType && name_info_pair.second != type) {
631 continue;
632 }
633 if (readCoolingDevice(name_info_pair.first, &value)) {
634 ret.emplace_back(std::move(value));
635 } else {
636 LOG(ERROR) << __func__ << ": error reading cooling device: " << name_info_pair.first;
637 return false;
638 }
639 }
640 *cooling_devices = ret;
641 return ret.size() > 0;
642 }
643
fillCpuUsages(hidl_vec<CpuUsage> * cpu_usages) const644 bool ThermalHelper::fillCpuUsages(hidl_vec<CpuUsage> *cpu_usages) const {
645 cpu_usages->resize(kMaxCpus);
646 parseCpuUsagesFileAndAssignUsages(cpu_usages);
647 return true;
648 }
649
650 // This is called in the different thread context and will update sensor_status
651 // uevent_sensors is the set of sensors which trigger uevent from thermal core driver.
thermalWatcherCallbackFunc(const std::set<std::string> & uevent_sensors)652 bool ThermalHelper::thermalWatcherCallbackFunc(const std::set<std::string> &uevent_sensors) {
653 std::vector<Temperature_2_0> temps;
654 bool thermal_triggered = false;
655 for (auto &name_status_pair : sensor_status_map_) {
656 Temperature_2_0 temp;
657 TemperatureThreshold threshold;
658 SensorStatus &sensor_status = name_status_pair.second;
659 const SensorInfo &sensor_info = sensor_info_map_.at(name_status_pair.first);
660 // Only send notification on whitelisted sensors
661 if (!sensor_info.is_monitor) {
662 continue;
663 }
664 // If callback is triggered by uevent, only check the sensors within uevent_sensors
665 if (uevent_sensors.size() != 0 &&
666 uevent_sensors.find(name_status_pair.first) == uevent_sensors.end()) {
667 if (sensor_status.severity != ThrottlingSeverity::NONE) {
668 thermal_triggered = true;
669 }
670 continue;
671 }
672
673 std::pair<ThrottlingSeverity, ThrottlingSeverity> throtting_status;
674 if (!readTemperature(name_status_pair.first, &temp, &throtting_status)) {
675 LOG(ERROR) << __func__
676 << ": error reading temperature for sensor: " << name_status_pair.first;
677 continue;
678 }
679 if (!readTemperatureThreshold(name_status_pair.first, &threshold)) {
680 LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
681 << name_status_pair.first;
682 continue;
683 }
684
685 {
686 // writer lock
687 std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
688 if (throtting_status.first != sensor_status.prev_hot_severity) {
689 sensor_status.prev_hot_severity = throtting_status.first;
690 }
691 if (throtting_status.second != sensor_status.prev_cold_severity) {
692 sensor_status.prev_cold_severity = throtting_status.second;
693 }
694 if (temp.throttlingStatus != sensor_status.severity) {
695 temps.push_back(temp);
696 sensor_status.severity = temp.throttlingStatus;
697 }
698 }
699 if (sensor_status.severity != ThrottlingSeverity::NONE) {
700 thermal_triggered = true;
701 LOG(INFO) << temp.name << ": " << temp.value;
702 }
703 }
704 if (!temps.empty() && cb_) {
705 cb_(temps);
706 }
707
708 return thermal_triggered;
709 }
710
connectToPowerHal()711 bool ThermalHelper::connectToPowerHal() {
712 return power_hal_service_.connect();
713 }
714
updateSupportedPowerHints()715 void ThermalHelper::updateSupportedPowerHints() {
716 for (auto const &name_status_pair : sensor_info_map_) {
717 if (!name_status_pair.second.send_powerhint) {
718 continue;
719 }
720 ThrottlingSeverity current_severity = ThrottlingSeverity::NONE;
721 for (const auto &severity : hidl_enum_range<ThrottlingSeverity>()) {
722 LOG(ERROR) << "sensor: " << name_status_pair.first
723 << " current_severity :" << toString(current_severity) << " severity "
724 << toString(severity);
725 if (severity == ThrottlingSeverity::NONE) {
726 supported_powerhint_map_[name_status_pair.first][ThrottlingSeverity::NONE] =
727 ThrottlingSeverity::NONE;
728 continue;
729 }
730
731 bool isSupported = false;
732 ndk::ScopedAStatus isSupportedResult;
733
734 if (power_hal_service_.isPowerHalExtConnected()) {
735 isSupported = power_hal_service_.isModeSupported(name_status_pair.first, severity);
736 }
737 if (isSupported)
738 current_severity = severity;
739 supported_powerhint_map_[name_status_pair.first][severity] = current_severity;
740 }
741 }
742 }
743
sendPowerExtHint(const Temperature_2_0 & t)744 void ThermalHelper::sendPowerExtHint(const Temperature_2_0 &t) {
745 std::lock_guard<std::shared_mutex> lock(sensor_status_map_mutex_);
746 if (!isAidlPowerHalExist())
747 return;
748
749 if (!sensor_info_map_.at(t.name).send_powerhint)
750 return;
751
752 ThrottlingSeverity prev_hint_severity;
753 prev_hint_severity = sensor_status_map_.at(t.name).prev_hint_severity;
754 ThrottlingSeverity current_hint_severity = supported_powerhint_map_[t.name][t.throttlingStatus];
755
756 if (prev_hint_severity == current_hint_severity)
757 return;
758
759 if (prev_hint_severity != ThrottlingSeverity::NONE) {
760 power_hal_service_.setMode(t.name, prev_hint_severity, false);
761 }
762
763 if (current_hint_severity != ThrottlingSeverity::NONE) {
764 power_hal_service_.setMode(t.name, current_hint_severity, true);
765 }
766
767 sensor_status_map_[t.name].prev_hint_severity = current_hint_severity;
768 }
769 } // namespace implementation
770 } // namespace V2_0
771 } // namespace thermal
772 } // namespace hardware
773 } // namespace android
774