Merge "Allow thermalHAL on Wahoo to look up thermistors by name." into pi-dev

This commit is contained in:
TreeHugger Robot
2018-03-28 23:21:56 +00:00
committed by Android (Google) Code Review
7 changed files with 295 additions and 163 deletions

View File

@@ -5,6 +5,7 @@ cc_library {
vendor: true,
relative_install_path: "hw",
srcs: [
"sensors.cpp",
"Thermal.cpp",
"thermal-helper.cpp",
],

View File

@@ -55,6 +55,8 @@ Return<void> Thermal::getTemperatures(getTemperatures_cb _hidl_cb) {
hidl_vec<Temperature> temperatures;
temperatures.resize(kTemperatureNum);
LOG(INFO) << "ThermalHAL enabled: " << enabled;
if (!enabled) {
status.code = ThermalStatusCode::FAILURE;
status.debugMessage = "Unsupported hardware";
@@ -62,10 +64,9 @@ Return<void> Thermal::getTemperatures(getTemperatures_cb _hidl_cb) {
return Void();
}
ssize_t ret = fillTemperatures(&temperatures);
if (ret < 0) {
if (fillTemperatures(&temperatures) != kTemperatureNum) {
status.code = ThermalStatusCode::FAILURE;
status.debugMessage = strerror(-ret);
status.debugMessage = "Error reading thermal sensors.";
}
_hidl_cb(status, temperatures);

View File

@@ -54,7 +54,6 @@ struct Thermal : public IThermal {
// Methods from ::android::hardware::thermal::V1_1::IThermal follow.
Return<void> registerThermalCallback(
const sp<IThermalCallback>& callback) override;
private:
bool enabled;
};

100
thermal/sensors.cpp Normal file
View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2018 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.
*/
#include <algorithm>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include "sensors.h"
namespace android {
namespace hardware {
namespace thermal {
namespace V1_1 {
namespace implementation {
std::string Sensors::getSensorPath(const std::string& sensor_name) {
if (sensor_name_to_data_map_.find(sensor_name) !=
sensor_name_to_data_map_.end()) {
return std::get<0>(sensor_name_to_data_map_.at(sensor_name));
}
return "";
}
bool Sensors::addSensor(
const std::string& sensor_name, const std::string& path,
const float throttling_threshold, const float shutdown_threshold,
const float vr_threshold, const TemperatureType& type) {
return sensor_name_to_data_map_.emplace(
sensor_name, std::make_tuple(
path, throttling_threshold, shutdown_threshold,
vr_threshold, type)).second;
}
bool Sensors::readSensorFile(
const std::string& sensor_name, std::string* data,
std::string* file_path) const {
std::string sensor_reading;
if (sensor_name_to_data_map_.find(sensor_name) ==
sensor_name_to_data_map_.end()) {
*data = "";
*file_path = "";
return false;
}
android::base::ReadFileToString(
std::get<0>(sensor_name_to_data_map_.at(sensor_name)), &sensor_reading);
// Strip the newline.
*data = ::android::base::Trim(sensor_reading);
*file_path = std::get<0>(sensor_name_to_data_map_.at(sensor_name));
return true;
}
bool Sensors::readTemperature(
const std::string& sensor_name, const float mult,
Temperature* out) const {
if (sensor_name_to_data_map_.find(sensor_name) ==
sensor_name_to_data_map_.end()) {
return false;
}
std::string sensor_reading;
std::string path;
readSensorFile(sensor_name, &sensor_reading, &path);
auto sensor = sensor_name_to_data_map_.at(sensor_name);
out->name = sensor_name;
out->currentValue = std::stoi(sensor_reading) * mult;
out->throttlingThreshold = std::get<1>(sensor);
out->shutdownThreshold = std::get<2>(sensor);
out->vrThrottlingThreshold = std::get<3>(sensor);
out->type = std::get<4>(sensor);
LOG(DEBUG) << android::base::StringPrintf(
"readTemperature: %s, %d, %s, %g, %g, %g, %g",
path.c_str(), out->type, out->name.c_str(), out->currentValue,
out->throttlingThreshold, out->shutdownThreshold,
out->vrThrottlingThreshold);
return true;
}
} // namespace implementation
} // namespace V1_1
} // namespace thermal
} // namespace hardware
} // namespace android

76
thermal/sensors.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2018 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.
*/
#ifndef __SENSORS_H__
#define __SENSORS_H__
#include <string>
#include <tuple>
#include <unordered_map>
#include <android/hardware/thermal/1.1/IThermal.h>
namespace android {
namespace hardware {
namespace thermal {
namespace V1_1 {
namespace implementation {
using ::android::hardware::thermal::V1_0::Temperature;
using ::android::hardware::thermal::V1_0::TemperatureType;
class Sensors {
public:
Sensors() = default;
~Sensors() = default;
Sensors(const Sensors&) = delete;
void operator=(const Sensors&) = delete;
std::string getSensorPath(const std::string& sensor_name);
// Returns true if add was successful, false otherwise.
bool addSensor(
const std::string& sensor_name, const std::string& path,
const float throttling_threshold, const float shutdown_threshold,
const float vr_threshold, const TemperatureType& type);
// If sensor is not found in the sensor names to path map, this will set
// data and file path to empty and return false. If the sensor is found,
// this function will fill in data and file_path accordingly then return
// true.
bool readSensorFile(
const std::string& sensor_name, std::string* data,
std::string* file_path) const;
bool readTemperature(
const std::string& sensor_name, const float mult,
Temperature* out) const;
size_t getNumSensors() const { return sensor_name_to_data_map_.size(); }
private:
// A map containing sensor names along with its thermal zone number, its
// thresholds, and its type. The tuple is formatted as such:
// <path, throttling threshold, shutdown threshold, vr threshold, type>
std::unordered_map<std::string, std::tuple<
std::string, float, float, float, TemperatureType>>
sensor_name_to_data_map_;
};
} // namespace implementation
} // namespace V1_1
} // namespace thermal
} // namespace hardware
} // namespace android
#endif // __SENSORS_H__

View File

@@ -20,11 +20,17 @@
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <tuple>
#include <unordered_map>
#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include "sensors.h"
#include "thermal-helper.h"
namespace android {
@@ -33,14 +39,102 @@ namespace thermal {
namespace V1_1 {
namespace implementation {
constexpr const char kThermalSensorsRoot[] = "/sys/class/thermal";
constexpr char kThermalZoneDirSuffix[] = "thermal_zone";
constexpr char kSensorTypeFileSuffix[] = "type";
constexpr char kTemperatureFileSuffix[] = "temp";
// This is a golden set of thermal sensor names, their types, and their
// multiplier. Used when we read in sensor values. The tuple value stored is
// formatted as such:
// <temperature type, multiplier value for reading temp>
const std::unordered_map<std::string, std::tuple<TemperatureType, float>>
kValidThermalSensorsMap = {
{"tsens_tz_sensor1", {TemperatureType::CPU, 0.1}}, // CPU0
{"tsens_tz_sensor2", {TemperatureType::CPU, 0.1}}, // CPU1
{"tsens_tz_sensor4", {TemperatureType::CPU, 0.1}}, // CPU2
{"tsens_tz_sensor3", {TemperatureType::CPU, 0.1}}, // CPU3
{"tsens_tz_sensor7", {TemperatureType::CPU, 0.1}}, // CPU4
{"tsens_tz_sensor8", {TemperatureType::CPU, 0.1}}, // CPU5
{"tsens_tz_sensor9", {TemperatureType::CPU, 0.1}}, // CPU6
{"tsens_tz_sensor10", {TemperatureType::CPU, 0.1}}, // CPU7
// GPU thermal sensor.
{"tsens_tz_sensor13", {TemperatureType::GPU, 0.1}},
// Battery thermal sensor.
{"battery", {TemperatureType::BATTERY, 0.001}},
// Skin thermal sensors. We use back_therm for walleye. For taimen we use
// bd_therm and bd_therm2.
{"back_therm", {TemperatureType::SKIN, 1.}},
{"bd_therm", {TemperatureType::SKIN, 1.}},
{"bd_therm2", {TemperatureType::SKIN, 1.}},
// USBC thermal sensor.
{"usb_port_temp", {TemperatureType::UNKNOWN, 0.1}},
};
namespace {
using ::android::hardware::thermal::V1_0::TemperatureType;
static unsigned int gSkinSensorNum;
static std::string gSkinSensorType;
static unsigned int gTsensOffset;
static unsigned int gSkinThrottlingThreshold;
static unsigned int gSkinShutdownThreshold;
static unsigned int gVrThrottledBelowMin;
Sensors gSensors;
// A map containing hardcoded thresholds per sensor type. Its not const
// because initThermal() will modify the skin sensor thresholds depending on the
// hardware type. The tuple is formatted as follows:
// <throttling threshold, shutdown threshold, vr threshold>
std::unordered_map<TemperatureType, std::tuple<float, float, float>>
gSensorTypeToThresholdsMap = {
{TemperatureType::CPU, {kCpuThrottlingThreshold, kCpuShutdownThreshold,
kCpuThrottlingThreshold}},
{TemperatureType::GPU, {NAN, NAN, NAN}},
{TemperatureType::BATTERY, {NAN, kBatteryShutdownThreshold, NAN}},
{TemperatureType::SKIN, {NAN, NAN, NAN}},
{TemperatureType::UNKNOWN, {NAN, NAN, NAN}}
};
bool initializeSensors() {
auto thermal_zone_dir = std::unique_ptr<DIR, int (*)(DIR*)>(
opendir(kThermalSensorsRoot), closedir);
struct dirent* dp;
size_t num_thermal_zones = 0;
while ((dp = readdir(thermal_zone_dir.get())) != nullptr) {
std::string dir_name(dp->d_name);
if (dir_name.find(kThermalZoneDirSuffix) != std::string::npos) {
++num_thermal_zones;
}
}
for (size_t sensor_zone_num = 0; sensor_zone_num < num_thermal_zones;
++sensor_zone_num) {
std::string path = android::base::StringPrintf("%s/%s%zu",
kThermalSensorsRoot,
kThermalZoneDirSuffix,
sensor_zone_num);
std::string sensor_name;
if (android::base::ReadFileToString(
path + "/" + kSensorTypeFileSuffix, &sensor_name)) {
sensor_name = android::base::Trim(sensor_name);
if (kValidThermalSensorsMap.find(sensor_name) !=
kValidThermalSensorsMap.end()) {
TemperatureType type = std::get<0>(
kValidThermalSensorsMap.at(sensor_name));
auto thresholds = gSensorTypeToThresholdsMap.at(type);
if (!gSensors.addSensor(
sensor_name, path + "/" + kTemperatureFileSuffix,
std::get<0>(thresholds), std::get<1>(thresholds),
std::get<2>(thresholds), type)) {
LOG(ERROR) << "Could not add " << sensor_name
<< "to sensors map";
}
}
}
}
return (gSensors.getNumSensors() == kTemperatureNum);
}
} // namespace
/**
* Initialization constants based on platform
@@ -51,9 +145,6 @@ bool initThermal() {
std::string hardware = android::base::GetProperty("ro.hardware", "");
if (hardware == "walleye") {
LOG(ERROR) << "Initialization on Walleye";
gSkinSensorNum = kWalleyeSkinSensorNum;
gSkinSensorType = kWalleyeSkinSensorType;
gTsensOffset = kWalleyeTsensOffset;
gSkinThrottlingThreshold = kWalleyeSkinThrottlingThreshold;
gSkinShutdownThreshold = kWalleyeSkinShutdownThreshold;
gVrThrottledBelowMin = kWalleyeVrThrottledBelowMin;
@@ -61,17 +152,11 @@ bool initThermal() {
std::string rev = android::base::GetProperty("ro.revision", "");
if (rev == "rev_a" || rev == "rev_b") {
LOG(ERROR) << "Initialization on Taimen pre revision C";
gSkinSensorNum = kTaimenRabSkinSensorNum;
gSkinSensorType = kTaimenRabSkinSensorType;
gTsensOffset = kTaimenRabTsensOffset;
gSkinThrottlingThreshold = kTaimenRabSkinThrottlingThreshold;
gSkinShutdownThreshold = kTaimenRabSkinShutdownThreshold;
gVrThrottledBelowMin = kTaimenRabVrThrottledBelowMin;
} else {
LOG(ERROR) << "Initialization on Taimen revision C and later";
gSkinSensorNum = kTaimenRcSkinSensorNum;
gSkinSensorType = kTaimenRcSkinSensorType;
gTsensOffset = kTaimenRcTsensOffset;
gSkinThrottlingThreshold = kTaimenRcSkinThrottlingThreshold;
gSkinShutdownThreshold = kTaimenRcSkinShutdownThreshold;
gVrThrottledBelowMin = kTaimenRcVrThrottledBelowMin;
@@ -80,139 +165,25 @@ bool initThermal() {
LOG(ERROR) << "Unsupported hardware: " << hardware;
return false;
}
return true;
gSensorTypeToThresholdsMap[TemperatureType::SKIN] =
std::make_tuple(gSkinThrottlingThreshold, gSkinShutdownThreshold,
gVrThrottledBelowMin);
return initializeSensors();
}
/**
* Reads device temperature.
*
* @param sensor_num Number of sensor file with temperature.
* @param type Device temperature type.
* @param name Device temperature name.
* @param mult Multiplier used to translate temperature to Celsius.
* @param throttling_threshold Throttling threshold for the temperature.
* @param shutdown_threshold Shutdown threshold for the temperature.
* @param out Pointer to temperature_t structure that will be filled with current
* values.
*
* @return 0 on success or negative value -errno on error.
*/
static ssize_t readTemperature(int sensor_num, TemperatureType type, const char *name, float mult,
float throttling_threshold, float shutdown_threshold,
float vr_throttling_threshold, Temperature *out) {
FILE *file;
char file_name[PATH_MAX];
float temp;
sprintf(file_name, kTemperatureFileFormat, sensor_num);
file = fopen(file_name, "r");
if (file == NULL) {
PLOG(ERROR) << "readTemperature: failed to open file (" << file_name << ")";
return -errno;
}
if (1 != fscanf(file, "%f", &temp)) {
fclose(file);
PLOG(ERROR) << "readTemperature: failed to read a float";
return errno ? -errno : -EIO;
}
fclose(file);
(*out).type = type;
(*out).name = name;
(*out).currentValue = temp * mult;
(*out).throttlingThreshold = throttling_threshold;
(*out).shutdownThreshold = shutdown_threshold;
(*out).vrThrottlingThreshold = vr_throttling_threshold;
LOG(DEBUG) << android::base::StringPrintf(
"readTemperature: %d, %d, %s, %g, %g, %g, %g",
sensor_num, type, name, temp * mult, throttling_threshold,
shutdown_threshold, vr_throttling_threshold);
return 0;
}
static ssize_t getCpuTemperatures(hidl_vec<Temperature> *temperatures) {
size_t cpu;
for (cpu = 0; cpu < kCpuNum; cpu++) {
if (cpu >= temperatures->size()) {
break;
}
// temperature in decidegrees Celsius.
ssize_t result = readTemperature(kCpuTsensOffset[cpu] + gTsensOffset, TemperatureType::CPU, kCpuLabel[cpu],
0.1, kCpuThrottlingThreshold, kCpuShutdownThreshold, kCpuThrottlingThreshold,
&(*temperatures)[cpu]);
if (result != 0) {
return result;
ssize_t fillTemperatures(hidl_vec<Temperature>* temperatures) {
temperatures->resize(gSensors.getNumSensors());
ssize_t current_index = 0;
for (const auto& name_type_mult_pair : kValidThermalSensorsMap) {
Temperature temp;
if (gSensors.readTemperature(name_type_mult_pair.first,
std::get<1>(name_type_mult_pair.second),
&temp)) {
(*temperatures)[current_index] = temp;
++current_index;
}
}
return cpu;
}
ssize_t fillTemperatures(hidl_vec<Temperature> *temperatures) {
ssize_t result = 0;
size_t current_index = 0;
if (temperatures == NULL || temperatures->size() < kTemperatureNum) {
LOG(ERROR) << "fillTemperatures: incorrect buffer";
return -EINVAL;
}
result = getCpuTemperatures(temperatures);
if (result < 0) {
return result;
}
current_index += result;
// GPU temperature.
if (current_index < temperatures->size()) {
// temperature in decidegrees Celsius.
result = readTemperature(gTsensOffset + kGpuTsensOffset, TemperatureType::GPU, kGpuLabel, 0.1,
NAN, NAN, NAN, &(*temperatures)[current_index]);
if (result < 0) {
return result;
}
current_index++;
}
// Battery temperature.
if (current_index < temperatures->size()) {
// battery: temperature in millidegrees Celsius.
result = readTemperature(kBatterySensorNum, TemperatureType::BATTERY, kBatteryLabel,
0.001, NAN, kBatteryShutdownThreshold, NAN,
&(*temperatures)[current_index]);
if (result < 0) {
return result;
}
current_index++;
}
// Skin temperature.
if (current_index < temperatures->size()) {
// temperature in Celsius.
result = readTemperature(gSkinSensorNum, TemperatureType::SKIN, kSkinLabel, 1.,
gSkinThrottlingThreshold, gSkinShutdownThreshold, gVrThrottledBelowMin,
&(*temperatures)[current_index]);
if (result < 0) {
return result;
}
current_index++;
}
// USB-C temperature.
if (current_index < temperatures->size()) {
// temperature in Celsius.
result = readTemperature(
kUsbcSensorNum, TemperatureType::UNKNOWN, kUsbcLabel, 0.1, NAN, NAN,
NAN, &(*temperatures)[current_index]);
if (result < 0) {
return result;
}
current_index++;
}
return kTemperatureNum;
return current_index;
}
ssize_t fillCpuUsages(hidl_vec<CpuUsage> *cpuUsages) {

View File

@@ -40,45 +40,29 @@ namespace implementation {
using ::android::hardware::thermal::V1_0::CpuUsage;
using ::android::hardware::thermal::V1_0::Temperature;
using ::android::hardware::thermal::V1_0::TemperatureType;
constexpr const char *kCpuUsageFile = "/proc/stat";
constexpr const char *kTemperatureFileFormat = "/sys/class/thermal/thermal_zone%d/temp";
constexpr const char *kCpuOnlineFileFormat = "/sys/devices/system/cpu/cpu%d/online";
// thermal-engine.conf
constexpr unsigned int kWalleyeSkinSensorNum = 14;
constexpr auto kWalleyeSkinSensorType = "back_therm";
constexpr unsigned int kWalleyeTsensOffset = 16;
constexpr unsigned int kWalleyeSkinThrottlingThreshold = 40;
constexpr unsigned int kWalleyeSkinShutdownThreshold = 56;
constexpr unsigned int kWalleyeVrThrottledBelowMin = 52;
constexpr unsigned int kTaimenRabSkinSensorNum = 13;
constexpr auto kTaimenRabSkinSensorType = "bd_therm";
constexpr unsigned int kTaimenRabTsensOffset = 14;
constexpr unsigned int kTaimenRabSkinThrottlingThreshold = 49;
constexpr unsigned int kTaimenRabSkinShutdownThreshold = 66;
constexpr unsigned int kTaimenRabVrThrottledBelowMin = 62;
constexpr unsigned int kTaimenRcSkinSensorNum = 13;
constexpr auto kTaimenRcSkinSensorType = "bd_therm2";
constexpr unsigned int kTaimenRcTsensOffset = 14;
constexpr unsigned int kTaimenRcSkinThrottlingThreshold = 38;
constexpr unsigned int kTaimenRcSkinShutdownThreshold = 54;
constexpr unsigned int kTaimenRcVrThrottledBelowMin = 50;
constexpr unsigned int kUsbcSensorNum = 6;
constexpr unsigned int kBatterySensorNum = 5;
// The gpu thermal sensor is tsens_tz_sensor13.
constexpr unsigned int kGpuTsensOffset = 11;
constexpr unsigned int kCpuNum = 8;
constexpr const char *kGpuLabel = "GPU";
constexpr const char *kBatteryLabel = "battery";
constexpr const char *kSkinLabel = "skin";
constexpr const char *kUsbcLabel = "usbc";
constexpr const char *kCpuLabel[kCpuNum] = {"CPU0", "CPU1", "CPU2", "CPU3", "CPU4", "CPU5", "CPU6", "CPU7"};
constexpr int kCpuTsensOffset[kCpuNum] = {1, 2, 4, 3, 5, 6, 7, 8};
constexpr const char *kCpuLabel[kCpuNum] = {
"CPU0", "CPU1", "CPU2", "CPU3", "CPU4", "CPU5", "CPU6", "CPU7"};
// Sum of kCpuNum + 4 for GPU, BATTERY, SKIN, and USB-C.
constexpr unsigned int kTemperatureNum = 4 + kCpuNum;