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