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