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 #include <tuple>
     24 #include <unordered_map>
     25 #include <vector>
     26 
     27 #include <android-base/file.h>
     28 #include <android-base/logging.h>
     29 #include <android-base/properties.h>
     30 #include <android-base/strings.h>
     31 #include <android-base/stringprintf.h>
     32 
     33 #include "sensors.h"
     34 #include "thermal-helper.h"
     35 
     36 namespace android {
     37 namespace hardware {
     38 namespace thermal {
     39 namespace V1_1 {
     40 namespace implementation {
     41 
     42 constexpr const char kThermalSensorsRoot[] = "/sys/class/thermal";
     43 constexpr char kThermalZoneDirSuffix[] = "thermal_zone";
     44 constexpr char kSensorTypeFileSuffix[] = "type";
     45 constexpr char kTemperatureFileSuffix[] = "temp";
     46 // This is a golden set of thermal sensor names, their types, and their
     47 // multiplier. Used when we read in sensor values. The tuple value stored is
     48 // formatted as such:
     49 // <temperature type, multiplier value for reading temp>
     50 const std::unordered_map<std::string, std::tuple<TemperatureType, float>>
     51 kValidThermalSensorsMap = {
     52     {"tsens_tz_sensor1", {TemperatureType::CPU, 0.1}},   // CPU0
     53     {"tsens_tz_sensor2", {TemperatureType::CPU, 0.1}},   // CPU1
     54     {"tsens_tz_sensor4", {TemperatureType::CPU, 0.1}},   // CPU2
     55     {"tsens_tz_sensor3", {TemperatureType::CPU, 0.1}},   // CPU3
     56     {"tsens_tz_sensor7", {TemperatureType::CPU, 0.1}},   // CPU4
     57     {"tsens_tz_sensor8", {TemperatureType::CPU, 0.1}},   // CPU5
     58     {"tsens_tz_sensor9", {TemperatureType::CPU, 0.1}},   // CPU6
     59     {"tsens_tz_sensor10", {TemperatureType::CPU, 0.1}},  // CPU7
     60     // GPU thermal sensor.
     61     {"tsens_tz_sensor13", {TemperatureType::GPU, 0.1}},
     62     // Battery thermal sensor.
     63     {"battery", {TemperatureType::BATTERY, 0.001}},
     64     // Skin thermal sensors. We use back_therm for walleye. For taimen we use
     65     // bd_therm and bd_therm2.
     66     {"back_therm", {TemperatureType::SKIN, 1.}},
     67     {"bd_therm", {TemperatureType::SKIN, 1.}},
     68     {"bd_therm2", {TemperatureType::SKIN, 1.}},
     69     // USBC thermal sensor.
     70     {"usb_port_temp", {TemperatureType::UNKNOWN, 0.1}},
     71 };
     72 
     73 namespace {
     74 
     75 using ::android::hardware::thermal::V1_0::TemperatureType;
     76 
     77 static std::string gSkinSensorType;
     78 static unsigned int gSkinThrottlingThreshold;
     79 static unsigned int gSkinShutdownThreshold;
     80 static unsigned int gVrThrottledBelowMin;
     81 Sensors gSensors;
     82 
     83 // A map containing hardcoded thresholds per sensor type.  Its not const
     84 // because initThermal() will modify the skin sensor thresholds depending on the
     85 // hardware type. The tuple is formatted as follows:
     86 // <throttling threshold, shutdown threshold, vr threshold>
     87 std::unordered_map<TemperatureType, std::tuple<float, float, float>>
     88 gSensorTypeToThresholdsMap = {
     89     {TemperatureType::CPU, {kCpuThrottlingThreshold, kCpuShutdownThreshold,
     90                              kCpuThrottlingThreshold}},
     91     {TemperatureType::GPU, {NAN, NAN, NAN}},
     92     {TemperatureType::BATTERY, {NAN, kBatteryShutdownThreshold, NAN}},
     93     {TemperatureType::SKIN, {NAN, NAN, NAN}},
     94     {TemperatureType::UNKNOWN, {NAN, NAN, NAN}}
     95 };
     96 
     97 bool initializeSensors() {
     98     auto thermal_zone_dir = std::unique_ptr<DIR, int (*)(DIR*)>(
     99         opendir(kThermalSensorsRoot), closedir);
    100     struct dirent* dp;
    101     size_t num_thermal_zones = 0;
    102     while ((dp = readdir(thermal_zone_dir.get())) != nullptr) {
    103         std::string dir_name(dp->d_name);
    104         if (dir_name.find(kThermalZoneDirSuffix) != std::string::npos) {
    105             ++num_thermal_zones;
    106         }
    107     }
    108 
    109     for (size_t sensor_zone_num = 0; sensor_zone_num < num_thermal_zones;
    110             ++sensor_zone_num) {
    111         std::string path = android::base::StringPrintf("%s/%s%zu",
    112                                                        kThermalSensorsRoot,
    113                                                        kThermalZoneDirSuffix,
    114                                                        sensor_zone_num);
    115         std::string sensor_name;
    116         if (android::base::ReadFileToString(
    117                 path + "/" + kSensorTypeFileSuffix, &sensor_name)) {
    118             sensor_name = android::base::Trim(sensor_name);
    119             if (kValidThermalSensorsMap.find(sensor_name) !=
    120                 kValidThermalSensorsMap.end()) {
    121                   TemperatureType type = std::get<0>(
    122                       kValidThermalSensorsMap.at(sensor_name));
    123                   auto thresholds = gSensorTypeToThresholdsMap.at(type);
    124                   if (!gSensors.addSensor(
    125                           sensor_name, path + "/" + kTemperatureFileSuffix,
    126                           std::get<0>(thresholds), std::get<1>(thresholds),
    127                           std::get<2>(thresholds), type)) {
    128                         LOG(ERROR) << "Could not add " << sensor_name
    129                                    << "to sensors map";
    130                   }
    131             }
    132         }
    133     }
    134     return (gSensors.getNumSensors() == kTemperatureNum);
    135 }
    136 
    137 }  // namespace
    138 
    139 /**
    140  * Initialization constants based on platform
    141  *
    142  * @return true on success or false on error.
    143  */
    144 bool initThermal() {
    145     std::string hardware = android::base::GetProperty("ro.hardware", "");
    146     if (hardware == "walleye") {
    147         LOG(ERROR) << "Initialization on Walleye";
    148         gSkinThrottlingThreshold = kWalleyeSkinThrottlingThreshold;
    149         gSkinShutdownThreshold = kWalleyeSkinShutdownThreshold;
    150         gVrThrottledBelowMin = kWalleyeVrThrottledBelowMin;
    151     } else if (hardware == "taimen") {
    152         std::string rev = android::base::GetProperty("ro.revision", "");
    153         if (rev == "rev_a" || rev == "rev_b") {
    154             LOG(ERROR) << "Initialization on Taimen pre revision C";
    155             gSkinThrottlingThreshold = kTaimenRabSkinThrottlingThreshold;
    156             gSkinShutdownThreshold = kTaimenRabSkinShutdownThreshold;
    157             gVrThrottledBelowMin = kTaimenRabVrThrottledBelowMin;
    158         } else {
    159             LOG(ERROR) << "Initialization on Taimen revision C and later";
    160             gSkinThrottlingThreshold = kTaimenRcSkinThrottlingThreshold;
    161             gSkinShutdownThreshold = kTaimenRcSkinShutdownThreshold;
    162             gVrThrottledBelowMin = kTaimenRcVrThrottledBelowMin;
    163         }
    164     } else {
    165         LOG(ERROR) << "Unsupported hardware: " << hardware;
    166         return false;
    167     }
    168     gSensorTypeToThresholdsMap[TemperatureType::SKIN] =
    169         std::make_tuple(gSkinThrottlingThreshold, gSkinShutdownThreshold,
    170                         gVrThrottledBelowMin);
    171     return initializeSensors();
    172 }
    173 
    174 ssize_t fillTemperatures(hidl_vec<Temperature>* temperatures) {
    175     temperatures->resize(gSensors.getNumSensors());
    176     ssize_t current_index = 0;
    177     for (const auto& name_type_mult_pair : kValidThermalSensorsMap) {
    178         Temperature temp;
    179         if (gSensors.readTemperature(name_type_mult_pair.first,
    180                                      std::get<1>(name_type_mult_pair.second),
    181                                      &temp)) {
    182             (*temperatures)[current_index] = temp;
    183             ++current_index;
    184         }
    185     }
    186     return current_index;
    187 }
    188 
    189 ssize_t fillCpuUsages(hidl_vec<CpuUsage> *cpuUsages) {
    190     int vals, cpu_num, online;
    191     ssize_t read;
    192     uint64_t user, nice, system, idle, active, total;
    193     char *line = NULL;
    194     size_t len = 0;
    195     size_t size = 0;
    196     char file_name[PATH_MAX];
    197     FILE *file;
    198     FILE *cpu_file;
    199 
    200     if (cpuUsages == NULL || cpuUsages->size() < kCpuNum ) {
    201         LOG(ERROR) << "fillCpuUsages: incorrect buffer";
    202         return -EINVAL;
    203     }
    204 
    205     file = fopen(kCpuUsageFile, "r");
    206     if (file == NULL) {
    207         PLOG(ERROR) << "fillCpuUsages: failed to open file (" << kCpuUsageFile << ")";
    208         return -errno;
    209     }
    210 
    211     while ((read = getline(&line, &len, file)) != -1) {
    212         // Skip non "cpu[0-9]" lines.
    213         if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) {
    214             free(line);
    215             line = NULL;
    216             len = 0;
    217             continue;
    218         }
    219 
    220         vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user,
    221                 &nice, &system, &idle);
    222 
    223         free(line);
    224         line = NULL;
    225         len = 0;
    226 
    227         if (vals != 5 || size == kCpuNum) {
    228             if (vals != 5) {
    229                 PLOG(ERROR) << "fillCpuUsages: failed to read CPU information from file ("
    230                             << kCpuUsageFile << ")";
    231             } else {
    232                 PLOG(ERROR) << "fillCpuUsages: file has incorrect format ("
    233                             << kCpuUsageFile << ")";
    234             }
    235             fclose(file);
    236             return errno ? -errno : -EIO;
    237         }
    238 
    239         active = user + nice + system;
    240         total = active + idle;
    241 
    242         // Read online CPU information.
    243         snprintf(file_name, PATH_MAX, kCpuOnlineFileFormat, cpu_num);
    244         cpu_file = fopen(file_name, "r");
    245         online = 0;
    246         if (cpu_file == NULL) {
    247             PLOG(ERROR) << "fillCpuUsages: failed to open file (" << file_name << ")";
    248             fclose(file);
    249             return -errno;
    250         }
    251         if (1 != fscanf(cpu_file, "%d", &online)) {
    252             PLOG(ERROR) << "fillCpuUsages: failed to read CPU online information from file ("
    253                         << file_name << ")";
    254             fclose(file);
    255             fclose(cpu_file);
    256             return errno ? -errno : -EIO;
    257         }
    258         fclose(cpu_file);
    259 
    260         (*cpuUsages)[size].name = kCpuLabel[size];
    261         (*cpuUsages)[size].active = active;
    262         (*cpuUsages)[size].total = total;
    263         (*cpuUsages)[size].isOnline = static_cast<bool>(online);
    264 
    265         LOG(DEBUG) << "fillCpuUsages: "<< kCpuLabel[size] << ": "
    266                    << active << " " << total << " " <<  online;
    267         size++;
    268     }
    269     fclose(file);
    270 
    271     if (size != kCpuNum) {
    272         PLOG(ERROR) << "fillCpuUsages: file has incorrect format (" << kCpuUsageFile << ")";
    273         return -EIO;
    274     }
    275     return kCpuNum;
    276 }
    277 
    278 std::string getTargetSkinSensorType() {
    279     return gSkinSensorType;
    280 }
    281 
    282 }  // namespace implementation
    283 }  // namespace V1_1
    284 }  // namespace thermal
    285 }  // namespace hardware
    286 }  // namespace android
    287