xref: /aosp_15_r20/hardware/libhardware/modules/thermal/thermal.c (revision e01b6f769022e40d0923dee176e8dc7cd1d52984)
1*e01b6f76SAndroid Build Coastguard Worker /*
2*e01b6f76SAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*e01b6f76SAndroid Build Coastguard Worker  *
4*e01b6f76SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*e01b6f76SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*e01b6f76SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*e01b6f76SAndroid Build Coastguard Worker  *
8*e01b6f76SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*e01b6f76SAndroid Build Coastguard Worker  *
10*e01b6f76SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*e01b6f76SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*e01b6f76SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e01b6f76SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*e01b6f76SAndroid Build Coastguard Worker  * limitations under the License.
15*e01b6f76SAndroid Build Coastguard Worker  */
16*e01b6f76SAndroid Build Coastguard Worker 
17*e01b6f76SAndroid Build Coastguard Worker #include <errno.h>
18*e01b6f76SAndroid Build Coastguard Worker #include <ctype.h>
19*e01b6f76SAndroid Build Coastguard Worker #include <dirent.h>
20*e01b6f76SAndroid Build Coastguard Worker #include <inttypes.h>
21*e01b6f76SAndroid Build Coastguard Worker #include <stdlib.h>
22*e01b6f76SAndroid Build Coastguard Worker #include <string.h>
23*e01b6f76SAndroid Build Coastguard Worker 
24*e01b6f76SAndroid Build Coastguard Worker #define LOG_TAG "ThermalHAL"
25*e01b6f76SAndroid Build Coastguard Worker #include <utils/Log.h>
26*e01b6f76SAndroid Build Coastguard Worker 
27*e01b6f76SAndroid Build Coastguard Worker #include <hardware/hardware.h>
28*e01b6f76SAndroid Build Coastguard Worker #include <hardware/thermal.h>
29*e01b6f76SAndroid Build Coastguard Worker 
30*e01b6f76SAndroid Build Coastguard Worker #define CPU_LABEL               "CPU"
31*e01b6f76SAndroid Build Coastguard Worker #define MAX_LENGTH              50
32*e01b6f76SAndroid Build Coastguard Worker 
33*e01b6f76SAndroid Build Coastguard Worker #define CPU_USAGE_FILE          "/proc/stat"
34*e01b6f76SAndroid Build Coastguard Worker #define TEMPERATURE_DIR         "/sys/class/thermal"
35*e01b6f76SAndroid Build Coastguard Worker #define THERMAL_DIR             "thermal_zone"
36*e01b6f76SAndroid Build Coastguard Worker #define CPU_ONLINE_FILE_FORMAT  "/sys/devices/system/cpu/cpu%d/online"
37*e01b6f76SAndroid Build Coastguard Worker #define UNKNOWN_LABEL           "UNKNOWN"
38*e01b6f76SAndroid Build Coastguard Worker 
get_temperatures(thermal_module_t * module,temperature_t * list,size_t size)39*e01b6f76SAndroid Build Coastguard Worker static ssize_t get_temperatures(thermal_module_t *module, temperature_t *list, size_t size) {
40*e01b6f76SAndroid Build Coastguard Worker     char file_name[MAX_LENGTH];
41*e01b6f76SAndroid Build Coastguard Worker     FILE *file;
42*e01b6f76SAndroid Build Coastguard Worker     float temp;
43*e01b6f76SAndroid Build Coastguard Worker     size_t idx = 0;
44*e01b6f76SAndroid Build Coastguard Worker     DIR *dir;
45*e01b6f76SAndroid Build Coastguard Worker     struct dirent *de;
46*e01b6f76SAndroid Build Coastguard Worker 
47*e01b6f76SAndroid Build Coastguard Worker     /** Read all available temperatures from
48*e01b6f76SAndroid Build Coastguard Worker      * /sys/class/thermal/thermal_zone[0-9]+/temp files.
49*e01b6f76SAndroid Build Coastguard Worker      * Don't guarantee that all temperatures are in Celsius. */
50*e01b6f76SAndroid Build Coastguard Worker     dir = opendir(TEMPERATURE_DIR);
51*e01b6f76SAndroid Build Coastguard Worker     if (dir == 0) {
52*e01b6f76SAndroid Build Coastguard Worker         ALOGE("%s: failed to open directory %s: %s", __func__, TEMPERATURE_DIR, strerror(-errno));
53*e01b6f76SAndroid Build Coastguard Worker         return -errno;
54*e01b6f76SAndroid Build Coastguard Worker     }
55*e01b6f76SAndroid Build Coastguard Worker 
56*e01b6f76SAndroid Build Coastguard Worker     while ((de = readdir(dir))) {
57*e01b6f76SAndroid Build Coastguard Worker         if (!strncmp(de->d_name, THERMAL_DIR, strlen(THERMAL_DIR))) {
58*e01b6f76SAndroid Build Coastguard Worker             snprintf(file_name, MAX_LENGTH, "%s/%s/temp", TEMPERATURE_DIR, de->d_name);
59*e01b6f76SAndroid Build Coastguard Worker             file = fopen(file_name, "r");
60*e01b6f76SAndroid Build Coastguard Worker             if (file == NULL) {
61*e01b6f76SAndroid Build Coastguard Worker                 continue;
62*e01b6f76SAndroid Build Coastguard Worker             }
63*e01b6f76SAndroid Build Coastguard Worker             if (1 != fscanf(file, "%f", &temp)) {
64*e01b6f76SAndroid Build Coastguard Worker                 fclose(file);
65*e01b6f76SAndroid Build Coastguard Worker                 continue;
66*e01b6f76SAndroid Build Coastguard Worker             }
67*e01b6f76SAndroid Build Coastguard Worker 
68*e01b6f76SAndroid Build Coastguard Worker             if (list != NULL && idx < size) {
69*e01b6f76SAndroid Build Coastguard Worker                 list[idx] = (temperature_t) {
70*e01b6f76SAndroid Build Coastguard Worker                     .name = UNKNOWN_LABEL,
71*e01b6f76SAndroid Build Coastguard Worker                     .type = DEVICE_TEMPERATURE_UNKNOWN,
72*e01b6f76SAndroid Build Coastguard Worker                     .current_value = temp,
73*e01b6f76SAndroid Build Coastguard Worker                     .throttling_threshold = UNKNOWN_TEMPERATURE,
74*e01b6f76SAndroid Build Coastguard Worker                     .shutdown_threshold = UNKNOWN_TEMPERATURE,
75*e01b6f76SAndroid Build Coastguard Worker                     .vr_throttling_threshold = UNKNOWN_TEMPERATURE,
76*e01b6f76SAndroid Build Coastguard Worker                 };
77*e01b6f76SAndroid Build Coastguard Worker             }
78*e01b6f76SAndroid Build Coastguard Worker             fclose(file);
79*e01b6f76SAndroid Build Coastguard Worker             idx++;
80*e01b6f76SAndroid Build Coastguard Worker         }
81*e01b6f76SAndroid Build Coastguard Worker     }
82*e01b6f76SAndroid Build Coastguard Worker     closedir(dir);
83*e01b6f76SAndroid Build Coastguard Worker     return idx;
84*e01b6f76SAndroid Build Coastguard Worker }
85*e01b6f76SAndroid Build Coastguard Worker 
get_cpu_usages(thermal_module_t * module,cpu_usage_t * list)86*e01b6f76SAndroid Build Coastguard Worker static ssize_t get_cpu_usages(thermal_module_t *module, cpu_usage_t *list) {
87*e01b6f76SAndroid Build Coastguard Worker     int vals, cpu_num, online;
88*e01b6f76SAndroid Build Coastguard Worker     ssize_t read;
89*e01b6f76SAndroid Build Coastguard Worker     uint64_t user, nice, system, idle, active, total;
90*e01b6f76SAndroid Build Coastguard Worker     char *line = NULL;
91*e01b6f76SAndroid Build Coastguard Worker     size_t len = 0;
92*e01b6f76SAndroid Build Coastguard Worker     size_t size = 0;
93*e01b6f76SAndroid Build Coastguard Worker     char file_name[MAX_LENGTH];
94*e01b6f76SAndroid Build Coastguard Worker     FILE *cpu_file;
95*e01b6f76SAndroid Build Coastguard Worker     FILE *file = fopen(CPU_USAGE_FILE, "r");
96*e01b6f76SAndroid Build Coastguard Worker 
97*e01b6f76SAndroid Build Coastguard Worker     if (file == NULL) {
98*e01b6f76SAndroid Build Coastguard Worker         ALOGE("%s: failed to open: %s", __func__, strerror(errno));
99*e01b6f76SAndroid Build Coastguard Worker         return -errno;
100*e01b6f76SAndroid Build Coastguard Worker     }
101*e01b6f76SAndroid Build Coastguard Worker 
102*e01b6f76SAndroid Build Coastguard Worker     while ((read = getline(&line, &len, file)) != -1) {
103*e01b6f76SAndroid Build Coastguard Worker         // Skip non "cpu[0-9]" lines.
104*e01b6f76SAndroid Build Coastguard Worker         if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) {
105*e01b6f76SAndroid Build Coastguard Worker             free(line);
106*e01b6f76SAndroid Build Coastguard Worker             line = NULL;
107*e01b6f76SAndroid Build Coastguard Worker             len = 0;
108*e01b6f76SAndroid Build Coastguard Worker             continue;
109*e01b6f76SAndroid Build Coastguard Worker         }
110*e01b6f76SAndroid Build Coastguard Worker         vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user,
111*e01b6f76SAndroid Build Coastguard Worker                 &nice, &system, &idle);
112*e01b6f76SAndroid Build Coastguard Worker 
113*e01b6f76SAndroid Build Coastguard Worker         free(line);
114*e01b6f76SAndroid Build Coastguard Worker         line = NULL;
115*e01b6f76SAndroid Build Coastguard Worker         len = 0;
116*e01b6f76SAndroid Build Coastguard Worker 
117*e01b6f76SAndroid Build Coastguard Worker         if (vals != 5) {
118*e01b6f76SAndroid Build Coastguard Worker             ALOGE("%s: failed to read CPU information from file: %s", __func__, strerror(errno));
119*e01b6f76SAndroid Build Coastguard Worker             fclose(file);
120*e01b6f76SAndroid Build Coastguard Worker             return errno ? -errno : -EIO;
121*e01b6f76SAndroid Build Coastguard Worker         }
122*e01b6f76SAndroid Build Coastguard Worker 
123*e01b6f76SAndroid Build Coastguard Worker         active = user + nice + system;
124*e01b6f76SAndroid Build Coastguard Worker         total = active + idle;
125*e01b6f76SAndroid Build Coastguard Worker 
126*e01b6f76SAndroid Build Coastguard Worker         // Read online CPU information.
127*e01b6f76SAndroid Build Coastguard Worker         snprintf(file_name, MAX_LENGTH, CPU_ONLINE_FILE_FORMAT, cpu_num);
128*e01b6f76SAndroid Build Coastguard Worker         cpu_file = fopen(file_name, "r");
129*e01b6f76SAndroid Build Coastguard Worker         online = 0;
130*e01b6f76SAndroid Build Coastguard Worker         if (cpu_file == NULL) {
131*e01b6f76SAndroid Build Coastguard Worker             ALOGE("%s: failed to open file: %s (%s)", __func__, file_name, strerror(errno));
132*e01b6f76SAndroid Build Coastguard Worker             // /sys/devices/system/cpu/cpu0/online is missing on some systems, because cpu0 can't
133*e01b6f76SAndroid Build Coastguard Worker             // be offline.
134*e01b6f76SAndroid Build Coastguard Worker             online = cpu_num == 0;
135*e01b6f76SAndroid Build Coastguard Worker         } else if (1 != fscanf(cpu_file, "%d", &online)) {
136*e01b6f76SAndroid Build Coastguard Worker             ALOGE("%s: failed to read CPU online information from file: %s (%s)", __func__,
137*e01b6f76SAndroid Build Coastguard Worker                     file_name, strerror(errno));
138*e01b6f76SAndroid Build Coastguard Worker             fclose(file);
139*e01b6f76SAndroid Build Coastguard Worker             fclose(cpu_file);
140*e01b6f76SAndroid Build Coastguard Worker             return errno ? -errno : -EIO;
141*e01b6f76SAndroid Build Coastguard Worker         } else {
142*e01b6f76SAndroid Build Coastguard Worker             fclose(cpu_file);
143*e01b6f76SAndroid Build Coastguard Worker         }
144*e01b6f76SAndroid Build Coastguard Worker 
145*e01b6f76SAndroid Build Coastguard Worker         if (list != NULL) {
146*e01b6f76SAndroid Build Coastguard Worker             list[size] = (cpu_usage_t) {
147*e01b6f76SAndroid Build Coastguard Worker                 .name = CPU_LABEL,
148*e01b6f76SAndroid Build Coastguard Worker                 .active = active,
149*e01b6f76SAndroid Build Coastguard Worker                 .total = total,
150*e01b6f76SAndroid Build Coastguard Worker                 .is_online = online
151*e01b6f76SAndroid Build Coastguard Worker             };
152*e01b6f76SAndroid Build Coastguard Worker         }
153*e01b6f76SAndroid Build Coastguard Worker 
154*e01b6f76SAndroid Build Coastguard Worker         size++;
155*e01b6f76SAndroid Build Coastguard Worker     }
156*e01b6f76SAndroid Build Coastguard Worker 
157*e01b6f76SAndroid Build Coastguard Worker     fclose(file);
158*e01b6f76SAndroid Build Coastguard Worker     return size;
159*e01b6f76SAndroid Build Coastguard Worker }
160*e01b6f76SAndroid Build Coastguard Worker 
get_cooling_devices(thermal_module_t * module,cooling_device_t * list,size_t size)161*e01b6f76SAndroid Build Coastguard Worker static ssize_t get_cooling_devices(thermal_module_t *module, cooling_device_t *list, size_t size) {
162*e01b6f76SAndroid Build Coastguard Worker     return 0;
163*e01b6f76SAndroid Build Coastguard Worker }
164*e01b6f76SAndroid Build Coastguard Worker 
165*e01b6f76SAndroid Build Coastguard Worker static struct hw_module_methods_t thermal_module_methods = {
166*e01b6f76SAndroid Build Coastguard Worker     .open = NULL,
167*e01b6f76SAndroid Build Coastguard Worker };
168*e01b6f76SAndroid Build Coastguard Worker 
169*e01b6f76SAndroid Build Coastguard Worker thermal_module_t HAL_MODULE_INFO_SYM = {
170*e01b6f76SAndroid Build Coastguard Worker     .common = {
171*e01b6f76SAndroid Build Coastguard Worker         .tag = HARDWARE_MODULE_TAG,
172*e01b6f76SAndroid Build Coastguard Worker         .module_api_version = THERMAL_HARDWARE_MODULE_API_VERSION_0_1,
173*e01b6f76SAndroid Build Coastguard Worker         .hal_api_version = HARDWARE_HAL_API_VERSION,
174*e01b6f76SAndroid Build Coastguard Worker         .id = THERMAL_HARDWARE_MODULE_ID,
175*e01b6f76SAndroid Build Coastguard Worker         .name = "Default Thermal HAL",
176*e01b6f76SAndroid Build Coastguard Worker         .author = "The Android Open Source Project",
177*e01b6f76SAndroid Build Coastguard Worker         .methods = &thermal_module_methods,
178*e01b6f76SAndroid Build Coastguard Worker     },
179*e01b6f76SAndroid Build Coastguard Worker 
180*e01b6f76SAndroid Build Coastguard Worker     .getTemperatures = get_temperatures,
181*e01b6f76SAndroid Build Coastguard Worker     .getCpuUsages = get_cpu_usages,
182*e01b6f76SAndroid Build Coastguard Worker     .getCoolingDevices = get_cooling_devices,
183*e01b6f76SAndroid Build Coastguard Worker };
184