Home | History | Annotate | Download | only in thermal
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <cctype>
     18 #include <cerrno>
     19 #include <cinttypes>
     20 #include <cmath>
     21 #include <cstdlib>
     22 #include <cstring>
     23 
     24 #include <android-base/logging.h>
     25 #include <android-base/properties.h>
     26 #include <android-base/stringprintf.h>
     27 
     28 #include "thermal-helper.h"
     29 
     30 namespace android {
     31 namespace hardware {
     32 namespace thermal {
     33 namespace V1_1 {
     34 namespace implementation {
     35 
     36 using ::android::hardware::thermal::V1_0::TemperatureType;
     37 
     38 static unsigned int gSkinSensorNum;
     39 static std::string gSkinSensorType;
     40 static unsigned int gTsensOffset;
     41 static unsigned int gSkinThrottlingThreshold;
     42 static unsigned int gSkinShutdownThreshold;
     43 static unsigned int gVrThrottledBelowMin;
     44 
     45 /**
     46  * Initialization constants based on platform
     47  *
     48  * @return true on success or false on error.
     49  */
     50 bool initThermal() {
     51     std::string hardware = android::base::GetProperty("ro.hardware", "");
     52     if (hardware == "walleye") {
     53         LOG(ERROR) << "Initialization on Walleye";
     54         gSkinSensorNum = kWalleyeSkinSensorNum;
     55         gSkinSensorType = kWalleyeSkinSensorType;
     56         gTsensOffset = kWalleyeTsensOffset;
     57         gSkinThrottlingThreshold = kWalleyeSkinThrottlingThreshold;
     58         gSkinShutdownThreshold = kWalleyeSkinShutdownThreshold;
     59         gVrThrottledBelowMin = kWalleyeVrThrottledBelowMin;
     60     } else if (hardware == "taimen") {
     61         std::string rev = android::base::GetProperty("ro.revision", "");
     62         if (rev == "rev_a" || rev == "rev_b") {
     63             LOG(ERROR) << "Initialization on Taimen pre revision C";
     64             gSkinSensorNum = kTaimenRabSkinSensorNum;
     65             gSkinSensorType = kTaimenRabSkinSensorType;
     66             gTsensOffset = kTaimenRabTsensOffset;
     67             gSkinThrottlingThreshold = kTaimenRabSkinThrottlingThreshold;
     68             gSkinShutdownThreshold = kTaimenRabSkinShutdownThreshold;
     69             gVrThrottledBelowMin = kTaimenRabVrThrottledBelowMin;
     70         } else {
     71             LOG(ERROR) << "Initialization on Taimen revision C and later";
     72             gSkinSensorNum = kTaimenRcSkinSensorNum;
     73             gSkinSensorType = kTaimenRcSkinSensorType;
     74             gTsensOffset = kTaimenRcTsensOffset;
     75             gSkinThrottlingThreshold = kTaimenRcSkinThrottlingThreshold;
     76             gSkinShutdownThreshold = kTaimenRcSkinShutdownThreshold;
     77             gVrThrottledBelowMin = kTaimenRcVrThrottledBelowMin;
     78         }
     79     } else {
     80         LOG(ERROR) << "Unsupported hardware: " << hardware;
     81         return false;
     82     }
     83     return true;
     84 }
     85 
     86 /**
     87  * Reads device temperature.
     88  *
     89  * @param sensor_num Number of sensor file with temperature.
     90  * @param type Device temperature type.
     91  * @param name Device temperature name.
     92  * @param mult Multiplier used to translate temperature to Celsius.
     93  * @param throttling_threshold Throttling threshold for the temperature.
     94  * @param shutdown_threshold Shutdown threshold for the temperature.
     95  * @param out Pointer to temperature_t structure that will be filled with current
     96  *     values.
     97  *
     98  * @return 0 on success or negative value -errno on error.
     99  */
    100 static ssize_t readTemperature(int sensor_num, TemperatureType type, const char *name, float mult,
    101                                 float throttling_threshold, float shutdown_threshold,
    102                                 float vr_throttling_threshold, Temperature *out) {
    103     FILE *file;
    104     char file_name[PATH_MAX];
    105     float temp;
    106 
    107     sprintf(file_name, kTemperatureFileFormat, sensor_num);
    108     file = fopen(file_name, "r");
    109     if (file == NULL) {
    110         PLOG(ERROR) << "readTemperature: failed to open file (" << file_name << ")";
    111         return -errno;
    112     }
    113     if (1 != fscanf(file, "%f", &temp)) {
    114         fclose(file);
    115         PLOG(ERROR) << "readTemperature: failed to read a float";
    116         return errno ? -errno : -EIO;
    117     }
    118 
    119     fclose(file);
    120 
    121     (*out).type = type;
    122     (*out).name = name;
    123     (*out).currentValue = temp * mult;
    124     (*out).throttlingThreshold = throttling_threshold;
    125     (*out).shutdownThreshold = shutdown_threshold;
    126     (*out).vrThrottlingThreshold = vr_throttling_threshold;
    127 
    128     LOG(DEBUG) << android::base::StringPrintf(
    129         "readTemperature: %d, %d, %s, %g, %g, %g, %g",
    130         sensor_num, type, name, temp * mult, throttling_threshold,
    131         shutdown_threshold, vr_throttling_threshold);
    132 
    133     return 0;
    134 }
    135 
    136 static ssize_t getCpuTemperatures(hidl_vec<Temperature> *temperatures) {
    137     size_t cpu;
    138 
    139     for (cpu = 0; cpu < kCpuNum; cpu++) {
    140         if (cpu >= temperatures->size()) {
    141             break;
    142         }
    143         // temperature in decidegrees Celsius.
    144         ssize_t result = readTemperature(kCpuTsensOffset[cpu] + gTsensOffset, TemperatureType::CPU, kCpuLabel[cpu],
    145                                           0.1, kCpuThrottlingThreshold, kCpuShutdownThreshold, kCpuThrottlingThreshold,
    146                                           &(*temperatures)[cpu]);
    147         if (result != 0) {
    148             return result;
    149         }
    150     }
    151     return cpu;
    152 }
    153 
    154 ssize_t fillTemperatures(hidl_vec<Temperature> *temperatures) {
    155     ssize_t result = 0;
    156     size_t current_index = 0;
    157 
    158     if (temperatures == NULL || temperatures->size() < kTemperatureNum) {
    159         LOG(ERROR) << "fillTemperatures: incorrect buffer";
    160         return -EINVAL;
    161     }
    162 
    163     result = getCpuTemperatures(temperatures);
    164     if (result < 0) {
    165         return result;
    166     }
    167     current_index += result;
    168 
    169     // GPU temperature.
    170     if (current_index < temperatures->size()) {
    171         // temperature in decidegrees Celsius.
    172         result = readTemperature(gTsensOffset + kGpuTsensOffset, TemperatureType::GPU, kGpuLabel, 0.1,
    173                                   NAN, NAN, NAN, &(*temperatures)[current_index]);
    174         if (result < 0) {
    175             return result;
    176         }
    177         current_index++;
    178     }
    179 
    180     // Battery temperature.
    181     if (current_index < temperatures->size()) {
    182         // battery: temperature in millidegrees Celsius.
    183         result = readTemperature(kBatterySensorNum, TemperatureType::BATTERY, kBatteryLabel,
    184                                   0.001, NAN, kBatteryShutdownThreshold, NAN,
    185                                   &(*temperatures)[current_index]);
    186         if (result < 0) {
    187             return result;
    188         }
    189         current_index++;
    190     }
    191 
    192     // Skin temperature.
    193     if (current_index < temperatures->size()) {
    194         // temperature in Celsius.
    195         result = readTemperature(gSkinSensorNum, TemperatureType::SKIN, kSkinLabel, 1.,
    196                                   gSkinThrottlingThreshold, gSkinShutdownThreshold, gVrThrottledBelowMin,
    197                                   &(*temperatures)[current_index]);
    198         if (result < 0) {
    199             return result;
    200         }
    201         current_index++;
    202     }
    203     return kTemperatureNum;
    204 }
    205 
    206 ssize_t fillCpuUsages(hidl_vec<CpuUsage> *cpuUsages) {
    207     int vals, cpu_num, online;
    208     ssize_t read;
    209     uint64_t user, nice, system, idle, active, total;
    210     char *line = NULL;
    211     size_t len = 0;
    212     size_t size = 0;
    213     char file_name[PATH_MAX];
    214     FILE *file;
    215     FILE *cpu_file;
    216 
    217     if (cpuUsages == NULL || cpuUsages->size() < kCpuNum ) {
    218         LOG(ERROR) << "fillCpuUsages: incorrect buffer";
    219         return -EINVAL;
    220     }
    221 
    222     file = fopen(kCpuUsageFile, "r");
    223     if (file == NULL) {
    224         PLOG(ERROR) << "fillCpuUsages: failed to open file (" << kCpuUsageFile << ")";
    225         return -errno;
    226     }
    227 
    228     while ((read = getline(&line, &len, file)) != -1) {
    229         // Skip non "cpu[0-9]" lines.
    230         if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) {
    231             free(line);
    232             line = NULL;
    233             len = 0;
    234             continue;
    235         }
    236 
    237         vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user,
    238                 &nice, &system, &idle);
    239 
    240         free(line);
    241         line = NULL;
    242         len = 0;
    243 
    244         if (vals != 5 || size == kCpuNum) {
    245             if (vals != 5) {
    246                 PLOG(ERROR) << "fillCpuUsages: failed to read CPU information from file ("
    247                             << kCpuUsageFile << ")";
    248             } else {
    249                 PLOG(ERROR) << "fillCpuUsages: file has incorrect format ("
    250                             << kCpuUsageFile << ")";
    251             }
    252             fclose(file);
    253             return errno ? -errno : -EIO;
    254         }
    255 
    256         active = user + nice + system;
    257         total = active + idle;
    258 
    259         // Read online CPU information.
    260         snprintf(file_name, PATH_MAX, kCpuOnlineFileFormat, cpu_num);
    261         cpu_file = fopen(file_name, "r");
    262         online = 0;
    263         if (cpu_file == NULL) {
    264             PLOG(ERROR) << "fillCpuUsages: failed to open file (" << file_name << ")";
    265             fclose(file);
    266             return -errno;
    267         }
    268         if (1 != fscanf(cpu_file, "%d", &online)) {
    269             PLOG(ERROR) << "fillCpuUsages: failed to read CPU online information from file ("
    270                         << file_name << ")";
    271             fclose(file);
    272             fclose(cpu_file);
    273             return errno ? -errno : -EIO;
    274         }
    275         fclose(cpu_file);
    276 
    277         (*cpuUsages)[size].name = kCpuLabel[size];
    278         (*cpuUsages)[size].active = active;
    279         (*cpuUsages)[size].total = total;
    280         (*cpuUsages)[size].isOnline = static_cast<bool>(online);
    281 
    282         LOG(DEBUG) << "fillCpuUsages: "<< kCpuLabel[size] << ": "
    283                    << active << " " << total << " " <<  online;
    284         size++;
    285     }
    286     fclose(file);
    287 
    288     if (size != kCpuNum) {
    289         PLOG(ERROR) << "fillCpuUsages: file has incorrect format (" << kCpuUsageFile << ")";
    290         return -EIO;
    291     }
    292     return kCpuNum;
    293 }
    294 
    295 std::string getTargetSkinSensorType() {
    296     return gSkinSensorType;
    297 }
    298 
    299 }  // namespace implementation
    300 }  // namespace V1_1
    301 }  // namespace thermal
    302 }  // namespace hardware
    303 }  // namespace android
    304