blob: 163f0fd0f49a27fc973f711e96ee2cb37e5fbef4 [file] [log] [blame]
/*
* Copyright (C) 2017 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 <cctype>
#include <cerrno>
#include <cinttypes>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include "thermal-helper.h"
namespace android {
namespace hardware {
namespace thermal {
namespace V1_1 {
namespace implementation {
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;
/**
* Initialization constants based on platform
*
* @return true on success or false on error.
*/
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;
} else if (hardware == "taimen") {
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;
}
} else {
LOG(ERROR) << "Unsupported hardware: " << hardware;
return false;
}
return true;
}
/**
* 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;
}
}
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;
}
ssize_t fillCpuUsages(hidl_vec<CpuUsage> *cpuUsages) {
int vals, cpu_num, online;
ssize_t read;
uint64_t user, nice, system, idle, active, total;
char *line = NULL;
size_t len = 0;
size_t size = 0;
char file_name[PATH_MAX];
FILE *file;
FILE *cpu_file;
if (cpuUsages == NULL || cpuUsages->size() < kCpuNum ) {
LOG(ERROR) << "fillCpuUsages: incorrect buffer";
return -EINVAL;
}
file = fopen(kCpuUsageFile, "r");
if (file == NULL) {
PLOG(ERROR) << "fillCpuUsages: failed to open file (" << kCpuUsageFile << ")";
return -errno;
}
while ((read = getline(&line, &len, file)) != -1) {
// Skip non "cpu[0-9]" lines.
if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) {
free(line);
line = NULL;
len = 0;
continue;
}
vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user,
&nice, &system, &idle);
free(line);
line = NULL;
len = 0;
if (vals != 5 || size == kCpuNum) {
if (vals != 5) {
PLOG(ERROR) << "fillCpuUsages: failed to read CPU information from file ("
<< kCpuUsageFile << ")";
} else {
PLOG(ERROR) << "fillCpuUsages: file has incorrect format ("
<< kCpuUsageFile << ")";
}
fclose(file);
return errno ? -errno : -EIO;
}
active = user + nice + system;
total = active + idle;
// Read online CPU information.
snprintf(file_name, PATH_MAX, kCpuOnlineFileFormat, cpu_num);
cpu_file = fopen(file_name, "r");
online = 0;
if (cpu_file == NULL) {
PLOG(ERROR) << "fillCpuUsages: failed to open file (" << file_name << ")";
fclose(file);
return -errno;
}
if (1 != fscanf(cpu_file, "%d", &online)) {
PLOG(ERROR) << "fillCpuUsages: failed to read CPU online information from file ("
<< file_name << ")";
fclose(file);
fclose(cpu_file);
return errno ? -errno : -EIO;
}
fclose(cpu_file);
(*cpuUsages)[size].name = kCpuLabel[size];
(*cpuUsages)[size].active = active;
(*cpuUsages)[size].total = total;
(*cpuUsages)[size].isOnline = static_cast<bool>(online);
LOG(DEBUG) << "fillCpuUsages: "<< kCpuLabel[size] << ": "
<< active << " " << total << " " << online;
size++;
}
fclose(file);
if (size != kCpuNum) {
PLOG(ERROR) << "fillCpuUsages: file has incorrect format (" << kCpuUsageFile << ")";
return -EIO;
}
return kCpuNum;
}
std::string getTargetSkinSensorType() {
return gSkinSensorType;
}
} // namespace implementation
} // namespace V1_1
} // namespace thermal
} // namespace hardware
} // namespace android