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