Home | History | Annotate | Download | only in thermal
      1 /*
      2  * Copyright (C) 2016 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 <ctype.h>
     18 #include <errno.h>
     19 #include <inttypes.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 
     23 #define LOG_TAG "ThermalHAL"
     24 #include <utils/Log.h>
     25 
     26 #include <hardware/hardware.h>
     27 #include <hardware/thermal.h>
     28 
     29 #define MAX_LENGTH                  50
     30 
     31 #define CPU_USAGE_FILE              "/proc/stat"
     32 #define TEMPERATURE_FILE_FORMAT     "/sys/class/thermal/thermal_zone%d/temp"
     33 #define CPU_ONLINE_FILE_FORMAT      "/sys/devices/system/cpu/cpu%d/online"
     34 
     35 #define CPU_SENSOR_NUM              3
     36 #define BATTERY_SENSOR_NUM          2
     37 #define GPU_SENSOR_NUM              4
     38 
     39 #define CPU_NUM                     2
     40 #define TEMPERATURE_NUM             4
     41 
     42 #define BATTERY_SHUTDOWN_THRESHOLD  68
     43 
     44 #define GPU_LABEL                   "GPU"
     45 #define BATTERY_LABEL               "battery"
     46 
     47 const char *CPU_LABEL[] = {"CPU0", "CPU1"};
     48 
     49 /**
     50  * Reads device temperature.
     51  *
     52  * @param sensor_num Number of sensor file with temperature.
     53  * @param type Device temperature type.
     54  * @param name Device temperature name.
     55  * @param mult Multiplier used to translate temperature to Celsius.
     56  * @param throttling_threshold Throttling threshold for the temperature.
     57  * @param shutdown_threshold Shutdown threshold for the temperature.
     58  * @param out Pointer to temperature_t structure that will be filled with current
     59  *     values.
     60  *
     61  * @return 0 on success or negative value -errno on error.
     62  */
     63 static ssize_t read_temperature(int sensor_num, int type, const char *name, float mult,
     64         float throttling_threshold, float shutdown_threshold, temperature_t *out) {
     65     FILE *file;
     66     char file_name[MAX_LENGTH];
     67     float temp;
     68 
     69     sprintf(file_name, TEMPERATURE_FILE_FORMAT, sensor_num);
     70     file = fopen(file_name, "r");
     71     if (file == NULL) {
     72         ALOGE("%s: failed to open: %s", __func__, strerror(errno));
     73         return -errno;
     74     }
     75     if (1 != fscanf(file, "%f", &temp)) {
     76         fclose(file);
     77         ALOGE("%s: failed to read a float: %s", __func__, strerror(errno));
     78         return errno ? -errno : -EIO;
     79     }
     80 
     81     fclose(file);
     82 
     83     (*out) = (temperature_t) {
     84         .type = type,
     85         .name = name,
     86         .current_value = temp * mult,
     87         .throttling_threshold = throttling_threshold,
     88         .shutdown_threshold = shutdown_threshold,
     89         .vr_throttling_threshold = UNKNOWN_TEMPERATURE
     90     };
     91 
     92     return 0;
     93 }
     94 
     95 static ssize_t get_temperatures(thermal_module_t *module, temperature_t *list, size_t size) {
     96     ssize_t result = 0;
     97     size_t current_index = 0;
     98 
     99     if (list == NULL) {
    100         return TEMPERATURE_NUM;
    101     }
    102 
    103     // CPU temperature.
    104     if (current_index < size) {
    105         // CPU_therm: temperature in millidegrees Celsius.
    106         result = read_temperature(CPU_SENSOR_NUM, DEVICE_TEMPERATURE_CPU, CPU_LABEL[0], 0.001,
    107                 UNKNOWN_TEMPERATURE, UNKNOWN_TEMPERATURE, &list[current_index]);
    108         if (result < 0) {
    109             return result;
    110         }
    111         current_index++;
    112         if (current_index < size) {
    113             list[current_index] = list[current_index - 1];
    114             list[current_index].name = CPU_LABEL[1];
    115             current_index++;
    116         }
    117     }
    118 
    119     // GPU temperature.
    120     if (current_index < size) {
    121         // GPU_therm: temperature in millidegrees Celsius.
    122         result = read_temperature(GPU_SENSOR_NUM, DEVICE_TEMPERATURE_GPU, GPU_LABEL, 0.001,
    123                 UNKNOWN_TEMPERATURE, UNKNOWN_TEMPERATURE, &list[current_index]);
    124         if (result < 0) {
    125             return result;
    126         }
    127         current_index++;
    128     }
    129 
    130     // Battery temperature.
    131     if (current_index < size) {
    132         // battery: temperature in millidegrees Celsius.
    133         result = read_temperature(BATTERY_SENSOR_NUM, DEVICE_TEMPERATURE_BATTERY, BATTERY_LABEL,
    134                 0.001, UNKNOWN_TEMPERATURE, BATTERY_SHUTDOWN_THRESHOLD, &list[current_index]);
    135         if (result < 0) {
    136             return result;
    137         }
    138         current_index++;
    139     }
    140     return TEMPERATURE_NUM;
    141 }
    142 
    143 static ssize_t get_cpu_usages(thermal_module_t *module, cpu_usage_t *list) {
    144     int vals, cpu_num, online;
    145     ssize_t read;
    146     uint64_t user, nice, system, idle, active, total;
    147     char *line = NULL;
    148     size_t len = 0;
    149     size_t size = 0;
    150     char file_name[MAX_LENGTH];
    151     FILE *file;
    152     FILE *cpu_file;
    153 
    154     if (list == NULL) {
    155         return CPU_NUM;
    156     }
    157 
    158     file = fopen(CPU_USAGE_FILE, "r");
    159     if (file == NULL) {
    160         ALOGE("%s: failed to open: %s", __func__, strerror(errno));
    161         return -errno;
    162     }
    163 
    164     while ((read = getline(&line, &len, file)) != -1) {
    165         // Skip non "cpu[0-9]" lines.
    166         if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) {
    167             free(line);
    168             line = NULL;
    169             len = 0;
    170             continue;
    171         }
    172 
    173         vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user,
    174                 &nice, &system, &idle);
    175 
    176         free(line);
    177         line = NULL;
    178         len = 0;
    179 
    180         if (vals != 5 || size == CPU_NUM) {
    181             if (vals != 5) {
    182                 ALOGE("%s: failed to read CPU information from file: %s", __func__,
    183                         strerror(errno));
    184             } else {
    185                 ALOGE("/proc/stat file has incorrect format.");
    186             }
    187             fclose(file);
    188             return errno ? -errno : -EIO;
    189         }
    190 
    191         active = user + nice + system;
    192         total = active + idle;
    193 
    194         // Read online CPU information.
    195         snprintf(file_name, MAX_LENGTH, CPU_ONLINE_FILE_FORMAT, cpu_num);
    196         cpu_file = fopen(file_name, "r");
    197         online = 0;
    198         if (cpu_file == NULL) {
    199             ALOGE("%s: failed to open file: %s (%s)", __func__, file_name, strerror(errno));
    200             fclose(file);
    201             return -errno;
    202         }
    203         if (1 != fscanf(cpu_file, "%d", &online)) {
    204             ALOGE("%s: failed to read CPU online information from file: %s (%s)", __func__,
    205                     file_name, strerror(errno));
    206             fclose(file);
    207             fclose(cpu_file);
    208             return errno ? -errno : -EIO;
    209         }
    210         fclose(cpu_file);
    211 
    212         list[size] = (cpu_usage_t) {
    213             .name = CPU_LABEL[size],
    214             .active = active,
    215             .total = total,
    216             .is_online = online
    217         };
    218 
    219         size++;
    220     }
    221 
    222     fclose(file);
    223 
    224     if (size != CPU_NUM) {
    225         ALOGE("/proc/stat file has incorrect format.");
    226         return -EIO;
    227     }
    228 
    229     return CPU_NUM;
    230 }
    231 
    232 static struct hw_module_methods_t thermal_module_methods = {
    233     .open = NULL,
    234 };
    235 
    236 thermal_module_t HAL_MODULE_INFO_SYM = {
    237     .common = {
    238         .tag = HARDWARE_MODULE_TAG,
    239         .module_api_version = THERMAL_HARDWARE_MODULE_API_VERSION_0_1,
    240         .hal_api_version = HARDWARE_HAL_API_VERSION,
    241         .id = THERMAL_HARDWARE_MODULE_ID,
    242         .name = "Flounder Thermal HAL",
    243         .author = "The Android Open Source Project",
    244         .methods = &thermal_module_methods,
    245     },
    246     .getTemperatures = get_temperatures,
    247     .getCpuUsages = get_cpu_usages,
    248 };
    249