blob: a138165e83aab999dbc2f5548433b8d3185f380e
1 | /* |
2 | * Copyright (C) 2011 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 | * @author Tellen Yu |
16 | * @version 1.0 |
17 | * @date 2017/7/19 |
18 | * @par function description: |
19 | * - 1 thermal HAL |
20 | */ |
21 | |
22 | #include <errno.h> |
23 | #include <ctype.h> |
24 | #include <dirent.h> |
25 | #include <inttypes.h> |
26 | #include <stdlib.h> |
27 | #include <string.h> |
28 | #include <vector> |
29 | |
30 | #define LOG_TAG "ThermalHAL" |
31 | #include <utils/Log.h> |
32 | |
33 | #include <hardware/hardware.h> |
34 | #include <hardware/thermal.h> |
35 | |
36 | #define TEMPERATURE_TYPE_CPU "CPU" |
37 | #define TEMPERATURE_TYPE_GPU "GPU" |
38 | |
39 | #define CPU_LABEL_0 "CPU0" |
40 | #define CPU_LABEL_1 "CPU1" |
41 | #define CPU_LABEL_2 "CPU2" |
42 | #define CPU_LABEL_3 "CPU3" |
43 | #define MAX_LENGTH 100 |
44 | #define VALUE_LENGTH 64 |
45 | |
46 | #define CPU_USAGE_FILE "/proc/stat" |
47 | #define TEMPERATURE_DIR "/sys/class/thermal" |
48 | #define THERMAL_DIR "thermal_zone" |
49 | #define CPU_ONLINE_FILE_FORMAT "/sys/devices/system/cpu/cpu%d/online" |
50 | #define UNKNOWN_LABEL "UNKNOWN" |
51 | |
52 | namespace android { |
53 | namespace amlogic { |
54 | |
55 | /*--------------------------------------------------------------- |
56 | * FUNCTION NAME: readSysValue |
57 | * DESCRIPTION: |
58 | * read value from sysfs |
59 | * ARGUMENTS: |
60 | * const char *path:sysfs patch |
61 | * Return: |
62 | * -1:fail, >=0: success |
63 | * Note: |
64 | * |
65 | *---------------------------------------------------------------*/ |
66 | static int readSysValue(const char *path) { |
67 | int fd, len; |
68 | char* end; |
69 | char value[VALUE_LENGTH] = {0}; |
70 | |
71 | if ((fd = open(path, O_RDONLY)) < 0) { |
72 | ALOGE("readSysValue, open %s fail.", path); |
73 | return -1; |
74 | } |
75 | |
76 | len = read(fd, value, VALUE_LENGTH); |
77 | if (len < 0) { |
78 | ALOGE("read error: %s, %s\n", path, strerror(errno)); |
79 | } |
80 | |
81 | close(fd); |
82 | |
83 | if ((0x0A == value[len-1]) || (0x0D == value[len-1])) { |
84 | value[len-1] = '\0'; |
85 | } |
86 | |
87 | //ALOGI("readSysValue, path: %s, value: %s\n", path, value); |
88 | int val = (int) strtol(value, &end, 0); |
89 | if (end == value || *end != '\0' || val == INT_MAX || val == INT_MIN) { |
90 | //ALOGI("readSysValue, end: %p, value: %p\n", end, value); |
91 | return -1; |
92 | } |
93 | |
94 | return val; |
95 | } |
96 | |
97 | static ssize_t getTemperatures(thermal_module_t *module, temperature_t *list, size_t size) { |
98 | char path[MAX_LENGTH]; |
99 | float temp; |
100 | float throttlingThreshold; |
101 | float shutdownThreshold; |
102 | size_t idx = 0; |
103 | DIR *dir; |
104 | struct dirent *de; |
105 | |
106 | /** Read all available temperatures from |
107 | * /sys/class/thermal/thermal_zone[0-9]+/temp files. |
108 | * Don't guarantee that all temperatures are in Celsius. */ |
109 | dir = opendir(TEMPERATURE_DIR); |
110 | if (dir == 0) { |
111 | ALOGE("%s: failed to open directory %s: %s", __func__, TEMPERATURE_DIR, strerror(-errno)); |
112 | return -errno; |
113 | } |
114 | |
115 | while ((de = readdir(dir))) { |
116 | if (!strncmp(de->d_name, THERMAL_DIR, strlen(THERMAL_DIR))) { |
117 | int val; |
118 | |
119 | snprintf(path, MAX_LENGTH, "%s/%s/temp", TEMPERATURE_DIR, de->d_name); |
120 | val = readSysValue(path); |
121 | if (val < 0) { |
122 | continue; |
123 | } |
124 | |
125 | temp = (float)val/1000; |
126 | if (list != NULL && idx < size) { |
127 | snprintf(path, MAX_LENGTH, "%s/%s/trip_point_1_temp", TEMPERATURE_DIR, de->d_name); |
128 | val = readSysValue(path); |
129 | if (val >= 0) { |
130 | throttlingThreshold = (float)val/1000; |
131 | } |
132 | |
133 | snprintf(path, MAX_LENGTH, "%s/%s/trip_point_3_temp", TEMPERATURE_DIR, de->d_name); |
134 | val = readSysValue(path); |
135 | if (val >= 0) { |
136 | shutdownThreshold = (float)val/1000; |
137 | } |
138 | |
139 | list[idx] = (temperature_t) { |
140 | .name = TEMPERATURE_TYPE_CPU, |
141 | .type = DEVICE_TEMPERATURE_CPU, |
142 | .current_value = temp, |
143 | .throttling_threshold = throttlingThreshold, |
144 | .shutdown_threshold = shutdownThreshold, |
145 | .vr_throttling_threshold = UNKNOWN_TEMPERATURE, |
146 | }; |
147 | } |
148 | |
149 | idx++; |
150 | } |
151 | } |
152 | closedir(dir); |
153 | |
154 | ALOGI("current temperature:%f, throttling_threshold:%f, shutdown_threshold:%f", temp, throttlingThreshold, shutdownThreshold); |
155 | return idx; |
156 | } |
157 | |
158 | static ssize_t getCpuUsages(thermal_module_t *module, cpu_usage_t *list) { |
159 | int vals, cpu_num, online; |
160 | ssize_t read; |
161 | uint64_t user, nice, system, idle, active, total; |
162 | char *line = NULL; |
163 | size_t len = 0; |
164 | size_t size = 0; |
165 | char file_name[MAX_LENGTH]; |
166 | FILE *cpu_file; |
167 | FILE *file = fopen(CPU_USAGE_FILE, "r"); |
168 | |
169 | if (file == NULL) { |
170 | ALOGE("%s: failed to open: %s", __func__, strerror(errno)); |
171 | return -errno; |
172 | } |
173 | |
174 | /* sample: |
175 | cpu 6604 1513 6140 156891 1251 0 9 0 0 0 |
176 | cpu0 1399 423 1667 38709 346 0 5 0 0 0 |
177 | cpu1 1521 325 1211 39586 157 0 3 0 0 0 |
178 | cpu2 1980 399 1931 38470 381 0 0 0 0 0 |
179 | cpu3 1704 366 1331 40126 367 0 1 0 0 0 |
180 | */ |
181 | while ((read = getline(&line, &len, file)) != -1) { |
182 | // Skip non "cpu[0-9]" lines. |
183 | if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) { |
184 | free(line); |
185 | line = NULL; |
186 | len = 0; |
187 | continue; |
188 | } |
189 | vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user, |
190 | &nice, &system, &idle); |
191 | |
192 | free(line); |
193 | line = NULL; |
194 | len = 0; |
195 | |
196 | if (vals != 5) { |
197 | ALOGE("%s: failed to read CPU information from file: %s", __func__, strerror(errno)); |
198 | fclose(file); |
199 | return errno ? -errno : -EIO; |
200 | } |
201 | |
202 | active = user + nice + system; |
203 | total = active + idle; |
204 | |
205 | // Read online CPU information. |
206 | snprintf(file_name, MAX_LENGTH, CPU_ONLINE_FILE_FORMAT, cpu_num); |
207 | cpu_file = fopen(file_name, "r"); |
208 | online = 0; |
209 | if (cpu_file == NULL) { |
210 | ALOGE("%s: failed to open file: %s (%s)", __func__, file_name, strerror(errno)); |
211 | // /sys/devices/system/cpu/cpu0/online is missing on some systems, because cpu0 can't |
212 | // be offline. |
213 | online = cpu_num == 0; |
214 | } else if (1 != fscanf(cpu_file, "%d", &online)) { |
215 | ALOGE("%s: failed to read CPU online information from file: %s (%s)", __func__, |
216 | file_name, strerror(errno)); |
217 | fclose(file); |
218 | fclose(cpu_file); |
219 | return errno ? -errno : -EIO; |
220 | } else { |
221 | fclose(cpu_file); |
222 | } |
223 | |
224 | if (list != NULL) { |
225 | const char *cpuName = CPU_LABEL_0; |
226 | if (0 == cpu_num) |
227 | cpuName = CPU_LABEL_0; |
228 | else if (1 == cpu_num) |
229 | cpuName = CPU_LABEL_1; |
230 | else if (2 == cpu_num) |
231 | cpuName = CPU_LABEL_2; |
232 | else if (3 == cpu_num) |
233 | cpuName = CPU_LABEL_3; |
234 | list[size] = (cpu_usage_t) { |
235 | .name = cpuName, |
236 | .active = active, |
237 | .total = total, |
238 | .is_online = (1 == online)?true:false |
239 | }; |
240 | } |
241 | |
242 | size++; |
243 | } |
244 | |
245 | //if (list != NULL) { |
246 | // for (size_t i = 0; i < size; ++i) |
247 | // ALOGI("index:%d: cpu name:%s", i, list[i].name); |
248 | //} |
249 | |
250 | fclose(file); |
251 | return size; |
252 | } |
253 | |
254 | static ssize_t getCoolingDevices(thermal_module_t *module, cooling_device_t *list, size_t size) { |
255 | return 0; |
256 | } |
257 | |
258 | } // namespace amlogic |
259 | } // namespace android |
260 | |
261 | |
262 | static struct hw_module_methods_t thermal_module_methods = { |
263 | .open = NULL, |
264 | }; |
265 | |
266 | thermal_module_t HAL_MODULE_INFO_SYM = { |
267 | .common = { |
268 | .tag = HARDWARE_MODULE_TAG, |
269 | .module_api_version = THERMAL_HARDWARE_MODULE_API_VERSION_0_1, |
270 | .hal_api_version = HARDWARE_HAL_API_VERSION, |
271 | .id = THERMAL_HARDWARE_MODULE_ID, |
272 | .name = "AML Thermal HAL", |
273 | .author = "aml", |
274 | .methods = &thermal_module_methods, |
275 | }, |
276 | |
277 | .getTemperatures = android::amlogic::getTemperatures, |
278 | .getCpuUsages = android::amlogic::getCpuUsages, |
279 | .getCoolingDevices = android::amlogic::getCoolingDevices, |
280 | }; |
281 |