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 BATTERY_SENSOR_NUM 23 36 #define GPU_SENSOR_NUM 13 37 #define SKIN_SENSOR_NUM 18 38 39 const int CPU_SENSORS[] = {8, 9, 10, 11, 14, 15, 16, 7}; 40 41 #define CPU_NUM (sizeof(CPU_SENSORS) / sizeof(int)) 42 #define TEMPERATURE_NUM 11 43 44 //qcom, therm-reset-temp 45 #define CPU_SHUTDOWN_THRESHOLD 115 46 //qcom, limit-temp 47 #define CPU_THROTTLING_THRESHOLD 60 48 #define BATTERY_SHUTDOWN_THRESHOLD 60 49 // device/huawei/angler/thermal-engine-angler.conf 50 #define SKIN_THROTTLING_THRESHOLD 41 51 #define SKIN_SHUTDOWN_THRESHOLD 64 52 #define VR_THROTTLED_BELOW_MIN 47 53 54 #define GPU_LABEL "GPU" 55 #define BATTERY_LABEL "battery" 56 #define SKIN_LABEL "skin" 57 58 const char *CPU_LABEL[] = {"CPU0", "CPU1", "CPU2", "CPU3", "CPU4", "CPU5", "CPU6", "CPU7"}; 59 60 /** 61 * Reads device temperature. 62 * 63 * @param sensor_num Number of sensor file with temperature. 64 * @param type Device temperature type. 65 * @param name Device temperature name. 66 * @param mult Multiplier used to translate temperature to Celsius. 67 * @param throttling_threshold Throttling threshold for the temperature. 68 * @param shutdown_threshold Shutdown threshold for the temperature. 69 * @param out Pointer to temperature_t structure that will be filled with current 70 * values. 71 * 72 * @return 0 on success or negative value -errno on error. 73 */ 74 static ssize_t read_temperature(int sensor_num, int type, const char *name, float mult, 75 float throttling_threshold, float shutdown_threshold, float vr_throttling_threshold, 76 temperature_t *out) { 77 FILE *file; 78 char file_name[MAX_LENGTH]; 79 float temp; 80 81 sprintf(file_name, TEMPERATURE_FILE_FORMAT, sensor_num); 82 file = fopen(file_name, "r"); 83 if (file == NULL) { 84 ALOGE("%s: failed to open: %s", __func__, strerror(errno)); 85 return -errno; 86 } 87 if (1 != fscanf(file, "%f", &temp)) { 88 fclose(file); 89 ALOGE("%s: failed to read a float: %s", __func__, strerror(errno)); 90 return errno ? -errno : -EIO; 91 } 92 93 fclose(file); 94 95 (*out) = (temperature_t) { 96 .type = type, 97 .name = name, 98 .current_value = temp * mult, 99 .throttling_threshold = throttling_threshold, 100 .shutdown_threshold = shutdown_threshold, 101 .vr_throttling_threshold = vr_throttling_threshold 102 }; 103 104 return 0; 105 } 106 107 static ssize_t get_cpu_temperatures(temperature_t *list, size_t size) { 108 size_t cpu; 109 110 for (cpu = 0; cpu < CPU_NUM; cpu++) { 111 if (cpu >= size) { 112 break; 113 } 114 // tsens_tz_sensor[7,8,9,10,11,14,15,6]: temperature in Celsius. 115 ssize_t result = read_temperature(CPU_SENSORS[cpu], DEVICE_TEMPERATURE_CPU, CPU_LABEL[cpu], 116 1, CPU_THROTTLING_THRESHOLD, CPU_SHUTDOWN_THRESHOLD, UNKNOWN_TEMPERATURE, 117 &list[cpu]); 118 if (result != 0) { 119 return result; 120 } 121 } 122 return cpu; 123 } 124 125 static ssize_t get_temperatures(thermal_module_t *module, temperature_t *list, size_t size) { 126 ssize_t result = 0; 127 size_t current_index = 0; 128 129 if (list == NULL) { 130 return TEMPERATURE_NUM; 131 } 132 133 result = get_cpu_temperatures(list, size); 134 if (result < 0) { 135 return result; 136 } 137 current_index += result; 138 139 // GPU temperature. 140 if (current_index < size) { 141 // tsens_tz_sensor12: temperature in Celsius. 142 result = read_temperature(GPU_SENSOR_NUM, DEVICE_TEMPERATURE_GPU, GPU_LABEL, 1, 143 UNKNOWN_TEMPERATURE, UNKNOWN_TEMPERATURE, UNKNOWN_TEMPERATURE, 144 &list[current_index]); 145 if (result < 0) { 146 return result; 147 } 148 current_index++; 149 } 150 151 // Battery temperature. 152 if (current_index < size) { 153 // hwmon sensor: battery: temperature in millidegrees Celsius. 154 result = read_temperature(BATTERY_SENSOR_NUM, DEVICE_TEMPERATURE_BATTERY, BATTERY_LABEL, 155 0.001, UNKNOWN_TEMPERATURE, BATTERY_SHUTDOWN_THRESHOLD, UNKNOWN_TEMPERATURE, 156 &list[current_index]); 157 if (result < 0) { 158 return result; 159 } 160 current_index++; 161 } 162 163 // Skin temperature. 164 if (current_index < size) { 165 // msm_thermal: temperature in Celsius. 166 result = read_temperature(SKIN_SENSOR_NUM, DEVICE_TEMPERATURE_SKIN, SKIN_LABEL, 1, 167 SKIN_THROTTLING_THRESHOLD, SKIN_SHUTDOWN_THRESHOLD, VR_THROTTLED_BELOW_MIN, 168 &list[current_index]); 169 if (result < 0) { 170 return result; 171 } 172 current_index++; 173 } 174 return TEMPERATURE_NUM; 175 } 176 177 static ssize_t get_cpu_usages(thermal_module_t *module, cpu_usage_t *list) { 178 int vals, cpu_num, online; 179 ssize_t read; 180 uint64_t user, nice, system, idle, active, total; 181 char *line = NULL; 182 size_t len = 0; 183 size_t size = 0; 184 char file_name[MAX_LENGTH]; 185 FILE *file; 186 FILE *cpu_file; 187 188 if (list == NULL) { 189 return CPU_NUM; 190 } 191 192 file = fopen(CPU_USAGE_FILE, "r"); 193 if (file == NULL) { 194 ALOGE("%s: failed to open: %s", __func__, strerror(errno)); 195 return -errno; 196 } 197 198 while ((read = getline(&line, &len, file)) != -1) { 199 // Skip non "cpu[0-9]" lines. 200 if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) { 201 free(line); 202 line = NULL; 203 len = 0; 204 continue; 205 } 206 207 vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user, 208 &nice, &system, &idle); 209 210 free(line); 211 line = NULL; 212 len = 0; 213 214 if (vals != 5 || size == CPU_NUM) { 215 if (vals != 5) { 216 ALOGE("%s: failed to read CPU information from file: %s", __func__, 217 strerror(errno)); 218 } else { 219 ALOGE("/proc/stat file has incorrect format."); 220 } 221 fclose(file); 222 return errno ? -errno : -EIO; 223 } 224 225 active = user + nice + system; 226 total = active + idle; 227 228 // Read online CPU information. 229 snprintf(file_name, MAX_LENGTH, CPU_ONLINE_FILE_FORMAT, cpu_num); 230 cpu_file = fopen(file_name, "r"); 231 online = 0; 232 if (cpu_file == NULL) { 233 ALOGE("%s: failed to open file: %s (%s)", __func__, file_name, strerror(errno)); 234 fclose(file); 235 return -errno; 236 } 237 if (1 != fscanf(cpu_file, "%d", &online)) { 238 ALOGE("%s: failed to read CPU online information from file: %s (%s)", __func__, 239 file_name, strerror(errno)); 240 fclose(file); 241 fclose(cpu_file); 242 return errno ? -errno : -EIO; 243 } 244 fclose(cpu_file); 245 246 list[size] = (cpu_usage_t) { 247 .name = CPU_LABEL[size], 248 .active = active, 249 .total = total, 250 .is_online = online 251 }; 252 253 size++; 254 } 255 fclose(file); 256 257 if (size != CPU_NUM) { 258 ALOGE("/proc/stat file has incorrect format."); 259 return -EIO; 260 } 261 return CPU_NUM; 262 } 263 264 static struct hw_module_methods_t thermal_module_methods = { 265 .open = NULL, 266 }; 267 268 thermal_module_t HAL_MODULE_INFO_SYM = { 269 .common = { 270 .tag = HARDWARE_MODULE_TAG, 271 .module_api_version = THERMAL_HARDWARE_MODULE_API_VERSION_0_1, 272 .hal_api_version = HARDWARE_HAL_API_VERSION, 273 .id = THERMAL_HARDWARE_MODULE_ID, 274 .name = "Angler Thermal HAL", 275 .author = "The Android Open Source Project", 276 .methods = &thermal_module_methods, 277 }, 278 .getTemperatures = get_temperatures, 279 .getCpuUsages = get_cpu_usages, 280 }; 281