blob: 85ccc5d5b3119c870bf3778a5ce395fd6c1c03d6 [file] [log] [blame]
Wei Wang086a2b22018-10-22 13:54:33 -07001/*
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 */
TeYuan Wangd0979f82022-02-11 19:17:51 +080016#define ATRACE_TAG (ATRACE_TAG_THERMAL | ATRACE_TAG_HAL)
Wei Wang086a2b22018-10-22 13:54:33 -070017
TeYuan Wangd0979f82022-02-11 19:17:51 +080018#include "thermal-helper.h"
Wei Wang086a2b22018-10-22 13:54:33 -070019
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>
TeYuan Wangd0979f82022-02-11 19:17:51 +080025#include <utils/Trace.h>
Wei Wang086a2b22018-10-22 13:54:33 -070026
TeYuan Wangd0979f82022-02-11 19:17:51 +080027#include <iterator>
28#include <set>
29#include <sstream>
30#include <thread>
31#include <vector>
Wei Wang086a2b22018-10-22 13:54:33 -070032
33namespace android {
34namespace hardware {
35namespace thermal {
36namespace V2_0 {
37namespace implementation {
38
TeYuan Wang2f5b7f62019-01-07 13:39:21 +080039constexpr std::string_view kCpuOnlineRoot("/sys/devices/system/cpu");
40constexpr std::string_view kThermalSensorsRoot("/sys/devices/virtual/thermal");
41constexpr std::string_view kCpuUsageFile("/proc/stat");
42constexpr std::string_view kCpuOnlineFileSuffix("online");
43constexpr std::string_view kCpuPresentFile("/sys/devices/system/cpu/present");
44constexpr std::string_view kSensorPrefix("thermal_zone");
45constexpr std::string_view kCoolingDevicePrefix("cooling_device");
46constexpr std::string_view kThermalNameFile("type");
47constexpr std::string_view kSensorPolicyFile("policy");
48constexpr std::string_view kSensorTempSuffix("temp");
49constexpr std::string_view kSensorTripPointTempZeroFile("trip_point_0_temp");
50constexpr std::string_view kSensorTripPointHystZeroFile("trip_point_0_hyst");
51constexpr std::string_view kUserSpaceSuffix("user_space");
52constexpr std::string_view kCoolingDeviceCurStateSuffix("cur_state");
TeYuan Wangc6186262021-04-27 15:11:44 +080053constexpr std::string_view kCoolingDeviceMaxStateSuffix("max_state");
David Chaod774cbb2021-06-09 11:08:18 +080054constexpr std::string_view kCoolingDeviceState2powerSuffix("state2power_table");
TeYuan Wang2f5b7f62019-01-07 13:39:21 +080055constexpr std::string_view kConfigProperty("vendor.thermal.config");
56constexpr std::string_view kConfigDefaultFileName("thermal_info_config.json");
davidchaoca114b72020-11-12 14:02:23 +080057constexpr std::string_view kThermalGenlProperty("persist.vendor.enable.thermal.genl");
TeYuan Wang2f5576d2021-03-03 15:03:53 +080058constexpr std::string_view kThermalDisabledProperty("vendor.disable.thermal.control");
Wei Wang086a2b22018-10-22 13:54:33 -070059
60namespace {
61using android::base::StringPrintf;
62
Wei Wangbe444752019-02-01 15:12:28 -080063/*
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 */
Wei Wanga1c75072020-07-28 14:22:39 -070072static int getNumberOfCores() {
Wei Wang1c473562018-10-23 21:14:06 -070073 std::string file;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +080074 if (!android::base::ReadFileToString(kCpuPresentFile.data(), &file)) {
TeYuan Wang708a1df2022-03-28 20:26:06 +080075 LOG(ERROR) << "Error reading CPU present file: " << kCpuPresentFile;
Wei Wang1c473562018-10-23 21:14:06 -070076 return 0;
Wei Wang086a2b22018-10-22 13:54:33 -070077 }
Wei Wang1c473562018-10-23 21:14:06 -070078 std::vector<std::string> pieces = android::base::Split(file, "-");
79 if (pieces.size() != 2) {
TeYuan Wang708a1df2022-03-28 20:26:06 +080080 LOG(ERROR) << "Error parsing CPU present file content: " << file;
Wei Wang1c473562018-10-23 21:14:06 -070081 return 0;
Wei Wang086a2b22018-10-22 13:54:33 -070082 }
Wei Wang1c473562018-10-23 21:14:06 -070083 auto min_core = std::stoul(pieces[0]);
84 auto max_core = std::stoul(pieces[1]);
85 if (max_core < min_core) {
TeYuan Wang708a1df2022-03-28 20:26:06 +080086 LOG(ERROR) << "Error parsing CPU present min and max: " << min_core << " - " << max_core;
Wei Wang1c473562018-10-23 21:14:06 -070087 return 0;
88 }
89 return static_cast<std::size_t>(max_core - min_core + 1);
Wei Wang086a2b22018-10-22 13:54:33 -070090}
Wei Wanga1c75072020-07-28 14:22:39 -070091const int kMaxCpus = getNumberOfCores();
Wei Wang086a2b22018-10-22 13:54:33 -070092
93void parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> *cpu_usages) {
Wei Wang086a2b22018-10-22 13:54:33 -070094 std::string data;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +080095 if (!android::base::ReadFileToString(kCpuUsageFile.data(), &data)) {
TeYuan Wang708a1df2022-03-28 20:26:06 +080096 LOG(ERROR) << "Error reading CPU usage file: " << kCpuUsageFile;
Wei Wang086a2b22018-10-22 13:54:33 -070097 return;
98 }
99
100 std::istringstream stat_data(data);
101 std::string line;
102 while (std::getline(stat_data, line)) {
davidchaoe145bf82021-02-10 03:28:21 +0800103 if (!line.find("cpu") && isdigit(line[3])) {
Wei Wang086a2b22018-10-22 13:54:33 -0700104 // Split the string using spaces.
105 std::vector<std::string> words = android::base::Split(line, " ");
Wei Wanga1c75072020-07-28 14:22:39 -0700106 std::string cpu_name = words[0];
107 int cpu_num = std::stoi(cpu_name.substr(3));
Wei Wang086a2b22018-10-22 13:54:33 -0700108
109 if (cpu_num < kMaxCpus) {
Wei Wanga1c75072020-07-28 14:22:39 -0700110 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]);
Wei Wang086a2b22018-10-22 13:54:33 -0700114
115 // Check if the CPU is online by reading the online file.
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800116 std::string cpu_online_path =
117 StringPrintf("%s/%s/%s", kCpuOnlineRoot.data(), cpu_name.c_str(),
118 kCpuOnlineFileSuffix.data());
Wei Wang086a2b22018-10-22 13:54:33 -0700119 std::string is_online;
120 if (!android::base::ReadFileToString(cpu_online_path, &is_online)) {
TeYuan Wang708a1df2022-03-28 20:26:06 +0800121 LOG(ERROR) << "Could not open CPU online file: " << cpu_online_path;
Wei Wang0fb78342020-07-20 17:38:09 -0700122 if (cpu_num != 0) {
123 return;
124 }
125 // Some architecture cannot offline cpu0, so assuming it is online
126 is_online = "1";
Wei Wang086a2b22018-10-22 13:54:33 -0700127 }
128 is_online = android::base::Trim(is_online);
129
Wei Wang086a2b22018-10-22 13:54:33 -0700130 (*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 {
TeYuan Wang708a1df2022-03-28 20:26:06 +0800134 LOG(ERROR) << "Unexpected CPU number: " << words[0];
Wei Wang086a2b22018-10-22 13:54:33 -0700135 return;
136 }
137 }
138 }
139}
140
TeYuan Wang5013fe42021-03-16 19:52:06 +0800141std::unordered_map<std::string, std::string> parseThermalPathMap(std::string_view prefix) {
142 std::unordered_map<std::string, std::string> path_map;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800143 std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(kThermalSensorsRoot.data()), closedir);
Wei Wangbe444752019-02-01 15:12:28 -0800144 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
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800155 if (!android::base::StartsWith(dp->d_name, prefix.data())) {
Wei Wangbe444752019-02-01 15:12:28 -0800156 continue;
157 }
158
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800159 std::string path = android::base::StringPrintf("%s/%s/%s", kThermalSensorsRoot.data(),
160 dp->d_name, kThermalNameFile.data());
Wei Wangbe444752019-02-01 15:12:28 -0800161 std::string name;
162 if (!android::base::ReadFileToString(path, &name)) {
163 PLOG(ERROR) << "Failed to read from " << path;
164 continue;
165 }
166
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800167 path_map.emplace(
168 android::base::Trim(name),
169 android::base::StringPrintf("%s/%s", kThermalSensorsRoot.data(), dp->d_name));
Wei Wangbe444752019-02-01 15:12:28 -0800170 }
171
172 return path_map;
173}
174
Wei Wang086a2b22018-10-22 13:54:33 -0700175} // 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 */
Wei Wang8720c722018-11-05 13:43:04 -0800182ThermalHelper::ThermalHelper(const NotificationCallback &cb)
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800183 : thermal_watcher_(new ThermalWatcher(
184 std::bind(&ThermalHelper::thermalWatcherCallbackFunc, this, std::placeholders::_1))),
TeYuan Wangb8173c12021-07-08 17:45:58 +0800185 cb_(cb) {
186 const std::string config_path =
187 "/vendor/etc/" +
188 android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data());
TeYuan Wang2ec4c032022-03-14 17:33:15 +0800189 bool thermal_throttling_disabled =
190 android::base::GetBoolProperty(kThermalDisabledProperty.data(), false);
191
192 is_initialized_ = ParseCoolingDevice(config_path, &cooling_device_info_map_) &&
TeYuan Wang708a1df2022-03-28 20:26:06 +0800193 ParseSensorInfo(config_path, &sensor_info_map_);
TeYuan Wang2ec4c032022-03-14 17:33:15 +0800194
195 if (thermal_throttling_disabled) {
196 return;
197 }
198
199 if (!is_initialized_) {
200 LOG(FATAL) << "Failed to parse thermal configs";
201 }
202
TeYuan Wangc6186262021-04-27 15:11:44 +0800203 auto tz_map = parseThermalPathMap(kSensorPrefix.data());
204 auto cdev_map = parseThermalPathMap(kCoolingDevicePrefix.data());
205
206 is_initialized_ = initializeSensorMap(tz_map) && initializeCoolingDevices(cdev_map);
TeYuan Wang2ec4c032022-03-14 17:33:15 +0800207
TeYuan Wangc6186262021-04-27 15:11:44 +0800208 if (!is_initialized_) {
209 LOG(FATAL) << "ThermalHAL could not be initialized properly.";
210 }
211
TeYuan Wang708a1df2022-03-28 20:26:06 +0800212 if (!power_files_.registerPowerRailsToWatch(config_path)) {
213 LOG(FATAL) << "Failed to register power rails";
214 }
215
Wei Wang1c473562018-10-23 21:14:06 -0700216 for (auto const &name_status_pair : sensor_info_map_) {
217 sensor_status_map_[name_status_pair.first] = {
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800218 .severity = ThrottlingSeverity::NONE,
219 .prev_hot_severity = ThrottlingSeverity::NONE,
220 .prev_cold_severity = ThrottlingSeverity::NONE,
221 .prev_hint_severity = ThrottlingSeverity::NONE,
TeYuan Wang8daf64c2021-07-05 11:17:05 +0800222 .last_update_time = boot_clock::time_point::min(),
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800223 .thermal_cached = {NAN, boot_clock::time_point::min()},
Wei Wang1c473562018-10-23 21:14:06 -0700224 };
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800225
TeYuan Wang708a1df2022-03-28 20:26:06 +0800226 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
TeYuan Wangc09e57e2022-05-10 12:12:50 +0800235 for (auto &binded_cdev_info_pair :
TeYuan Wang5013fe42021-03-16 19:52:06 +0800236 name_status_pair.second.throttling_info->binded_cdev_info_map) {
TeYuan Wangc09e57e2022-05-10 12:12:50 +0800237 const auto &cdev_info = cooling_device_info_map_.at(binded_cdev_info_pair.first);
TeYuan Wangcf16c812021-07-07 00:10:03 +0800238
TeYuan Wangc09e57e2022-05-10 12:12:50 +0800239 for (auto &cdev_ceiling : binded_cdev_info_pair.second.cdev_ceiling) {
TeYuan Wangb8173c12021-07-08 17:45:58 +0800240 if (cdev_ceiling > cdev_info.max_state) {
241 if (cdev_ceiling != std::numeric_limits<int>::max()) {
TeYuan Wangc09e57e2022-05-10 12:12:50 +0800242 LOG(ERROR)
243 << "Sensor " << name_status_pair.first << "'s "
244 << binded_cdev_info_pair.first << " cdev_ceiling:" << cdev_ceiling
245 << " is higher than max state:" << cdev_info.max_state;
TeYuan Wangb8173c12021-07-08 17:45:58 +0800246 }
TeYuan Wangcf16c812021-07-07 00:10:03 +0800247 cdev_ceiling = cdev_info.max_state;
248 }
TeYuan Wang5013fe42021-03-16 19:52:06 +0800249 }
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800250 }
251
TeYuan Wang4bc02eb2021-01-05 21:56:07 +0800252 if (name_status_pair.second.virtual_sensor_info != nullptr &&
TeYuan Wange80ff152022-06-28 16:33:12 +0800253 !name_status_pair.second.virtual_sensor_info->trigger_sensors.empty() &&
TeYuan Wanga5203482022-04-01 17:50:50 +0800254 name_status_pair.second.is_watch) {
TeYuan Wange80ff152022-06-28 16:33:12 +0800255 for (size_t i = 0;
256 i < name_status_pair.second.virtual_sensor_info->trigger_sensors.size(); i++) {
257 if (sensor_info_map_.find(
258 name_status_pair.second.virtual_sensor_info->trigger_sensors[i]) !=
259 sensor_info_map_.end()) {
260 sensor_info_map_[name_status_pair.second.virtual_sensor_info
261 ->trigger_sensors[i]]
262 .is_watch = true;
263 } else {
264 LOG(FATAL) << name_status_pair.first << "'s trigger sensor: "
265 << name_status_pair.second.virtual_sensor_info->trigger_sensors[i]
266 << " is invalid";
267 }
TeYuan Wang8cbada82020-12-10 15:49:53 +0800268 }
269 }
Wei Wang086a2b22018-10-22 13:54:33 -0700270 }
271
davidchaoca114b72020-11-12 14:02:23 +0800272 const bool thermal_genl_enabled =
273 android::base::GetBoolProperty(kThermalGenlProperty.data(), false);
TeYuan Wang63260822021-02-02 16:57:19 +0800274
275 std::set<std::string> monitored_sensors;
276 initializeTrip(tz_map, &monitored_sensors, thermal_genl_enabled);
277
davidchaoca114b72020-11-12 14:02:23 +0800278 if (thermal_genl_enabled) {
279 thermal_watcher_->registerFilesToWatchNl(monitored_sensors);
280 } else {
281 thermal_watcher_->registerFilesToWatch(monitored_sensors);
282 }
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800283
Wei Wang086a2b22018-10-22 13:54:33 -0700284 // Need start watching after status map initialized
285 is_initialized_ = thermal_watcher_->startWatchingDeviceFiles();
286 if (!is_initialized_) {
287 LOG(FATAL) << "ThermalHAL could not start watching thread properly.";
288 }
Kyle Lin7c8556b2020-08-07 17:02:55 +0800289
290 if (!connectToPowerHal()) {
291 LOG(ERROR) << "Fail to connect to Power Hal";
292 } else {
293 updateSupportedPowerHints();
294 }
Wei Wang086a2b22018-10-22 13:54:33 -0700295}
296
davidchaod9a195e2020-10-26 19:41:29 +0800297bool getThermalZoneTypeById(int tz_id, std::string *type) {
298 std::string tz_type;
299 std::string path =
300 android::base::StringPrintf("%s/%s%d/%s", kThermalSensorsRoot.data(),
301 kSensorPrefix.data(), tz_id, kThermalNameFile.data());
302 LOG(INFO) << "TZ Path: " << path;
303 if (!::android::base::ReadFileToString(path, &tz_type)) {
304 LOG(ERROR) << "Failed to read sensor: " << tz_type;
305 return false;
306 }
307
308 // Strip the newline.
309 *type = ::android::base::Trim(tz_type);
310 LOG(INFO) << "TZ type: " << *type;
311 return true;
312}
313
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800314bool ThermalHelper::readCoolingDevice(std::string_view cooling_device,
Wei Wang086a2b22018-10-22 13:54:33 -0700315 CoolingDevice_2_0 *out) const {
316 // Read the file. If the file can't be read temp will be empty string.
Wei Wangbe444752019-02-01 15:12:28 -0800317 std::string data;
Wei Wang086a2b22018-10-22 13:54:33 -0700318
Wei Wangbe444752019-02-01 15:12:28 -0800319 if (!cooling_devices_.readThermalFile(cooling_device, &data)) {
Wei Wang086a2b22018-10-22 13:54:33 -0700320 LOG(ERROR) << "readCoolingDevice: failed to read cooling_device: " << cooling_device;
321 return false;
322 }
323
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800324 const CdevInfo &cdev_info = cooling_device_info_map_.at(cooling_device.data());
325 const CoolingType &type = cdev_info.type;
Wei Wang086a2b22018-10-22 13:54:33 -0700326
327 out->type = type;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800328 out->name = cooling_device.data();
Wei Wangbe444752019-02-01 15:12:28 -0800329 out->value = std::stoi(data);
Wei Wang086a2b22018-10-22 13:54:33 -0700330
331 return true;
332}
333
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800334bool ThermalHelper::readTemperature(std::string_view sensor_name, Temperature_1_0 *out) {
335 // Return fail if the thermal sensor cannot be read.
336 float temp;
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800337 std::string sensor_log;
338 if (!readThermalSensor(sensor_name, &temp, false, &sensor_log)) {
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800339 LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
340 return false;
Wei Wang086a2b22018-10-22 13:54:33 -0700341 }
342
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800343 const SensorInfo &sensor_info = sensor_info_map_.at(sensor_name.data());
Wei Wang086a2b22018-10-22 13:54:33 -0700344 TemperatureType_1_0 type =
TeYuan Wang708a1df2022-03-28 20:26:06 +0800345 (static_cast<int>(sensor_info.type) > static_cast<int>(TemperatureType_1_0::SKIN))
346 ? TemperatureType_1_0::UNKNOWN
347 : static_cast<TemperatureType_1_0>(sensor_info.type);
Wei Wang086a2b22018-10-22 13:54:33 -0700348 out->type = type;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800349 out->name = sensor_name.data();
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800350 out->currentValue = temp * sensor_info.multiplier;
Wei Wang086a2b22018-10-22 13:54:33 -0700351 out->throttlingThreshold =
TeYuan Wang708a1df2022-03-28 20:26:06 +0800352 sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)];
Wei Wang086a2b22018-10-22 13:54:33 -0700353 out->shutdownThreshold =
TeYuan Wang708a1df2022-03-28 20:26:06 +0800354 sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SHUTDOWN)];
Wei Wang086a2b22018-10-22 13:54:33 -0700355 out->vrThrottlingThreshold = sensor_info.vr_threshold;
356
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800357 if (sensor_info.is_watch) {
358 LOG(INFO) << sensor_name.data() << ":" << out->currentValue << " raw data:[" << sensor_log
359 << "]";
360 }
Wei Wang086a2b22018-10-22 13:54:33 -0700361 return true;
362}
363
Wei Wang1c473562018-10-23 21:14:06 -0700364bool ThermalHelper::readTemperature(
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800365 std::string_view sensor_name, Temperature_2_0 *out,
George Lee9af1e972020-10-05 11:59:36 -0700366 std::pair<ThrottlingSeverity, ThrottlingSeverity> *throtting_status,
TeYuan Wange80ff152022-06-28 16:33:12 +0800367 const bool force_no_cache) {
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800368 // Return fail if the thermal sensor cannot be read.
369 float temp;
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800370 std::string sensor_log;
Wei Wang086a2b22018-10-22 13:54:33 -0700371
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800372 if (!readThermalSensor(sensor_name, &temp, force_no_cache, &sensor_log)) {
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800373 LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
374 return false;
Wei Wang086a2b22018-10-22 13:54:33 -0700375 }
376
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800377 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
Wei Wang086a2b22018-10-22 13:54:33 -0700378 out->type = sensor_info.type;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800379 out->name = sensor_name.data();
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800380 out->value = temp * sensor_info.multiplier;
Wei Wang086a2b22018-10-22 13:54:33 -0700381
Wei Wang12ad0a82019-02-19 16:18:25 -0800382 std::pair<ThrottlingSeverity, ThrottlingSeverity> status =
TeYuan Wang708a1df2022-03-28 20:26:06 +0800383 std::make_pair(ThrottlingSeverity::NONE, ThrottlingSeverity::NONE);
Wei Wang12ad0a82019-02-19 16:18:25 -0800384 // Only update status if the thermal sensor is being monitored
TeYuan Wanga5203482022-04-01 17:50:50 +0800385 if (sensor_info.is_watch) {
Wei Wang12ad0a82019-02-19 16:18:25 -0800386 ThrottlingSeverity prev_hot_severity, prev_cold_severity;
387 {
388 // reader lock, readTemperature will be called in Binder call and the watcher thread.
389 std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800390 prev_hot_severity = sensor_status_map_.at(sensor_name.data()).prev_hot_severity;
391 prev_cold_severity = sensor_status_map_.at(sensor_name.data()).prev_cold_severity;
Wei Wang12ad0a82019-02-19 16:18:25 -0800392 }
393 status = getSeverityFromThresholds(sensor_info.hot_thresholds, sensor_info.cold_thresholds,
394 sensor_info.hot_hysteresis, sensor_info.cold_hysteresis,
395 prev_hot_severity, prev_cold_severity, out->value);
Wei Wang1c473562018-10-23 21:14:06 -0700396 }
Wei Wang12ad0a82019-02-19 16:18:25 -0800397 if (throtting_status) {
398 *throtting_status = status;
399 }
Wei Wang1c473562018-10-23 21:14:06 -0700400
401 out->throttlingStatus = static_cast<size_t>(status.first) > static_cast<size_t>(status.second)
TeYuan Wang708a1df2022-03-28 20:26:06 +0800402 ? status.first
403 : status.second;
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800404 if (sensor_info.is_watch) {
405 LOG(INFO) << sensor_name.data() << ":" << out->value << " raw data:[" << sensor_log << "]";
406 }
Wei Wang086a2b22018-10-22 13:54:33 -0700407 return true;
408}
409
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800410bool ThermalHelper::readTemperatureThreshold(std::string_view sensor_name,
Wei Wang086a2b22018-10-22 13:54:33 -0700411 TemperatureThreshold *out) const {
412 // Read the file. If the file can't be read temp will be empty string.
413 std::string temp;
414 std::string path;
415
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800416 if (!sensor_info_map_.count(sensor_name.data())) {
Wei Wang086a2b22018-10-22 13:54:33 -0700417 LOG(ERROR) << __func__ << ": sensor not found: " << sensor_name;
418 return false;
419 }
420
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800421 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
Wei Wang086a2b22018-10-22 13:54:33 -0700422
423 out->type = sensor_info.type;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800424 out->name = sensor_name.data();
Wei Wang086a2b22018-10-22 13:54:33 -0700425 out->hotThrottlingThresholds = sensor_info.hot_thresholds;
426 out->coldThrottlingThresholds = sensor_info.cold_thresholds;
427 out->vrThrottlingThreshold = sensor_info.vr_threshold;
428 return true;
429}
430
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800431void ThermalHelper::updateCoolingDevices(const std::vector<std::string> &updated_cdev) {
TeYuan Wangb8173c12021-07-08 17:45:58 +0800432 int max_state;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800433
TeYuan Wang708a1df2022-03-28 20:26:06 +0800434 const auto &thermal_throttling_status_map = thermal_throttling_.GetThermalThrottlingStatusMap();
435
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800436 for (const auto &target_cdev : updated_cdev) {
437 max_state = 0;
TeYuan Wang708a1df2022-03-28 20:26:06 +0800438 for (const auto &thermal_throttling_status_pair : thermal_throttling_status_map) {
439 if (!thermal_throttling_status_pair.second.cdev_status_map.count(target_cdev)) {
440 continue;
441 }
442 const auto state =
443 thermal_throttling_status_pair.second.cdev_status_map.at(target_cdev);
444 if (state > max_state) {
445 max_state = state;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800446 }
447 }
448 if (cooling_devices_.writeCdevFile(target_cdev, std::to_string(max_state))) {
TeYuan Wang708a1df2022-03-28 20:26:06 +0800449 LOG(INFO) << "Successfully update cdev " << target_cdev << " sysfs to " << max_state;
TeYuan Wangd2920b92022-05-25 15:40:20 +0800450 } else {
451 LOG(ERROR) << "Failed to update cdev " << target_cdev << " sysfs to " << max_state;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800452 }
453 }
454}
455
Wei Wang1c473562018-10-23 21:14:06 -0700456std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelper::getSeverityFromThresholds(
TeYuan Wang708a1df2022-03-28 20:26:06 +0800457 const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
458 const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
459 ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
460 float value) const {
Wei Wang086a2b22018-10-22 13:54:33 -0700461 ThrottlingSeverity ret_hot = ThrottlingSeverity::NONE;
Wei Wang1c473562018-10-23 21:14:06 -0700462 ThrottlingSeverity ret_hot_hysteresis = ThrottlingSeverity::NONE;
Wei Wang086a2b22018-10-22 13:54:33 -0700463 ThrottlingSeverity ret_cold = ThrottlingSeverity::NONE;
Wei Wang1c473562018-10-23 21:14:06 -0700464 ThrottlingSeverity ret_cold_hysteresis = ThrottlingSeverity::NONE;
465
466 // Here we want to control the iteration from high to low, and hidl_enum_range doesn't support
467 // a reverse iterator yet.
468 for (size_t i = static_cast<size_t>(ThrottlingSeverity::SHUTDOWN);
469 i > static_cast<size_t>(ThrottlingSeverity::NONE); --i) {
470 if (!std::isnan(hot_thresholds[i]) && hot_thresholds[i] <= value &&
471 ret_hot == ThrottlingSeverity::NONE) {
472 ret_hot = static_cast<ThrottlingSeverity>(i);
Wei Wang086a2b22018-10-22 13:54:33 -0700473 }
Wei Wang1c473562018-10-23 21:14:06 -0700474 if (!std::isnan(hot_thresholds[i]) && (hot_thresholds[i] - hot_hysteresis[i]) < value &&
475 ret_hot_hysteresis == ThrottlingSeverity::NONE) {
476 ret_hot_hysteresis = static_cast<ThrottlingSeverity>(i);
477 }
478 if (!std::isnan(cold_thresholds[i]) && cold_thresholds[i] >= value &&
479 ret_cold == ThrottlingSeverity::NONE) {
480 ret_cold = static_cast<ThrottlingSeverity>(i);
481 }
482 if (!std::isnan(cold_thresholds[i]) && (cold_thresholds[i] + cold_hysteresis[i]) > value &&
483 ret_cold_hysteresis == ThrottlingSeverity::NONE) {
484 ret_cold_hysteresis = static_cast<ThrottlingSeverity>(i);
485 }
486 }
487 if (static_cast<size_t>(ret_hot) < static_cast<size_t>(prev_hot_severity)) {
488 ret_hot = ret_hot_hysteresis;
489 }
490 if (static_cast<size_t>(ret_cold) < static_cast<size_t>(prev_cold_severity)) {
491 ret_cold = ret_cold_hysteresis;
Wei Wang086a2b22018-10-22 13:54:33 -0700492 }
493
Wei Wang1c473562018-10-23 21:14:06 -0700494 return std::make_pair(ret_hot, ret_cold);
Wei Wang086a2b22018-10-22 13:54:33 -0700495}
496
TeYuan Wang5013fe42021-03-16 19:52:06 +0800497bool ThermalHelper::initializeSensorMap(
498 const std::unordered_map<std::string, std::string> &path_map) {
Wei Wangbe444752019-02-01 15:12:28 -0800499 for (const auto &sensor_info_pair : sensor_info_map_) {
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800500 std::string_view sensor_name = sensor_info_pair.first;
TeYuan Wang8cbada82020-12-10 15:49:53 +0800501 if (sensor_info_pair.second.virtual_sensor_info != nullptr) {
502 continue;
George Lee9af1e972020-10-05 11:59:36 -0700503 }
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800504 if (!path_map.count(sensor_name.data())) {
Wei Wangbe444752019-02-01 15:12:28 -0800505 LOG(ERROR) << "Could not find " << sensor_name << " in sysfs";
TeYuan Wang8cbada82020-12-10 15:49:53 +0800506 return false;
Wei Wangbe444752019-02-01 15:12:28 -0800507 }
YiHo Chengf1da54d2021-07-08 19:33:11 +0800508
509 std::string path;
510 if (sensor_info_pair.second.temp_path.empty()) {
511 path = android::base::StringPrintf("%s/%s", path_map.at(sensor_name.data()).c_str(),
512 kSensorTempSuffix.data());
513 } else {
514 path = sensor_info_pair.second.temp_path;
515 }
TeYuan Wang8cbada82020-12-10 15:49:53 +0800516
Wei Wangbe444752019-02-01 15:12:28 -0800517 if (!thermal_sensors_.addThermalFile(sensor_name, path)) {
Wei Wang086a2b22018-10-22 13:54:33 -0700518 LOG(ERROR) << "Could not add " << sensor_name << "to sensors map";
TeYuan Wang8cbada82020-12-10 15:49:53 +0800519 return false;
Wei Wang086a2b22018-10-22 13:54:33 -0700520 }
521 }
TeYuan Wang8cbada82020-12-10 15:49:53 +0800522 return true;
Wei Wang086a2b22018-10-22 13:54:33 -0700523}
524
TeYuan Wang5013fe42021-03-16 19:52:06 +0800525bool ThermalHelper::initializeCoolingDevices(
526 const std::unordered_map<std::string, std::string> &path_map) {
TeYuan Wangc6186262021-04-27 15:11:44 +0800527 for (auto &cooling_device_info_pair : cooling_device_info_map_) {
TeYuan Wang63260822021-02-02 16:57:19 +0800528 std::string cooling_device_name = cooling_device_info_pair.first;
529 if (!path_map.count(cooling_device_name)) {
Wei Wangbe444752019-02-01 15:12:28 -0800530 LOG(ERROR) << "Could not find " << cooling_device_name << " in sysfs";
TeYuan Wang2ec4c032022-03-14 17:33:15 +0800531 return false;
Wei Wangbe444752019-02-01 15:12:28 -0800532 }
TeYuan Wang63260822021-02-02 16:57:19 +0800533 // Add cooling device path for thermalHAL to get current state
534 std::string_view path = path_map.at(cooling_device_name);
535 std::string read_path;
536 if (!cooling_device_info_pair.second.read_path.empty()) {
537 read_path = cooling_device_info_pair.second.read_path.data();
538 } else {
539 read_path = android::base::StringPrintf("%s/%s", path.data(),
540 kCoolingDeviceCurStateSuffix.data());
541 }
542 if (!cooling_devices_.addThermalFile(cooling_device_name, read_path)) {
543 LOG(ERROR) << "Could not add " << cooling_device_name
544 << " read path to cooling device map";
TeYuan Wang2ec4c032022-03-14 17:33:15 +0800545 return false;
TeYuan Wang63260822021-02-02 16:57:19 +0800546 }
547
David Chaod774cbb2021-06-09 11:08:18 +0800548 std::string state2power_path = android::base::StringPrintf(
549 "%s/%s", path.data(), kCoolingDeviceState2powerSuffix.data());
550 std::string state2power_str;
551 if (android::base::ReadFileToString(state2power_path, &state2power_str)) {
552 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first
553 << " use state2power read from sysfs";
554 cooling_device_info_pair.second.state2power.clear();
555
556 std::stringstream power(state2power_str);
557 unsigned int power_number;
558 int i = 0;
559 while (power >> power_number) {
560 cooling_device_info_pair.second.state2power.push_back(
561 static_cast<float>(power_number));
562 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first << " state:" << i
563 << " power: " << power_number;
564 i++;
565 }
566 }
567
TeYuan Wangc6186262021-04-27 15:11:44 +0800568 // Get max cooling device request state
569 std::string max_state;
570 std::string max_state_path = android::base::StringPrintf(
571 "%s/%s", path.data(), kCoolingDeviceMaxStateSuffix.data());
572 if (!android::base::ReadFileToString(max_state_path, &max_state)) {
573 LOG(ERROR) << cooling_device_info_pair.first
574 << " could not open max state file:" << max_state_path;
TeYuan Wangb8173c12021-07-08 17:45:58 +0800575 cooling_device_info_pair.second.max_state = std::numeric_limits<int>::max();
TeYuan Wangc6186262021-04-27 15:11:44 +0800576 } else {
577 cooling_device_info_pair.second.max_state = std::stoi(android::base::Trim(max_state));
578 LOG(INFO) << "Cooling device " << cooling_device_info_pair.first
David Chaod774cbb2021-06-09 11:08:18 +0800579 << " max state: " << cooling_device_info_pair.second.max_state
580 << " state2power number: "
581 << cooling_device_info_pair.second.state2power.size();
582 if (cooling_device_info_pair.second.state2power.size() > 0 &&
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800583 static_cast<int>(cooling_device_info_pair.second.state2power.size()) !=
584 (cooling_device_info_pair.second.max_state + 1)) {
David Chaod774cbb2021-06-09 11:08:18 +0800585 LOG(ERROR) << "Invalid state2power number: "
586 << cooling_device_info_pair.second.state2power.size()
587 << ", number should be " << cooling_device_info_pair.second.max_state + 1
588 << " (max_state + 1)";
TeYuan Wang2ec4c032022-03-14 17:33:15 +0800589 return false;
David Chaod774cbb2021-06-09 11:08:18 +0800590 }
TeYuan Wangc6186262021-04-27 15:11:44 +0800591 }
592
TeYuan Wang63260822021-02-02 16:57:19 +0800593 // Add cooling device path for thermalHAL to request state
594 cooling_device_name =
595 android::base::StringPrintf("%s_%s", cooling_device_name.c_str(), "w");
596 std::string write_path;
597 if (!cooling_device_info_pair.second.write_path.empty()) {
598 write_path = cooling_device_info_pair.second.write_path.data();
599 } else {
600 write_path = android::base::StringPrintf("%s/%s", path.data(),
601 kCoolingDeviceCurStateSuffix.data());
602 }
603
604 if (!cooling_devices_.addThermalFile(cooling_device_name, write_path)) {
605 LOG(ERROR) << "Could not add " << cooling_device_name
606 << " write path to cooling device map";
TeYuan Wang2ec4c032022-03-14 17:33:15 +0800607 return false;
Wei Wang086a2b22018-10-22 13:54:33 -0700608 }
609 }
Wei Wang197195f2021-04-02 16:57:32 -0700610 return true;
Wei Wang086a2b22018-10-22 13:54:33 -0700611}
612
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800613void ThermalHelper::setMinTimeout(SensorInfo *sensor_info) {
614 sensor_info->polling_delay = kMinPollIntervalMs;
615 sensor_info->passive_delay = kMinPollIntervalMs;
616}
617
TeYuan Wang5013fe42021-03-16 19:52:06 +0800618void ThermalHelper::initializeTrip(const std::unordered_map<std::string, std::string> &path_map,
TeYuan Wang63260822021-02-02 16:57:19 +0800619 std::set<std::string> *monitored_sensors,
620 bool thermal_genl_enabled) {
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800621 for (auto &sensor_info : sensor_info_map_) {
TeYuan Wanga5203482022-04-01 17:50:50 +0800622 if (!sensor_info.second.is_watch || (sensor_info.second.virtual_sensor_info != nullptr)) {
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800623 continue;
624 }
625
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800626 bool trip_update = false;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800627 std::string_view sensor_name = sensor_info.first;
628 std::string_view tz_path = path_map.at(sensor_name.data());
629 std::string tz_policy;
630 std::string path =
631 android::base::StringPrintf("%s/%s", (tz_path.data()), kSensorPolicyFile.data());
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800632
633 if (thermal_genl_enabled) {
634 trip_update = true;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800635 } else {
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800636 // Check if thermal zone support uevent notify
637 if (!android::base::ReadFileToString(path, &tz_policy)) {
638 LOG(ERROR) << sensor_name << " could not open tz policy file:" << path;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800639 } else {
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800640 tz_policy = android::base::Trim(tz_policy);
641 if (tz_policy != kUserSpaceSuffix) {
642 LOG(ERROR) << sensor_name << " does not support uevent notify";
643 } else {
644 trip_update = true;
645 }
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800646 }
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800647 }
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800648 if (trip_update) {
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800649 // Update thermal zone trip point
650 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
651 if (!std::isnan(sensor_info.second.hot_thresholds[i]) &&
652 !std::isnan(sensor_info.second.hot_hysteresis[i])) {
653 // Update trip_point_0_temp threshold
654 std::string threshold = std::to_string(static_cast<int>(
655 sensor_info.second.hot_thresholds[i] / sensor_info.second.multiplier));
656 path = android::base::StringPrintf("%s/%s", (tz_path.data()),
657 kSensorTripPointTempZeroFile.data());
658 if (!android::base::WriteStringToFile(threshold, path)) {
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800659 LOG(ERROR) << "fail to update " << sensor_name << " trip point: " << path
660 << " to " << threshold;
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800661 trip_update = false;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800662 break;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800663 }
664 // Update trip_point_0_hyst threshold
665 threshold = std::to_string(static_cast<int>(
666 sensor_info.second.hot_hysteresis[i] / sensor_info.second.multiplier));
667 path = android::base::StringPrintf("%s/%s", (tz_path.data()),
668 kSensorTripPointHystZeroFile.data());
669 if (!android::base::WriteStringToFile(threshold, path)) {
670 LOG(ERROR) << "fail to update " << sensor_name << "trip hyst" << threshold
671 << path;
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800672 trip_update = false;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800673 break;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800674 }
675 break;
676 } else if (i == kThrottlingSeverityCount - 1) {
677 LOG(ERROR) << sensor_name << ":all thresholds are NAN";
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800678 trip_update = false;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800679 break;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800680 }
681 }
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800682 monitored_sensors->insert(sensor_info.first);
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800683 }
TeYuan Wang63260822021-02-02 16:57:19 +0800684
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800685 if (!trip_update) {
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800686 LOG(INFO) << "config Sensor: " << sensor_info.first
687 << " to default polling interval: " << kMinPollIntervalMs.count();
688 setMinTimeout(&sensor_info.second);
689 }
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800690 }
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800691}
TeYuan Wang4edd2aa2021-02-18 21:40:27 +0800692
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800693bool ThermalHelper::fillTemperatures(hidl_vec<Temperature_1_0> *temperatures) {
TeYuan Wang2d3c6662022-04-06 11:36:07 +0800694 std::vector<Temperature_1_0> ret;
Wei Wang086a2b22018-10-22 13:54:33 -0700695 for (const auto &name_info_pair : sensor_info_map_) {
696 Temperature_1_0 temp;
697
TeYuan Wanga5203482022-04-01 17:50:50 +0800698 if (name_info_pair.second.is_hidden) {
699 continue;
700 }
701
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800702 if (readTemperature(name_info_pair.first, &temp)) {
TeYuan Wang2d3c6662022-04-06 11:36:07 +0800703 ret.emplace_back(std::move(temp));
Wei Wang086a2b22018-10-22 13:54:33 -0700704 } else {
705 LOG(ERROR) << __func__
706 << ": error reading temperature for sensor: " << name_info_pair.first;
TeYuan Wang708a1df2022-03-28 20:26:06 +0800707 return false;
Wei Wang086a2b22018-10-22 13:54:33 -0700708 }
Wei Wang086a2b22018-10-22 13:54:33 -0700709 }
TeYuan Wang2d3c6662022-04-06 11:36:07 +0800710 *temperatures = ret;
TeYuan Wang2d3c6662022-04-06 11:36:07 +0800711 return ret.size() > 0;
Wei Wang086a2b22018-10-22 13:54:33 -0700712}
713
TeYuan Wangb9f33ac2021-08-04 20:39:42 +0800714bool ThermalHelper::fillCurrentTemperatures(bool filterType, bool filterCallback,
715 TemperatureType_2_0 type,
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800716 hidl_vec<Temperature_2_0> *temperatures) {
Wei Wang086a2b22018-10-22 13:54:33 -0700717 std::vector<Temperature_2_0> ret;
718 for (const auto &name_info_pair : sensor_info_map_) {
719 Temperature_2_0 temp;
TeYuan Wanga5203482022-04-01 17:50:50 +0800720 if (name_info_pair.second.is_hidden) {
721 continue;
722 }
Wei Wang086a2b22018-10-22 13:54:33 -0700723 if (filterType && name_info_pair.second.type != type) {
724 continue;
725 }
TeYuan Wangb9f33ac2021-08-04 20:39:42 +0800726 if (filterCallback && !name_info_pair.second.send_cb) {
727 continue;
728 }
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800729 if (readTemperature(name_info_pair.first, &temp, nullptr, false)) {
Wei Wang086a2b22018-10-22 13:54:33 -0700730 ret.emplace_back(std::move(temp));
731 } else {
732 LOG(ERROR) << __func__
733 << ": error reading temperature for sensor: " << name_info_pair.first;
Wei Wang086a2b22018-10-22 13:54:33 -0700734 }
735 }
736 *temperatures = ret;
737 return ret.size() > 0;
738}
739
740bool ThermalHelper::fillTemperatureThresholds(bool filterType, TemperatureType_2_0 type,
741 hidl_vec<TemperatureThreshold> *thresholds) const {
742 std::vector<TemperatureThreshold> ret;
743 for (const auto &name_info_pair : sensor_info_map_) {
744 TemperatureThreshold temp;
TeYuan Wanga5203482022-04-01 17:50:50 +0800745 if (name_info_pair.second.is_hidden) {
746 continue;
747 }
Wei Wang086a2b22018-10-22 13:54:33 -0700748 if (filterType && name_info_pair.second.type != type) {
749 continue;
750 }
751 if (readTemperatureThreshold(name_info_pair.first, &temp)) {
752 ret.emplace_back(std::move(temp));
753 } else {
754 LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
755 << name_info_pair.first;
756 return false;
757 }
758 }
759 *thresholds = ret;
760 return ret.size() > 0;
761}
762
763bool ThermalHelper::fillCurrentCoolingDevices(bool filterType, CoolingType type,
764 hidl_vec<CoolingDevice_2_0> *cooling_devices) const {
765 std::vector<CoolingDevice_2_0> ret;
766 for (const auto &name_info_pair : cooling_device_info_map_) {
767 CoolingDevice_2_0 value;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800768 if (filterType && name_info_pair.second.type != type) {
Wei Wang086a2b22018-10-22 13:54:33 -0700769 continue;
770 }
771 if (readCoolingDevice(name_info_pair.first, &value)) {
772 ret.emplace_back(std::move(value));
773 } else {
774 LOG(ERROR) << __func__ << ": error reading cooling device: " << name_info_pair.first;
775 return false;
776 }
777 }
778 *cooling_devices = ret;
779 return ret.size() > 0;
780}
781
782bool ThermalHelper::fillCpuUsages(hidl_vec<CpuUsage> *cpu_usages) const {
783 cpu_usages->resize(kMaxCpus);
Wei Wanga1c75072020-07-28 14:22:39 -0700784 for (int i = 0; i < kMaxCpus; i++) {
785 (*cpu_usages)[i].name = StringPrintf("cpu%d", i);
786 (*cpu_usages)[i].active = 0;
787 (*cpu_usages)[i].total = 0;
788 (*cpu_usages)[i].isOnline = false;
789 }
Wei Wang086a2b22018-10-22 13:54:33 -0700790 parseCpuUsagesFileAndAssignUsages(cpu_usages);
791 return true;
792}
793
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800794bool ThermalHelper::readThermalSensor(std::string_view sensor_name, float *temp,
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800795 const bool force_no_cache, std::string *sensor_log) {
TeYuan Wang8cbada82020-12-10 15:49:53 +0800796 float temp_val = 0.0;
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800797 std::string file_reading;
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800798 std::string sub_sensor_log;
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800799 boot_clock::time_point now = boot_clock::now();
800
TeYuan Wangd0979f82022-02-11 19:17:51 +0800801 ATRACE_NAME(StringPrintf("ThermalHelper::readThermalSensor - %s", sensor_name.data()).c_str());
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800802 if (!(sensor_info_map_.count(sensor_name.data()) &&
803 sensor_status_map_.count(sensor_name.data()))) {
804 return false;
805 }
TeYuan Wang8cbada82020-12-10 15:49:53 +0800806
807 const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800808 auto &sensor_status = sensor_status_map_.at(sensor_name.data());
809
810 // Check if thermal data need to be read from buffer
TeYuan Wange80ff152022-06-28 16:33:12 +0800811 if (!force_no_cache &&
812 (sensor_status.thermal_cached.timestamp != boot_clock::time_point::min()) &&
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800813 (std::chrono::duration_cast<std::chrono::milliseconds>(
814 now - sensor_status.thermal_cached.timestamp) < sensor_info.time_resolution) &&
815 !isnan(sensor_status.thermal_cached.temp)) {
816 *temp = sensor_status.thermal_cached.temp;
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800817 sensor_log->append(StringPrintf("%s:%0.f ", sensor_name.data(), *temp));
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800818 LOG(VERBOSE) << "read " << sensor_name.data() << " from buffer, value:" << *temp;
819 return true;
820 }
821
822 // Reading thermal sensor according to it's composition
823 if (sensor_info.virtual_sensor_info == nullptr) {
824 if (!thermal_sensors_.readThermalFile(sensor_name.data(), &file_reading)) {
TeYuan Wang8cbada82020-12-10 15:49:53 +0800825 return false;
George Lee9af1e972020-10-05 11:59:36 -0700826 }
TeYuan Wang8cbada82020-12-10 15:49:53 +0800827
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800828 if (file_reading.empty()) {
829 LOG(ERROR) << "failed to read sensor: " << sensor_name;
TeYuan Wang8cbada82020-12-10 15:49:53 +0800830 return false;
George Lee9af1e972020-10-05 11:59:36 -0700831 }
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800832 *temp = std::stof(::android::base::Trim(file_reading));
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800833 sensor_log->append(StringPrintf("%s:%0.f ", sensor_name.data(), *temp));
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800834 } else {
835 for (size_t i = 0; i < sensor_info.virtual_sensor_info->linked_sensors.size(); i++) {
836 float sensor_reading = 0.0;
837 if (!readThermalSensor(sensor_info.virtual_sensor_info->linked_sensors[i],
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800838 &sensor_reading, force_no_cache, &sub_sensor_log)) {
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800839 return false;
840 }
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800841 if (std::isnan(sensor_info.virtual_sensor_info->coefficients[i])) {
842 return false;
843 }
844
845 float coefficient = sensor_info.virtual_sensor_info->coefficients[i];
846 switch (sensor_info.virtual_sensor_info->formula) {
847 case FormulaOption::COUNT_THRESHOLD:
848 if ((coefficient < 0 && sensor_reading < -coefficient) ||
849 (coefficient >= 0 && sensor_reading >= coefficient))
850 temp_val += 1;
851 break;
852 case FormulaOption::WEIGHTED_AVG:
853 temp_val += sensor_reading * coefficient;
854 break;
855 case FormulaOption::MAXIMUM:
856 if (i == 0)
857 temp_val = std::numeric_limits<float>::lowest();
858 if (sensor_reading * coefficient > temp_val)
859 temp_val = sensor_reading * coefficient;
860 break;
861 case FormulaOption::MINIMUM:
862 if (i == 0)
863 temp_val = std::numeric_limits<float>::max();
864 if (sensor_reading * coefficient < temp_val)
865 temp_val = sensor_reading * coefficient;
866 break;
867 default:
868 break;
869 }
TeYuan Wang8cbada82020-12-10 15:49:53 +0800870 }
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800871 *temp = (temp_val + sensor_info.virtual_sensor_info->offset);
TeYuan Wangaadb90a2022-09-23 17:16:36 +0800872 sensor_log->append(
873 StringPrintf("%s:%0.f(%s) ", sensor_name.data(), *temp, sub_sensor_log.data()));
George Lee9af1e972020-10-05 11:59:36 -0700874 }
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800875
876 {
877 std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
878 sensor_status.thermal_cached.temp = *temp;
879 sensor_status.thermal_cached.timestamp = now;
880 }
881
TeYuan Wang8cbada82020-12-10 15:49:53 +0800882 return true;
George Lee9af1e972020-10-05 11:59:36 -0700883}
884
Wei Wang1c473562018-10-23 21:14:06 -0700885// This is called in the different thread context and will update sensor_status
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800886// uevent_sensors is the set of sensors which trigger uevent from thermal core driver.
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800887std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc(
888 const std::set<std::string> &uevent_sensors) {
Wei Wang086a2b22018-10-22 13:54:33 -0700889 std::vector<Temperature_2_0> temps;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800890 std::vector<std::string> cooling_devices_to_update;
891 boot_clock::time_point now = boot_clock::now();
TeYuan Wang5013fe42021-03-16 19:52:06 +0800892 auto min_sleep_ms = std::chrono::milliseconds::max();
TeYuan Wang708a1df2022-03-28 20:26:06 +0800893 bool power_data_is_updated = false;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800894
TeYuan Wangd0979f82022-02-11 19:17:51 +0800895 ATRACE_CALL();
Wei Wang1c473562018-10-23 21:14:06 -0700896 for (auto &name_status_pair : sensor_status_map_) {
TeYuan Wang8cbada82020-12-10 15:49:53 +0800897 bool force_update = false;
TeYuan Wange80ff152022-06-28 16:33:12 +0800898 bool force_no_cache = false;
Wei Wang086a2b22018-10-22 13:54:33 -0700899 Temperature_2_0 temp;
900 TemperatureThreshold threshold;
901 SensorStatus &sensor_status = name_status_pair.second;
902 const SensorInfo &sensor_info = sensor_info_map_.at(name_status_pair.first);
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800903
904 // Only handle the sensors in allow list
TeYuan Wang996a9e12022-04-13 11:38:45 +0800905 if (!sensor_info.is_watch) {
Wei Wang086a2b22018-10-22 13:54:33 -0700906 continue;
907 }
George Lee9af1e972020-10-05 11:59:36 -0700908
TeYuan Wangd0979f82022-02-11 19:17:51 +0800909 ATRACE_NAME(StringPrintf("ThermalHelper::thermalWatcherCallbackFunc - %s",
910 name_status_pair.first.data())
911 .c_str());
912
TeYuan Wang8daf64c2021-07-05 11:17:05 +0800913 std::chrono::milliseconds time_elapsed_ms = std::chrono::milliseconds::zero();
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800914 auto sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
915 ? sensor_info.passive_delay
916 : sensor_info.polling_delay;
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800917
918 if (sensor_info.virtual_sensor_info != nullptr &&
TeYuan Wange80ff152022-06-28 16:33:12 +0800919 !sensor_info.virtual_sensor_info->trigger_sensors.empty()) {
920 for (size_t i = 0; i < sensor_info.virtual_sensor_info->trigger_sensors.size(); i++) {
921 const auto &trigger_sensor_status =
922 sensor_status_map_.at(sensor_info.virtual_sensor_info->trigger_sensors[i]);
923 if (trigger_sensor_status.severity != ThrottlingSeverity::NONE) {
924 sleep_ms = sensor_info.passive_delay;
925 }
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800926 }
927 }
TeYuan Wang8daf64c2021-07-05 11:17:05 +0800928 // Check if the sensor need to be updated
929 if (sensor_status.last_update_time == boot_clock::time_point::min()) {
TeYuan Wang8cbada82020-12-10 15:49:53 +0800930 force_update = true;
TeYuan Wange80ff152022-06-28 16:33:12 +0800931 force_no_cache = true;
TeYuan Wang8daf64c2021-07-05 11:17:05 +0800932 } else {
933 time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
934 now - sensor_status.last_update_time);
TeYuan Wange80ff152022-06-28 16:33:12 +0800935 if (uevent_sensors.size()) {
936 if (sensor_info.virtual_sensor_info != nullptr) {
937 for (size_t i = 0; i < sensor_info.virtual_sensor_info->trigger_sensors.size();
938 i++) {
939 if (uevent_sensors.find(
940 sensor_info.virtual_sensor_info->trigger_sensors[i]) !=
941 uevent_sensors.end()) {
942 force_update = true;
943 force_no_cache = true;
944 }
945 }
946 } else if (uevent_sensors.find(name_status_pair.first) != uevent_sensors.end()) {
947 force_update = true;
948 force_no_cache = true;
949 }
950 } else if (time_elapsed_ms > sleep_ms) {
TeYuan Wang8cbada82020-12-10 15:49:53 +0800951 force_update = true;
952 }
953 }
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800954 LOG(VERBOSE) << "sensor " << name_status_pair.first
955 << ": time_elpased=" << time_elapsed_ms.count()
TeYuan Wang1a3d0172021-12-23 15:30:16 +0800956 << ", sleep_ms=" << sleep_ms.count() << ", force_update = " << force_update
TeYuan Wange80ff152022-06-28 16:33:12 +0800957 << ", force_no_cache = " << force_no_cache;
TeYuan Wang8cbada82020-12-10 15:49:53 +0800958
959 if (!force_update) {
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800960 auto timeout_remaining = sleep_ms - time_elapsed_ms;
961 if (min_sleep_ms > timeout_remaining) {
962 min_sleep_ms = timeout_remaining;
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800963 }
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800964 LOG(VERBOSE) << "sensor " << name_status_pair.first
965 << ": timeout_remaining=" << timeout_remaining.count();
TeYuan Wang2f5b7f62019-01-07 13:39:21 +0800966 continue;
967 }
Wei Wang086a2b22018-10-22 13:54:33 -0700968
Wei Wang1c473562018-10-23 21:14:06 -0700969 std::pair<ThrottlingSeverity, ThrottlingSeverity> throtting_status;
TeYuan Wange80ff152022-06-28 16:33:12 +0800970 if (!readTemperature(name_status_pair.first, &temp, &throtting_status, force_no_cache)) {
Wei Wang086a2b22018-10-22 13:54:33 -0700971 LOG(ERROR) << __func__
972 << ": error reading temperature for sensor: " << name_status_pair.first;
973 continue;
974 }
975 if (!readTemperatureThreshold(name_status_pair.first, &threshold)) {
976 LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
977 << name_status_pair.first;
978 continue;
979 }
Wei Wang1c473562018-10-23 21:14:06 -0700980
981 {
982 // writer lock
983 std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
984 if (throtting_status.first != sensor_status.prev_hot_severity) {
985 sensor_status.prev_hot_severity = throtting_status.first;
986 }
987 if (throtting_status.second != sensor_status.prev_cold_severity) {
988 sensor_status.prev_cold_severity = throtting_status.second;
989 }
990 if (temp.throttlingStatus != sensor_status.severity) {
991 temps.push_back(temp);
992 sensor_status.severity = temp.throttlingStatus;
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800993 sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
994 ? sensor_info.passive_delay
995 : sensor_info.polling_delay;
Wei Wang1c473562018-10-23 21:14:06 -0700996 }
Wei Wang086a2b22018-10-22 13:54:33 -0700997 }
TeYuan Wangdcee68c2020-10-21 16:29:37 +0800998
TeYuan Wang708a1df2022-03-28 20:26:06 +0800999 if (!power_data_is_updated) {
1000 power_files_.refreshPowerStatus();
1001 power_data_is_updated = true;
1002 }
1003
1004 if (sensor_status.severity == ThrottlingSeverity::NONE) {
TeYuan Wang708a1df2022-03-28 20:26:06 +08001005 thermal_throttling_.clearThrottlingData(name_status_pair.first, sensor_info);
1006 } else {
TeYuan Wang708a1df2022-03-28 20:26:06 +08001007 // update thermal throttling request
1008 thermal_throttling_.thermalThrottlingUpdate(
1009 temp, sensor_info, sensor_status.severity, time_elapsed_ms,
1010 power_files_.GetPowerStatusMap(), cooling_device_info_map_);
TeYuan Wang2f5b7f62019-01-07 13:39:21 +08001011 }
TeYuan Wangdcee68c2020-10-21 16:29:37 +08001012
TeYuan Wang708a1df2022-03-28 20:26:06 +08001013 thermal_throttling_.computeCoolingDevicesRequest(name_status_pair.first, sensor_info,
1014 sensor_status.severity,
1015 &cooling_devices_to_update);
TeYuan Wangdcee68c2020-10-21 16:29:37 +08001016 if (min_sleep_ms > sleep_ms) {
1017 min_sleep_ms = sleep_ms;
1018 }
TeYuan Wang708a1df2022-03-28 20:26:06 +08001019
TeYuan Wangdcee68c2020-10-21 16:29:37 +08001020 LOG(VERBOSE) << "Sensor " << name_status_pair.first << ": sleep_ms=" << sleep_ms.count()
1021 << ", min_sleep_ms voting result=" << min_sleep_ms.count();
1022 sensor_status.last_update_time = now;
Wei Wang086a2b22018-10-22 13:54:33 -07001023 }
TeYuan Wang2f5b7f62019-01-07 13:39:21 +08001024
TeYuan Wangdcee68c2020-10-21 16:29:37 +08001025 if (!cooling_devices_to_update.empty()) {
1026 updateCoolingDevices(cooling_devices_to_update);
1027 }
1028
1029 if (!temps.empty()) {
1030 for (const auto &t : temps) {
1031 if (sensor_info_map_.at(t.name).send_cb && cb_) {
1032 cb_(t);
1033 }
1034
1035 if (sensor_info_map_.at(t.name).send_powerhint && isAidlPowerHalExist()) {
1036 sendPowerExtHint(t);
1037 }
1038 }
1039 }
1040
TeYuan Wang708a1df2022-03-28 20:26:06 +08001041 return min_sleep_ms;
Wei Wang086a2b22018-10-22 13:54:33 -07001042}
1043
Kyle Lin7c8556b2020-08-07 17:02:55 +08001044bool ThermalHelper::connectToPowerHal() {
1045 return power_hal_service_.connect();
1046}
1047
1048void ThermalHelper::updateSupportedPowerHints() {
1049 for (auto const &name_status_pair : sensor_info_map_) {
TeYuan Wangdcee68c2020-10-21 16:29:37 +08001050 if (!(name_status_pair.second.send_powerhint)) {
Kyle Lin7c8556b2020-08-07 17:02:55 +08001051 continue;
1052 }
1053 ThrottlingSeverity current_severity = ThrottlingSeverity::NONE;
1054 for (const auto &severity : hidl_enum_range<ThrottlingSeverity>()) {
Kyle Lin7c8556b2020-08-07 17:02:55 +08001055 if (severity == ThrottlingSeverity::NONE) {
1056 supported_powerhint_map_[name_status_pair.first][ThrottlingSeverity::NONE] =
1057 ThrottlingSeverity::NONE;
1058 continue;
1059 }
1060
1061 bool isSupported = false;
1062 ndk::ScopedAStatus isSupportedResult;
1063
1064 if (power_hal_service_.isPowerHalExtConnected()) {
1065 isSupported = power_hal_service_.isModeSupported(name_status_pair.first, severity);
1066 }
1067 if (isSupported)
1068 current_severity = severity;
1069 supported_powerhint_map_[name_status_pair.first][severity] = current_severity;
1070 }
1071 }
1072}
1073
1074void ThermalHelper::sendPowerExtHint(const Temperature_2_0 &t) {
TeYuan Wangd0979f82022-02-11 19:17:51 +08001075 ATRACE_CALL();
Kyle Lin7c8556b2020-08-07 17:02:55 +08001076 std::lock_guard<std::shared_mutex> lock(sensor_status_map_mutex_);
Kyle Lin7c8556b2020-08-07 17:02:55 +08001077 ThrottlingSeverity prev_hint_severity;
1078 prev_hint_severity = sensor_status_map_.at(t.name).prev_hint_severity;
1079 ThrottlingSeverity current_hint_severity = supported_powerhint_map_[t.name][t.throttlingStatus];
1080
1081 if (prev_hint_severity == current_hint_severity)
1082 return;
1083
1084 if (prev_hint_severity != ThrottlingSeverity::NONE) {
1085 power_hal_service_.setMode(t.name, prev_hint_severity, false);
1086 }
1087
1088 if (current_hint_severity != ThrottlingSeverity::NONE) {
1089 power_hal_service_.setMode(t.name, current_hint_severity, true);
1090 }
1091
1092 sensor_status_map_[t.name].prev_hint_severity = current_hint_severity;
1093}
Wei Wang086a2b22018-10-22 13:54:33 -07001094} // namespace implementation
1095} // namespace V2_0
1096} // namespace thermal
1097} // namespace hardware
1098} // namespace android