You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1180 lines
49 KiB
1180 lines
49 KiB
/*
|
|
* Copyright (C) 2022 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#define ATRACE_TAG (ATRACE_TAG_THERMAL | ATRACE_TAG_HAL)
|
|
|
|
#include "thermal-helper.h"
|
|
|
|
#include <android-base/file.h>
|
|
#include <android-base/logging.h>
|
|
#include <android-base/properties.h>
|
|
#include <android-base/stringprintf.h>
|
|
#include <android-base/strings.h>
|
|
#include <utils/Trace.h>
|
|
|
|
#include <iterator>
|
|
#include <set>
|
|
#include <sstream>
|
|
#include <thread>
|
|
#include <vector>
|
|
|
|
namespace aidl {
|
|
namespace android {
|
|
namespace hardware {
|
|
namespace thermal {
|
|
namespace implementation {
|
|
|
|
constexpr std::string_view kThermalSensorsRoot("/sys/devices/virtual/thermal");
|
|
constexpr std::string_view kSensorPrefix("thermal_zone");
|
|
constexpr std::string_view kCoolingDevicePrefix("cooling_device");
|
|
constexpr std::string_view kThermalNameFile("type");
|
|
constexpr std::string_view kSensorPolicyFile("policy");
|
|
constexpr std::string_view kSensorTempSuffix("temp");
|
|
constexpr std::string_view kSensorTripPointTempZeroFile("trip_point_0_temp");
|
|
constexpr std::string_view kSensorTripPointHystZeroFile("trip_point_0_hyst");
|
|
constexpr std::string_view kUserSpaceSuffix("user_space");
|
|
constexpr std::string_view kCoolingDeviceCurStateSuffix("cur_state");
|
|
constexpr std::string_view kCoolingDeviceMaxStateSuffix("max_state");
|
|
constexpr std::string_view kCoolingDeviceState2powerSuffix("state2power_table");
|
|
constexpr std::string_view kConfigProperty("vendor.thermal.config");
|
|
constexpr std::string_view kConfigDefaultFileName("thermal_info_config.json");
|
|
constexpr std::string_view kThermalGenlProperty("persist.vendor.enable.thermal.genl");
|
|
constexpr std::string_view kThermalDisabledProperty("vendor.disable.thermalhal.control");
|
|
|
|
namespace {
|
|
using ::android::base::StringPrintf;
|
|
|
|
std::unordered_map<std::string, std::string> parseThermalPathMap(std::string_view prefix) {
|
|
std::unordered_map<std::string, std::string> path_map;
|
|
std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(kThermalSensorsRoot.data()), closedir);
|
|
if (!dir) {
|
|
return path_map;
|
|
}
|
|
|
|
// std::filesystem is not available for vendor yet
|
|
// see discussion: aosp/894015
|
|
while (struct dirent *dp = readdir(dir.get())) {
|
|
if (dp->d_type != DT_DIR) {
|
|
continue;
|
|
}
|
|
|
|
if (!::android::base::StartsWith(dp->d_name, prefix.data())) {
|
|
continue;
|
|
}
|
|
|
|
std::string path = ::android::base::StringPrintf("%s/%s/%s", kThermalSensorsRoot.data(),
|
|
dp->d_name, kThermalNameFile.data());
|
|
std::string name;
|
|
if (!::android::base::ReadFileToString(path, &name)) {
|
|
PLOG(ERROR) << "Failed to read from " << path;
|
|
continue;
|
|
}
|
|
|
|
path_map.emplace(
|
|
::android::base::Trim(name),
|
|
::android::base::StringPrintf("%s/%s", kThermalSensorsRoot.data(), dp->d_name));
|
|
}
|
|
|
|
return path_map;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
/*
|
|
* Populate the sensor_name_to_file_map_ map by walking through the file tree,
|
|
* reading the type file and assigning the temp file path to the map. If we do
|
|
* not succeed, abort.
|
|
*/
|
|
ThermalHelper::ThermalHelper(const NotificationCallback &cb)
|
|
: thermal_watcher_(new ThermalWatcher(
|
|
std::bind(&ThermalHelper::thermalWatcherCallbackFunc, this, std::placeholders::_1))),
|
|
cb_(cb) {
|
|
const std::string config_path =
|
|
"/vendor/etc/" +
|
|
::android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data());
|
|
bool thermal_throttling_disabled =
|
|
::android::base::GetBoolProperty(kThermalDisabledProperty.data(), false);
|
|
bool ret = true;
|
|
Json::Value config;
|
|
if (!ParseThermalConfig(config_path, &config)) {
|
|
LOG(ERROR) << "Failed to read JSON config";
|
|
ret = false;
|
|
}
|
|
|
|
if (!ParseCoolingDevice(config, &cooling_device_info_map_)) {
|
|
LOG(ERROR) << "Failed to parse cooling device info config";
|
|
ret = false;
|
|
}
|
|
|
|
if (!ParseSensorInfo(config, &sensor_info_map_)) {
|
|
LOG(ERROR) << "Failed to parse sensor info config";
|
|
ret = false;
|
|
}
|
|
|
|
auto tz_map = parseThermalPathMap(kSensorPrefix.data());
|
|
if (!initializeSensorMap(tz_map)) {
|
|
LOG(ERROR) << "Failed to initialize sensor map";
|
|
ret = false;
|
|
}
|
|
|
|
auto cdev_map = parseThermalPathMap(kCoolingDevicePrefix.data());
|
|
if (!initializeCoolingDevices(cdev_map)) {
|
|
LOG(ERROR) << "Failed to initialize cooling device map";
|
|
ret = false;
|
|
}
|
|
|
|
if (!power_files_.registerPowerRailsToWatch(config)) {
|
|
LOG(ERROR) << "Failed to register power rails";
|
|
ret = false;
|
|
}
|
|
|
|
if (!thermal_stats_helper_.initializeStats(config, sensor_info_map_,
|
|
cooling_device_info_map_)) {
|
|
LOG(FATAL) << "Failed to initialize thermal stats";
|
|
}
|
|
|
|
for (auto const &name_status_pair : sensor_info_map_) {
|
|
sensor_status_map_[name_status_pair.first] = {
|
|
.severity = ThrottlingSeverity::NONE,
|
|
.prev_hot_severity = ThrottlingSeverity::NONE,
|
|
.prev_cold_severity = ThrottlingSeverity::NONE,
|
|
.prev_hint_severity = ThrottlingSeverity::NONE,
|
|
.last_update_time = boot_clock::time_point::min(),
|
|
.thermal_cached = {NAN, boot_clock::time_point::min()},
|
|
.emul_setting = nullptr,
|
|
};
|
|
|
|
if (name_status_pair.second.throttling_info != nullptr) {
|
|
if (!thermal_throttling_.registerThermalThrottling(
|
|
name_status_pair.first, name_status_pair.second.throttling_info,
|
|
cooling_device_info_map_)) {
|
|
LOG(ERROR) << name_status_pair.first << " failed to register thermal throttling";
|
|
ret = false;
|
|
break;
|
|
}
|
|
|
|
// Update cooling device max state
|
|
for (auto &binded_cdev_info_pair :
|
|
name_status_pair.second.throttling_info->binded_cdev_info_map) {
|
|
const auto &cdev_info = cooling_device_info_map_.at(binded_cdev_info_pair.first);
|
|
|
|
for (auto &cdev_ceiling : binded_cdev_info_pair.second.cdev_ceiling) {
|
|
if (cdev_ceiling > cdev_info.max_state) {
|
|
if (cdev_ceiling != std::numeric_limits<int>::max()) {
|
|
LOG(WARNING) << "Sensor " << name_status_pair.first << "'s "
|
|
<< binded_cdev_info_pair.first
|
|
<< " cdev_ceiling:" << cdev_ceiling
|
|
<< " is higher than max state:" << cdev_info.max_state;
|
|
}
|
|
cdev_ceiling = cdev_info.max_state;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Check the virtual sensor settings are valid
|
|
if (name_status_pair.second.virtual_sensor_info != nullptr) {
|
|
// Check if sub sensor setting is valid
|
|
for (size_t i = 0;
|
|
i < name_status_pair.second.virtual_sensor_info->linked_sensors.size(); i++) {
|
|
if (!isSubSensorValid(
|
|
name_status_pair.second.virtual_sensor_info->linked_sensors[i],
|
|
name_status_pair.second.virtual_sensor_info->linked_sensors_type[i])) {
|
|
LOG(ERROR) << name_status_pair.first << "'s link sensor "
|
|
<< name_status_pair.second.virtual_sensor_info->linked_sensors[i]
|
|
<< " is invalid";
|
|
ret = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check if the trigger sensor is valid
|
|
if (!name_status_pair.second.virtual_sensor_info->trigger_sensors.empty() &&
|
|
name_status_pair.second.is_watch) {
|
|
for (size_t i = 0;
|
|
i < name_status_pair.second.virtual_sensor_info->trigger_sensors.size(); i++) {
|
|
if (sensor_info_map_.count(
|
|
name_status_pair.second.virtual_sensor_info->trigger_sensors[i])) {
|
|
sensor_info_map_[name_status_pair.second.virtual_sensor_info
|
|
->trigger_sensors[i]]
|
|
.is_watch = true;
|
|
} else {
|
|
LOG(ERROR)
|
|
<< name_status_pair.first << "'s trigger sensor: "
|
|
<< name_status_pair.second.virtual_sensor_info->trigger_sensors[i]
|
|
<< " is invalid";
|
|
ret = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!connectToPowerHal()) {
|
|
LOG(ERROR) << "Fail to connect to Power Hal";
|
|
} else {
|
|
updateSupportedPowerHints();
|
|
}
|
|
|
|
if (thermal_throttling_disabled) {
|
|
if (ret) {
|
|
clearAllThrottling();
|
|
is_initialized_ = ret;
|
|
return;
|
|
} else {
|
|
sensor_info_map_.clear();
|
|
cooling_device_info_map_.clear();
|
|
return;
|
|
}
|
|
} else if (!ret) {
|
|
LOG(FATAL) << "ThermalHAL could not be initialized properly.";
|
|
}
|
|
is_initialized_ = ret;
|
|
|
|
const bool thermal_genl_enabled =
|
|
::android::base::GetBoolProperty(kThermalGenlProperty.data(), false);
|
|
|
|
std::set<std::string> monitored_sensors;
|
|
initializeTrip(tz_map, &monitored_sensors, thermal_genl_enabled);
|
|
|
|
if (thermal_genl_enabled) {
|
|
thermal_watcher_->registerFilesToWatchNl(monitored_sensors);
|
|
} else {
|
|
thermal_watcher_->registerFilesToWatch(monitored_sensors);
|
|
}
|
|
|
|
// Need start watching after status map initialized
|
|
is_initialized_ = thermal_watcher_->startWatchingDeviceFiles();
|
|
if (!is_initialized_) {
|
|
LOG(FATAL) << "ThermalHAL could not start watching thread properly.";
|
|
}
|
|
|
|
if (!connectToPowerHal()) {
|
|
LOG(ERROR) << "Fail to connect to Power Hal";
|
|
} else {
|
|
updateSupportedPowerHints();
|
|
}
|
|
}
|
|
|
|
bool getThermalZoneTypeById(int tz_id, std::string *type) {
|
|
std::string tz_type;
|
|
std::string path =
|
|
::android::base::StringPrintf("%s/%s%d/%s", kThermalSensorsRoot.data(),
|
|
kSensorPrefix.data(), tz_id, kThermalNameFile.data());
|
|
LOG(INFO) << "TZ Path: " << path;
|
|
if (!::android::base::ReadFileToString(path, &tz_type)) {
|
|
LOG(ERROR) << "Failed to read sensor: " << tz_type;
|
|
return false;
|
|
}
|
|
|
|
// Strip the newline.
|
|
*type = ::android::base::Trim(tz_type);
|
|
LOG(INFO) << "TZ type: " << *type;
|
|
return true;
|
|
}
|
|
|
|
bool ThermalHelper::emulTemp(std::string_view target_sensor, const float value) {
|
|
LOG(INFO) << "Set " << target_sensor.data() << " emul_temp "
|
|
<< "to " << value;
|
|
|
|
std::lock_guard<std::shared_mutex> _lock(sensor_status_map_mutex_);
|
|
// Check the target sensor is valid
|
|
if (!sensor_status_map_.count(target_sensor.data())) {
|
|
LOG(ERROR) << "Cannot find target emul sensor: " << target_sensor.data();
|
|
return false;
|
|
}
|
|
|
|
sensor_status_map_.at(target_sensor.data())
|
|
.emul_setting.reset(new EmulSetting{value, -1, true});
|
|
|
|
thermal_watcher_->wake();
|
|
return true;
|
|
}
|
|
|
|
bool ThermalHelper::emulSeverity(std::string_view target_sensor, const int severity) {
|
|
LOG(INFO) << "Set " << target_sensor.data() << " emul_severity "
|
|
<< "to " << severity;
|
|
|
|
std::lock_guard<std::shared_mutex> _lock(sensor_status_map_mutex_);
|
|
// Check the target sensor is valid
|
|
if (!sensor_status_map_.count(target_sensor.data())) {
|
|
LOG(ERROR) << "Cannot find target emul sensor: " << target_sensor.data();
|
|
return false;
|
|
}
|
|
// Check the emul severity is valid
|
|
if (severity > static_cast<int>(kThrottlingSeverityCount)) {
|
|
LOG(ERROR) << "Invalid emul severity value " << severity;
|
|
return false;
|
|
}
|
|
|
|
sensor_status_map_.at(target_sensor.data())
|
|
.emul_setting.reset(new EmulSetting{NAN, severity, true});
|
|
|
|
thermal_watcher_->wake();
|
|
return true;
|
|
}
|
|
|
|
bool ThermalHelper::emulClear(std::string_view target_sensor) {
|
|
LOG(INFO) << "Clear " << target_sensor.data() << " emulation settings";
|
|
|
|
std::lock_guard<std::shared_mutex> _lock(sensor_status_map_mutex_);
|
|
if (target_sensor == "all") {
|
|
for (auto &sensor_status : sensor_status_map_) {
|
|
if (sensor_status.second.emul_setting != nullptr) {
|
|
sensor_status.second.emul_setting.reset(new EmulSetting{NAN, -1, true});
|
|
}
|
|
}
|
|
} else if (sensor_status_map_.count(target_sensor.data()) &&
|
|
sensor_status_map_.at(target_sensor.data()).emul_setting != nullptr) {
|
|
sensor_status_map_.at(target_sensor.data())
|
|
.emul_setting.reset(new EmulSetting{NAN, -1, true});
|
|
} else {
|
|
LOG(ERROR) << "Cannot find target emul sensor: " << target_sensor.data();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ThermalHelper::readCoolingDevice(std::string_view cooling_device, CoolingDevice *out) const {
|
|
// Read the file. If the file can't be read temp will be empty string.
|
|
std::string data;
|
|
|
|
if (!cooling_devices_.readThermalFile(cooling_device, &data)) {
|
|
LOG(ERROR) << "readCoolingDevice: failed to read cooling_device: " << cooling_device;
|
|
return false;
|
|
}
|
|
|
|
const CdevInfo &cdev_info = cooling_device_info_map_.at(cooling_device.data());
|
|
const CoolingType &type = cdev_info.type;
|
|
|
|
out->type = type;
|
|
out->name = cooling_device.data();
|
|
out->value = std::stoi(data);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ThermalHelper::readTemperature(
|
|
std::string_view sensor_name, Temperature *out,
|
|
std::pair<ThrottlingSeverity, ThrottlingSeverity> *throttling_status,
|
|
const bool force_no_cache) {
|
|
// Return fail if the thermal sensor cannot be read.
|
|
float temp;
|
|
std::map<std::string, float> sensor_log_map;
|
|
auto &sensor_status = sensor_status_map_.at(sensor_name.data());
|
|
|
|
if (!readThermalSensor(sensor_name, &temp, force_no_cache, &sensor_log_map)) {
|
|
LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
|
|
return false;
|
|
}
|
|
|
|
const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
|
|
out->type = sensor_info.type;
|
|
out->name = sensor_name.data();
|
|
out->value = temp * sensor_info.multiplier;
|
|
|
|
std::pair<ThrottlingSeverity, ThrottlingSeverity> status =
|
|
std::make_pair(ThrottlingSeverity::NONE, ThrottlingSeverity::NONE);
|
|
// Only update status if the thermal sensor is being monitored
|
|
if (sensor_info.is_watch) {
|
|
ThrottlingSeverity prev_hot_severity, prev_cold_severity;
|
|
{
|
|
// reader lock, readTemperature will be called in Binder call and the watcher thread.
|
|
std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
|
|
prev_hot_severity = sensor_status.prev_hot_severity;
|
|
prev_cold_severity = sensor_status.prev_cold_severity;
|
|
}
|
|
status = getSeverityFromThresholds(sensor_info.hot_thresholds, sensor_info.cold_thresholds,
|
|
sensor_info.hot_hysteresis, sensor_info.cold_hysteresis,
|
|
prev_hot_severity, prev_cold_severity, out->value);
|
|
}
|
|
|
|
if (throttling_status) {
|
|
*throttling_status = status;
|
|
}
|
|
|
|
if (sensor_status.emul_setting != nullptr && sensor_status.emul_setting->emul_severity >= 0) {
|
|
std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
|
|
out->throttlingStatus =
|
|
static_cast<ThrottlingSeverity>(sensor_status.emul_setting->emul_severity);
|
|
} else {
|
|
out->throttlingStatus =
|
|
static_cast<size_t>(status.first) > static_cast<size_t>(status.second)
|
|
? status.first
|
|
: status.second;
|
|
}
|
|
if (sensor_info.is_watch) {
|
|
std::ostringstream sensor_log;
|
|
for (const auto &sensor_log_pair : sensor_log_map) {
|
|
sensor_log << sensor_log_pair.first << ":" << sensor_log_pair.second << " ";
|
|
}
|
|
// Update sensor temperature time in state
|
|
thermal_stats_helper_.updateSensorTempStatsBySeverity(sensor_name, out->throttlingStatus);
|
|
LOG(INFO) << sensor_name.data() << ":" << out->value << " raw data: " << sensor_log.str();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ThermalHelper::readTemperatureThreshold(std::string_view sensor_name,
|
|
TemperatureThreshold *out) const {
|
|
// Read the file. If the file can't be read temp will be empty string.
|
|
std::string temp;
|
|
std::string path;
|
|
|
|
if (!sensor_info_map_.count(sensor_name.data())) {
|
|
LOG(ERROR) << __func__ << ": sensor not found: " << sensor_name;
|
|
return false;
|
|
}
|
|
|
|
const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
|
|
|
|
out->type = sensor_info.type;
|
|
out->name = sensor_name.data();
|
|
out->hotThrottlingThresholds =
|
|
std::vector(sensor_info.hot_thresholds.begin(), sensor_info.hot_thresholds.end());
|
|
out->coldThrottlingThresholds =
|
|
std::vector(sensor_info.cold_thresholds.begin(), sensor_info.cold_thresholds.end());
|
|
return true;
|
|
}
|
|
|
|
void ThermalHelper::updateCoolingDevices(const std::vector<std::string> &updated_cdev) {
|
|
int max_state;
|
|
|
|
for (const auto &target_cdev : updated_cdev) {
|
|
if (thermal_throttling_.getCdevMaxRequest(target_cdev, &max_state)) {
|
|
if (cooling_devices_.writeCdevFile(target_cdev, std::to_string(max_state))) {
|
|
ATRACE_INT(target_cdev.c_str(), max_state);
|
|
LOG(INFO) << "Successfully update cdev " << target_cdev << " sysfs to "
|
|
<< max_state;
|
|
} else {
|
|
LOG(ERROR) << "Failed to update cdev " << target_cdev << " sysfs to " << max_state;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelper::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) const {
|
|
ThrottlingSeverity ret_hot = ThrottlingSeverity::NONE;
|
|
ThrottlingSeverity ret_hot_hysteresis = ThrottlingSeverity::NONE;
|
|
ThrottlingSeverity ret_cold = ThrottlingSeverity::NONE;
|
|
ThrottlingSeverity ret_cold_hysteresis = ThrottlingSeverity::NONE;
|
|
|
|
// Here we want to control the iteration from high to low, and ::ndk::enum_range doesn't support
|
|
// a reverse iterator yet.
|
|
for (size_t i = static_cast<size_t>(ThrottlingSeverity::SHUTDOWN);
|
|
i > static_cast<size_t>(ThrottlingSeverity::NONE); --i) {
|
|
if (!std::isnan(hot_thresholds[i]) && hot_thresholds[i] <= value &&
|
|
ret_hot == ThrottlingSeverity::NONE) {
|
|
ret_hot = static_cast<ThrottlingSeverity>(i);
|
|
}
|
|
if (!std::isnan(hot_thresholds[i]) && (hot_thresholds[i] - hot_hysteresis[i]) < value &&
|
|
ret_hot_hysteresis == ThrottlingSeverity::NONE) {
|
|
ret_hot_hysteresis = static_cast<ThrottlingSeverity>(i);
|
|
}
|
|
if (!std::isnan(cold_thresholds[i]) && cold_thresholds[i] >= value &&
|
|
ret_cold == ThrottlingSeverity::NONE) {
|
|
ret_cold = static_cast<ThrottlingSeverity>(i);
|
|
}
|
|
if (!std::isnan(cold_thresholds[i]) && (cold_thresholds[i] + cold_hysteresis[i]) > value &&
|
|
ret_cold_hysteresis == ThrottlingSeverity::NONE) {
|
|
ret_cold_hysteresis = static_cast<ThrottlingSeverity>(i);
|
|
}
|
|
}
|
|
if (static_cast<size_t>(ret_hot) < static_cast<size_t>(prev_hot_severity)) {
|
|
ret_hot = ret_hot_hysteresis;
|
|
}
|
|
if (static_cast<size_t>(ret_cold) < static_cast<size_t>(prev_cold_severity)) {
|
|
ret_cold = ret_cold_hysteresis;
|
|
}
|
|
|
|
return std::make_pair(ret_hot, ret_cold);
|
|
}
|
|
|
|
bool ThermalHelper::isSubSensorValid(std::string_view sensor_data,
|
|
const SensorFusionType sensor_fusion_type) {
|
|
switch (sensor_fusion_type) {
|
|
case SensorFusionType::SENSOR:
|
|
if (!sensor_info_map_.count(sensor_data.data())) {
|
|
LOG(ERROR) << "Cannot find " << sensor_data.data() << " from sensor info map";
|
|
return false;
|
|
}
|
|
break;
|
|
case SensorFusionType::ODPM:
|
|
if (!GetPowerStatusMap().count(sensor_data.data())) {
|
|
LOG(ERROR) << "Cannot find " << sensor_data.data() << " from power status map";
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void ThermalHelper::clearAllThrottling(void) {
|
|
// Clear the CDEV request
|
|
for (const auto &cdev_info_pair : cooling_device_info_map_) {
|
|
cooling_devices_.writeCdevFile(cdev_info_pair.first, "0");
|
|
}
|
|
|
|
for (auto &sensor_info_pair : sensor_info_map_) {
|
|
sensor_info_pair.second.is_watch = false;
|
|
sensor_info_pair.second.throttling_info.reset();
|
|
sensor_info_pair.second.hot_thresholds.fill(NAN);
|
|
sensor_info_pair.second.cold_thresholds.fill(NAN);
|
|
Temperature temp = {
|
|
.type = sensor_info_pair.second.type,
|
|
.name = sensor_info_pair.first,
|
|
.value = NAN,
|
|
.throttlingStatus = ThrottlingSeverity::NONE,
|
|
};
|
|
// Send callbacks with NONE severity
|
|
if (sensor_info_pair.second.send_cb && cb_) {
|
|
cb_(temp);
|
|
}
|
|
// Disable thermal power hints
|
|
if (sensor_info_pair.second.send_powerhint) {
|
|
for (const auto &severity : ::ndk::enum_range<ThrottlingSeverity>()) {
|
|
power_hal_service_.setMode(sensor_info_pair.first, severity, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ThermalHelper::initializeSensorMap(
|
|
const std::unordered_map<std::string, std::string> &path_map) {
|
|
for (const auto &sensor_info_pair : sensor_info_map_) {
|
|
std::string_view sensor_name = sensor_info_pair.first;
|
|
if (sensor_info_pair.second.virtual_sensor_info != nullptr) {
|
|
continue;
|
|
}
|
|
if (!path_map.count(sensor_name.data())) {
|
|
LOG(ERROR) << "Could not find " << sensor_name << " in sysfs";
|
|
return false;
|
|
}
|
|
|
|
std::string path;
|
|
if (sensor_info_pair.second.temp_path.empty()) {
|
|
path = ::android::base::StringPrintf("%s/%s", path_map.at(sensor_name.data()).c_str(),
|
|
kSensorTempSuffix.data());
|
|
} else {
|
|
path = sensor_info_pair.second.temp_path;
|
|
}
|
|
|
|
if (!thermal_sensors_.addThermalFile(sensor_name, path)) {
|
|
LOG(ERROR) << "Could not add " << sensor_name << "to sensors map";
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ThermalHelper::initializeCoolingDevices(
|
|
const std::unordered_map<std::string, std::string> &path_map) {
|
|
for (auto &cooling_device_info_pair : cooling_device_info_map_) {
|
|
std::string cooling_device_name = cooling_device_info_pair.first;
|
|
if (!path_map.count(cooling_device_name)) {
|
|
LOG(ERROR) << "Could not find " << cooling_device_name << " in sysfs";
|
|
return false;
|
|
}
|
|
// Add cooling device path for thermalHAL to get current state
|
|
std::string_view path = path_map.at(cooling_device_name);
|
|
std::string read_path;
|
|
if (!cooling_device_info_pair.second.read_path.empty()) {
|
|
read_path = cooling_device_info_pair.second.read_path.data();
|
|
} else {
|
|
read_path = ::android::base::StringPrintf("%s/%s", path.data(),
|
|
kCoolingDeviceCurStateSuffix.data());
|
|
}
|
|
if (!cooling_devices_.addThermalFile(cooling_device_name, read_path)) {
|
|
LOG(ERROR) << "Could not add " << cooling_device_name
|
|
<< " read path to cooling device map";
|
|
return false;
|
|
}
|
|
|
|
std::string state2power_path = ::android::base::StringPrintf(
|
|
"%s/%s", path.data(), kCoolingDeviceState2powerSuffix.data());
|
|
std::string state2power_str;
|
|
if (::android::base::ReadFileToString(state2power_path, &state2power_str)) {
|
|
LOG(INFO) << "Cooling device " << cooling_device_info_pair.first
|
|
<< " use state2power read from sysfs";
|
|
cooling_device_info_pair.second.state2power.clear();
|
|
|
|
std::stringstream power(state2power_str);
|
|
unsigned int power_number;
|
|
int i = 0;
|
|
while (power >> power_number) {
|
|
cooling_device_info_pair.second.state2power.push_back(
|
|
static_cast<float>(power_number));
|
|
LOG(INFO) << "Cooling device " << cooling_device_info_pair.first << " state:" << i
|
|
<< " power: " << power_number;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// Get max cooling device request state
|
|
std::string max_state;
|
|
std::string max_state_path = ::android::base::StringPrintf(
|
|
"%s/%s", path.data(), kCoolingDeviceMaxStateSuffix.data());
|
|
if (!::android::base::ReadFileToString(max_state_path, &max_state)) {
|
|
LOG(ERROR) << cooling_device_info_pair.first
|
|
<< " could not open max state file:" << max_state_path;
|
|
cooling_device_info_pair.second.max_state = std::numeric_limits<int>::max();
|
|
} else {
|
|
cooling_device_info_pair.second.max_state = std::stoi(::android::base::Trim(max_state));
|
|
LOG(INFO) << "Cooling device " << cooling_device_info_pair.first
|
|
<< " max state: " << cooling_device_info_pair.second.max_state
|
|
<< " state2power number: "
|
|
<< cooling_device_info_pair.second.state2power.size();
|
|
if (cooling_device_info_pair.second.state2power.size() > 0 &&
|
|
static_cast<int>(cooling_device_info_pair.second.state2power.size()) !=
|
|
(cooling_device_info_pair.second.max_state + 1)) {
|
|
LOG(ERROR) << "Invalid state2power number: "
|
|
<< cooling_device_info_pair.second.state2power.size()
|
|
<< ", number should be " << cooling_device_info_pair.second.max_state + 1
|
|
<< " (max_state + 1)";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Add cooling device path for thermalHAL to request state
|
|
cooling_device_name =
|
|
::android::base::StringPrintf("%s_%s", cooling_device_name.c_str(), "w");
|
|
std::string write_path;
|
|
if (!cooling_device_info_pair.second.write_path.empty()) {
|
|
write_path = cooling_device_info_pair.second.write_path.data();
|
|
} else {
|
|
write_path = ::android::base::StringPrintf("%s/%s", path.data(),
|
|
kCoolingDeviceCurStateSuffix.data());
|
|
}
|
|
|
|
if (!cooling_devices_.addThermalFile(cooling_device_name, write_path)) {
|
|
LOG(ERROR) << "Could not add " << cooling_device_name
|
|
<< " write path to cooling device map";
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void ThermalHelper::setMinTimeout(SensorInfo *sensor_info) {
|
|
sensor_info->polling_delay = kMinPollIntervalMs;
|
|
sensor_info->passive_delay = kMinPollIntervalMs;
|
|
}
|
|
|
|
void ThermalHelper::initializeTrip(const std::unordered_map<std::string, std::string> &path_map,
|
|
std::set<std::string> *monitored_sensors,
|
|
bool thermal_genl_enabled) {
|
|
for (auto &sensor_info : sensor_info_map_) {
|
|
if (!sensor_info.second.is_watch || (sensor_info.second.virtual_sensor_info != nullptr)) {
|
|
continue;
|
|
}
|
|
|
|
bool trip_update = false;
|
|
std::string_view sensor_name = sensor_info.first;
|
|
std::string_view tz_path = path_map.at(sensor_name.data());
|
|
std::string tz_policy;
|
|
std::string path =
|
|
::android::base::StringPrintf("%s/%s", (tz_path.data()), kSensorPolicyFile.data());
|
|
|
|
if (thermal_genl_enabled) {
|
|
trip_update = true;
|
|
} else {
|
|
// Check if thermal zone support uevent notify
|
|
if (!::android::base::ReadFileToString(path, &tz_policy)) {
|
|
LOG(ERROR) << sensor_name << " could not open tz policy file:" << path;
|
|
} else {
|
|
tz_policy = ::android::base::Trim(tz_policy);
|
|
if (tz_policy != kUserSpaceSuffix) {
|
|
LOG(ERROR) << sensor_name << " does not support uevent notify";
|
|
} else {
|
|
trip_update = true;
|
|
}
|
|
}
|
|
}
|
|
if (trip_update) {
|
|
// Update thermal zone trip point
|
|
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
|
|
if (!std::isnan(sensor_info.second.hot_thresholds[i]) &&
|
|
!std::isnan(sensor_info.second.hot_hysteresis[i])) {
|
|
// Update trip_point_0_temp threshold
|
|
std::string threshold = std::to_string(static_cast<int>(
|
|
sensor_info.second.hot_thresholds[i] / sensor_info.second.multiplier));
|
|
path = ::android::base::StringPrintf("%s/%s", (tz_path.data()),
|
|
kSensorTripPointTempZeroFile.data());
|
|
if (!::android::base::WriteStringToFile(threshold, path)) {
|
|
LOG(ERROR) << "fail to update " << sensor_name << " trip point: " << path
|
|
<< " to " << threshold;
|
|
trip_update = false;
|
|
break;
|
|
}
|
|
// Update trip_point_0_hyst threshold
|
|
threshold = std::to_string(static_cast<int>(
|
|
sensor_info.second.hot_hysteresis[i] / sensor_info.second.multiplier));
|
|
path = ::android::base::StringPrintf("%s/%s", (tz_path.data()),
|
|
kSensorTripPointHystZeroFile.data());
|
|
if (!::android::base::WriteStringToFile(threshold, path)) {
|
|
LOG(ERROR) << "fail to update " << sensor_name << "trip hyst" << threshold
|
|
<< path;
|
|
trip_update = false;
|
|
break;
|
|
}
|
|
break;
|
|
} else if (i == kThrottlingSeverityCount - 1) {
|
|
LOG(ERROR) << sensor_name << ":all thresholds are NAN";
|
|
trip_update = false;
|
|
break;
|
|
}
|
|
}
|
|
monitored_sensors->insert(sensor_info.first);
|
|
}
|
|
|
|
if (!trip_update) {
|
|
LOG(INFO) << "config Sensor: " << sensor_info.first
|
|
<< " to default polling interval: " << kMinPollIntervalMs.count();
|
|
setMinTimeout(&sensor_info.second);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ThermalHelper::fillCurrentTemperatures(bool filterType, bool filterCallback,
|
|
TemperatureType type,
|
|
std::vector<Temperature> *temperatures) {
|
|
std::vector<Temperature> ret;
|
|
for (const auto &name_info_pair : sensor_info_map_) {
|
|
Temperature temp;
|
|
if (name_info_pair.second.is_hidden) {
|
|
continue;
|
|
}
|
|
if (filterType && name_info_pair.second.type != type) {
|
|
continue;
|
|
}
|
|
if (filterCallback && !name_info_pair.second.send_cb) {
|
|
continue;
|
|
}
|
|
if (readTemperature(name_info_pair.first, &temp, nullptr, false)) {
|
|
ret.emplace_back(std::move(temp));
|
|
} else {
|
|
LOG(ERROR) << __func__
|
|
<< ": error reading temperature for sensor: " << name_info_pair.first;
|
|
}
|
|
}
|
|
*temperatures = ret;
|
|
return ret.size() > 0;
|
|
}
|
|
|
|
bool ThermalHelper::fillTemperatureThresholds(bool filterType, TemperatureType type,
|
|
std::vector<TemperatureThreshold> *thresholds) const {
|
|
std::vector<TemperatureThreshold> ret;
|
|
for (const auto &name_info_pair : sensor_info_map_) {
|
|
TemperatureThreshold temp;
|
|
if (name_info_pair.second.is_hidden) {
|
|
continue;
|
|
}
|
|
if (filterType && name_info_pair.second.type != type) {
|
|
continue;
|
|
}
|
|
if (readTemperatureThreshold(name_info_pair.first, &temp)) {
|
|
ret.emplace_back(std::move(temp));
|
|
} else {
|
|
LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
|
|
<< name_info_pair.first;
|
|
return false;
|
|
}
|
|
}
|
|
*thresholds = ret;
|
|
return ret.size() > 0;
|
|
}
|
|
|
|
bool ThermalHelper::fillCurrentCoolingDevices(bool filterType, CoolingType type,
|
|
std::vector<CoolingDevice> *cooling_devices) const {
|
|
std::vector<CoolingDevice> ret;
|
|
for (const auto &name_info_pair : cooling_device_info_map_) {
|
|
CoolingDevice value;
|
|
if (filterType && name_info_pair.second.type != type) {
|
|
continue;
|
|
}
|
|
if (readCoolingDevice(name_info_pair.first, &value)) {
|
|
ret.emplace_back(std::move(value));
|
|
} else {
|
|
LOG(ERROR) << __func__ << ": error reading cooling device: " << name_info_pair.first;
|
|
return false;
|
|
}
|
|
}
|
|
*cooling_devices = ret;
|
|
return ret.size() > 0;
|
|
}
|
|
|
|
bool ThermalHelper::readDataByType(std::string_view sensor_data, float *reading_value,
|
|
const SensorFusionType type, const bool force_no_cache,
|
|
std::map<std::string, float> *sensor_log_map) {
|
|
switch (type) {
|
|
case SensorFusionType::SENSOR:
|
|
if (!readThermalSensor(sensor_data.data(), reading_value, force_no_cache,
|
|
sensor_log_map)) {
|
|
LOG(ERROR) << "Failed to get " << sensor_data.data() << " data";
|
|
return false;
|
|
}
|
|
break;
|
|
case SensorFusionType::ODPM:
|
|
*reading_value = GetPowerStatusMap().at(sensor_data.data()).last_updated_avg_power;
|
|
if (std::isnan(*reading_value)) {
|
|
LOG(INFO) << "Power data " << sensor_data.data() << " is under collecting";
|
|
return false;
|
|
}
|
|
(*sensor_log_map)[sensor_data.data()] = *reading_value;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ThermalHelper::readThermalSensor(std::string_view sensor_name, float *temp,
|
|
const bool force_no_cache,
|
|
std::map<std::string, float> *sensor_log_map) {
|
|
float temp_val = 0.0;
|
|
std::string file_reading;
|
|
boot_clock::time_point now = boot_clock::now();
|
|
|
|
ATRACE_NAME(StringPrintf("ThermalHelper::readThermalSensor - %s", sensor_name.data()).c_str());
|
|
if (!(sensor_info_map_.count(sensor_name.data()) &&
|
|
sensor_status_map_.count(sensor_name.data()))) {
|
|
return false;
|
|
}
|
|
|
|
const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
|
|
auto &sensor_status = sensor_status_map_.at(sensor_name.data());
|
|
|
|
{
|
|
std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
|
|
if (sensor_status.emul_setting != nullptr &&
|
|
!isnan(sensor_status.emul_setting->emul_temp)) {
|
|
*temp = sensor_status.emul_setting->emul_temp;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Check if thermal data need to be read from cache
|
|
if (!force_no_cache &&
|
|
(sensor_status.thermal_cached.timestamp != boot_clock::time_point::min()) &&
|
|
(std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
now - sensor_status.thermal_cached.timestamp) < sensor_info.time_resolution) &&
|
|
!isnan(sensor_status.thermal_cached.temp)) {
|
|
*temp = sensor_status.thermal_cached.temp;
|
|
(*sensor_log_map)[sensor_name.data()] = *temp;
|
|
ATRACE_INT((sensor_name.data() + std::string("-cached")).c_str(), static_cast<int>(*temp));
|
|
return true;
|
|
}
|
|
|
|
// Reading thermal sensor according to it's composition
|
|
if (sensor_info.virtual_sensor_info == nullptr) {
|
|
if (!thermal_sensors_.readThermalFile(sensor_name.data(), &file_reading)) {
|
|
return false;
|
|
}
|
|
|
|
if (file_reading.empty()) {
|
|
LOG(ERROR) << "failed to read sensor: " << sensor_name;
|
|
return false;
|
|
}
|
|
*temp = std::stof(::android::base::Trim(file_reading));
|
|
} else {
|
|
for (size_t i = 0; i < sensor_info.virtual_sensor_info->linked_sensors.size(); i++) {
|
|
float sensor_reading = 0.0;
|
|
// Get the sensor reading data
|
|
if (!readDataByType(sensor_info.virtual_sensor_info->linked_sensors[i], &sensor_reading,
|
|
sensor_info.virtual_sensor_info->linked_sensors_type[i],
|
|
force_no_cache, sensor_log_map)) {
|
|
LOG(ERROR) << "Failed to read " << sensor_name.data() << "'s linked sensor "
|
|
<< sensor_info.virtual_sensor_info->linked_sensors[i];
|
|
}
|
|
if (std::isnan(sensor_info.virtual_sensor_info->coefficients[i])) {
|
|
return false;
|
|
}
|
|
float coefficient = sensor_info.virtual_sensor_info->coefficients[i];
|
|
switch (sensor_info.virtual_sensor_info->formula) {
|
|
case FormulaOption::COUNT_THRESHOLD:
|
|
if ((coefficient < 0 && sensor_reading < -coefficient) ||
|
|
(coefficient >= 0 && sensor_reading >= coefficient))
|
|
temp_val += 1;
|
|
break;
|
|
case FormulaOption::WEIGHTED_AVG:
|
|
temp_val += sensor_reading * coefficient;
|
|
break;
|
|
case FormulaOption::MAXIMUM:
|
|
if (i == 0)
|
|
temp_val = std::numeric_limits<float>::lowest();
|
|
if (sensor_reading * coefficient > temp_val)
|
|
temp_val = sensor_reading * coefficient;
|
|
break;
|
|
case FormulaOption::MINIMUM:
|
|
if (i == 0)
|
|
temp_val = std::numeric_limits<float>::max();
|
|
if (sensor_reading * coefficient < temp_val)
|
|
temp_val = sensor_reading * coefficient;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
*temp = (temp_val + sensor_info.virtual_sensor_info->offset);
|
|
}
|
|
(*sensor_log_map)[sensor_name.data()] = *temp;
|
|
ATRACE_INT(sensor_name.data(), static_cast<int>(*temp));
|
|
|
|
{
|
|
std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
|
|
sensor_status.thermal_cached.temp = *temp;
|
|
sensor_status.thermal_cached.timestamp = now;
|
|
}
|
|
auto real_temp = (*temp) * sensor_info.multiplier;
|
|
thermal_stats_helper_.updateSensorTempStatsByThreshold(sensor_name, real_temp);
|
|
return true;
|
|
}
|
|
|
|
// This is called in the different thread context and will update sensor_status
|
|
// uevent_sensors is the set of sensors which trigger uevent from thermal core driver.
|
|
std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc(
|
|
const std::set<std::string> &uevent_sensors) {
|
|
std::vector<Temperature> temps;
|
|
std::vector<std::string> cooling_devices_to_update;
|
|
boot_clock::time_point now = boot_clock::now();
|
|
auto min_sleep_ms = std::chrono::milliseconds::max();
|
|
bool power_data_is_updated = false;
|
|
|
|
ATRACE_CALL();
|
|
for (auto &name_status_pair : sensor_status_map_) {
|
|
bool force_update = false;
|
|
bool force_no_cache = false;
|
|
Temperature temp;
|
|
TemperatureThreshold threshold;
|
|
SensorStatus &sensor_status = name_status_pair.second;
|
|
const SensorInfo &sensor_info = sensor_info_map_.at(name_status_pair.first);
|
|
|
|
// Only handle the sensors in allow list
|
|
if (!sensor_info.is_watch) {
|
|
continue;
|
|
}
|
|
|
|
ATRACE_NAME(StringPrintf("ThermalHelper::thermalWatcherCallbackFunc - %s",
|
|
name_status_pair.first.data())
|
|
.c_str());
|
|
|
|
std::chrono::milliseconds time_elapsed_ms = std::chrono::milliseconds::zero();
|
|
auto sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
|
|
? sensor_info.passive_delay
|
|
: sensor_info.polling_delay;
|
|
|
|
if (sensor_info.virtual_sensor_info != nullptr &&
|
|
!sensor_info.virtual_sensor_info->trigger_sensors.empty()) {
|
|
for (size_t i = 0; i < sensor_info.virtual_sensor_info->trigger_sensors.size(); i++) {
|
|
const auto &trigger_sensor_status =
|
|
sensor_status_map_.at(sensor_info.virtual_sensor_info->trigger_sensors[i]);
|
|
if (trigger_sensor_status.severity != ThrottlingSeverity::NONE) {
|
|
sleep_ms = sensor_info.passive_delay;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// Check if the sensor need to be updated
|
|
if (sensor_status.last_update_time == boot_clock::time_point::min()) {
|
|
force_update = true;
|
|
} else {
|
|
time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
now - sensor_status.last_update_time);
|
|
if (uevent_sensors.size()) {
|
|
if (sensor_info.virtual_sensor_info != nullptr) {
|
|
for (size_t i = 0; i < sensor_info.virtual_sensor_info->trigger_sensors.size();
|
|
i++) {
|
|
if (uevent_sensors.find(
|
|
sensor_info.virtual_sensor_info->trigger_sensors[i]) !=
|
|
uevent_sensors.end()) {
|
|
force_update = true;
|
|
break;
|
|
}
|
|
}
|
|
} else if (uevent_sensors.find(name_status_pair.first) != uevent_sensors.end()) {
|
|
force_update = true;
|
|
force_no_cache = true;
|
|
}
|
|
} else if (time_elapsed_ms > sleep_ms) {
|
|
force_update = true;
|
|
}
|
|
}
|
|
{
|
|
std::lock_guard<std::shared_mutex> _lock(sensor_status_map_mutex_);
|
|
if (sensor_status.emul_setting != nullptr &&
|
|
sensor_status.emul_setting->pending_update) {
|
|
force_update = true;
|
|
sensor_status.emul_setting->pending_update = false;
|
|
LOG(INFO) << "Update " << name_status_pair.first.data()
|
|
<< " right away with emul setting";
|
|
}
|
|
}
|
|
LOG(VERBOSE) << "sensor " << name_status_pair.first
|
|
<< ": time_elapsed=" << time_elapsed_ms.count()
|
|
<< ", sleep_ms=" << sleep_ms.count() << ", force_update = " << force_update
|
|
<< ", force_no_cache = " << force_no_cache;
|
|
|
|
if (!force_update) {
|
|
auto timeout_remaining = sleep_ms - time_elapsed_ms;
|
|
if (min_sleep_ms > timeout_remaining) {
|
|
min_sleep_ms = timeout_remaining;
|
|
}
|
|
LOG(VERBOSE) << "sensor " << name_status_pair.first
|
|
<< ": timeout_remaining=" << timeout_remaining.count();
|
|
continue;
|
|
}
|
|
|
|
std::pair<ThrottlingSeverity, ThrottlingSeverity> throttling_status;
|
|
if (!readTemperature(name_status_pair.first, &temp, &throttling_status, force_no_cache)) {
|
|
LOG(ERROR) << __func__
|
|
<< ": error reading temperature for sensor: " << name_status_pair.first;
|
|
continue;
|
|
}
|
|
if (!readTemperatureThreshold(name_status_pair.first, &threshold)) {
|
|
LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
|
|
<< name_status_pair.first;
|
|
continue;
|
|
}
|
|
|
|
{
|
|
// writer lock
|
|
std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
|
|
if (throttling_status.first != sensor_status.prev_hot_severity) {
|
|
sensor_status.prev_hot_severity = throttling_status.first;
|
|
}
|
|
if (throttling_status.second != sensor_status.prev_cold_severity) {
|
|
sensor_status.prev_cold_severity = throttling_status.second;
|
|
}
|
|
if (temp.throttlingStatus != sensor_status.severity) {
|
|
temps.push_back(temp);
|
|
sensor_status.severity = temp.throttlingStatus;
|
|
sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
|
|
? sensor_info.passive_delay
|
|
: sensor_info.polling_delay;
|
|
}
|
|
}
|
|
|
|
if (!power_data_is_updated) {
|
|
power_files_.refreshPowerStatus();
|
|
power_data_is_updated = true;
|
|
}
|
|
|
|
if (sensor_status.severity == ThrottlingSeverity::NONE) {
|
|
thermal_throttling_.clearThrottlingData(name_status_pair.first, sensor_info);
|
|
} else {
|
|
// update thermal throttling request
|
|
thermal_throttling_.thermalThrottlingUpdate(
|
|
temp, sensor_info, sensor_status.severity, time_elapsed_ms,
|
|
power_files_.GetPowerStatusMap(), cooling_device_info_map_);
|
|
}
|
|
|
|
thermal_throttling_.computeCoolingDevicesRequest(
|
|
name_status_pair.first, sensor_info, sensor_status.severity,
|
|
&cooling_devices_to_update, &thermal_stats_helper_);
|
|
if (min_sleep_ms > sleep_ms) {
|
|
min_sleep_ms = sleep_ms;
|
|
}
|
|
|
|
LOG(VERBOSE) << "Sensor " << name_status_pair.first << ": sleep_ms=" << sleep_ms.count()
|
|
<< ", min_sleep_ms voting result=" << min_sleep_ms.count();
|
|
sensor_status.last_update_time = now;
|
|
}
|
|
|
|
if (!cooling_devices_to_update.empty()) {
|
|
updateCoolingDevices(cooling_devices_to_update);
|
|
}
|
|
|
|
if (!temps.empty()) {
|
|
for (const auto &t : temps) {
|
|
if (sensor_info_map_.at(t.name).send_cb && cb_) {
|
|
cb_(t);
|
|
}
|
|
|
|
if (sensor_info_map_.at(t.name).send_powerhint && isAidlPowerHalExist()) {
|
|
sendPowerExtHint(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
int count_failed_reporting = thermal_stats_helper_.reportStats();
|
|
if (count_failed_reporting != 0) {
|
|
LOG(ERROR) << "Failed to report " << count_failed_reporting << " thermal stats";
|
|
}
|
|
|
|
return min_sleep_ms;
|
|
}
|
|
|
|
bool ThermalHelper::connectToPowerHal() {
|
|
return power_hal_service_.connect();
|
|
}
|
|
|
|
void ThermalHelper::updateSupportedPowerHints() {
|
|
for (auto const &name_status_pair : sensor_info_map_) {
|
|
if (!(name_status_pair.second.send_powerhint)) {
|
|
continue;
|
|
}
|
|
ThrottlingSeverity current_severity = ThrottlingSeverity::NONE;
|
|
for (const auto &severity : ::ndk::enum_range<ThrottlingSeverity>()) {
|
|
if (severity == ThrottlingSeverity::NONE) {
|
|
supported_powerhint_map_[name_status_pair.first][ThrottlingSeverity::NONE] =
|
|
ThrottlingSeverity::NONE;
|
|
continue;
|
|
}
|
|
|
|
bool isSupported = false;
|
|
ndk::ScopedAStatus isSupportedResult;
|
|
|
|
if (power_hal_service_.isPowerHalExtConnected()) {
|
|
isSupported = power_hal_service_.isModeSupported(name_status_pair.first, severity);
|
|
}
|
|
if (isSupported)
|
|
current_severity = severity;
|
|
supported_powerhint_map_[name_status_pair.first][severity] = current_severity;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ThermalHelper::sendPowerExtHint(const Temperature &t) {
|
|
ATRACE_CALL();
|
|
std::lock_guard<std::shared_mutex> lock(sensor_status_map_mutex_);
|
|
ThrottlingSeverity prev_hint_severity;
|
|
prev_hint_severity = sensor_status_map_.at(t.name).prev_hint_severity;
|
|
ThrottlingSeverity current_hint_severity = supported_powerhint_map_[t.name][t.throttlingStatus];
|
|
|
|
if (prev_hint_severity == current_hint_severity)
|
|
return;
|
|
|
|
if (prev_hint_severity != ThrottlingSeverity::NONE) {
|
|
power_hal_service_.setMode(t.name, prev_hint_severity, false);
|
|
}
|
|
|
|
if (current_hint_severity != ThrottlingSeverity::NONE) {
|
|
power_hal_service_.setMode(t.name, current_hint_severity, true);
|
|
}
|
|
|
|
sensor_status_map_[t.name].prev_hint_severity = current_hint_severity;
|
|
}
|
|
} // namespace implementation
|
|
} // namespace thermal
|
|
} // namespace hardware
|
|
} // namespace android
|
|
} // namespace aidl
|
|
|