blob: c45d87ab00c31ae11f153a7d122e5b8ddb2e4fcf [file] [log] [blame]
Polina Bondarenko25cd7f02016-02-26 12:15:53 +01001/*
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 <errno.h>
18#include <ctype.h>
19#include <dirent.h>
20#include <inttypes.h>
21#include <stdlib.h>
22#include <string.h>
23
24#define LOG_TAG "ThermalHAL"
25#include <utils/Log.h>
26
27#include <hardware/hardware.h>
28#include <hardware/thermal.h>
29
30#define CPU_LABEL "CPU"
31#define MAX_LENGTH 50
32
33#define CPU_USAGE_FILE "/proc/stat"
34#define TEMPERATURE_DIR "/sys/class/thermal"
35#define THERMAL_DIR "thermal_zone"
36#define CPU_ONLINE_FILE_FORMAT "/sys/devices/system/cpu/cpu%d/online"
37#define UNKNOWN_LABEL "UNKNOWN"
38
39static ssize_t get_temperatures(thermal_module_t *module, temperature_t *list, size_t size) {
40 char file_name[MAX_LENGTH];
41 FILE *file;
42 float temp;
43 size_t idx = 0;
44 DIR *dir;
45 struct dirent *de;
46
47 /** Read all available temperatures from
48 * /sys/class/thermal/thermal_zone[0-9]+/temp files.
49 * Don't guarantee that all temperatures are in Celsius. */
50 dir = opendir(TEMPERATURE_DIR);
51 if (dir == 0) {
52 ALOGE("%s: failed to open directory %s: %s", __func__, TEMPERATURE_DIR, strerror(-errno));
53 return -errno;
54 }
55
56 while ((de = readdir(dir))) {
57 if (!strncmp(de->d_name, THERMAL_DIR, strlen(THERMAL_DIR))) {
58 snprintf(file_name, MAX_LENGTH, "%s/%s/temp", TEMPERATURE_DIR, de->d_name);
59 file = fopen(file_name, "r");
60 if (file == NULL) {
61 continue;
62 }
63 if (1 != fscanf(file, "%f", &temp)) {
64 fclose(file);
65 continue;
66 }
67
68 if (list != NULL && idx < size) {
69 list[idx] = (temperature_t) {
70 .name = UNKNOWN_LABEL,
71 .type = DEVICE_TEMPERATURE_UNKNOWN,
72 .current_value = temp,
73 .throttling_threshold = UNKNOWN_TEMPERATURE,
74 .shutdown_threshold = UNKNOWN_TEMPERATURE,
75 };
76 }
77 fclose(file);
78 idx++;
79 }
80 }
81 closedir(dir);
82 return idx;
83}
84
85static ssize_t get_cpu_usages(thermal_module_t *module, cpu_usage_t *list) {
86 int vals, cpu_num, online;
87 ssize_t read;
88 uint64_t user, nice, system, idle, active, total;
89 char *line = NULL;
90 size_t len = 0;
91 size_t size = 0;
92 char file_name[MAX_LENGTH];
93 FILE *cpu_file;
94 FILE *file = fopen(CPU_USAGE_FILE, "r");
95
96 if (file == NULL) {
97 ALOGE("%s: failed to open: %s", __func__, strerror(errno));
98 return -errno;
99 }
100
101 while ((read = getline(&line, &len, file)) != -1) {
102 // Skip non "cpu[0-9]" lines.
103 if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) {
104 free(line);
105 line = NULL;
106 len = 0;
107 continue;
108 }
109 vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user,
110 &nice, &system, &idle);
111
112 free(line);
113 line = NULL;
114 len = 0;
115
116 if (vals != 5) {
117 ALOGE("%s: failed to read CPU information from file: %s", __func__, strerror(errno));
118 fclose(file);
119 return errno ? -errno : -EIO;
120 }
121
122 active = user + nice + system;
123 total = active + idle;
124
125 // Read online CPU information.
126 snprintf(file_name, MAX_LENGTH, CPU_ONLINE_FILE_FORMAT, cpu_num);
127 cpu_file = fopen(file_name, "r");
128 online = 0;
129 if (cpu_file == NULL) {
130 ALOGE("%s: failed to open file: %s (%s)", __func__, file_name, strerror(errno));
131 // /sys/devices/system/cpu/cpu0/online is missing on some systems, because cpu0 can't
132 // be offline.
133 online = cpu_num == 0;
134 } else if (1 != fscanf(cpu_file, "%d", &online)) {
135 ALOGE("%s: failed to read CPU online information from file: %s (%s)", __func__,
136 file_name, strerror(errno));
137 fclose(file);
138 fclose(cpu_file);
139 return errno ? -errno : -EIO;
140 }
141 fclose(cpu_file);
142
143 if (list != NULL) {
144 list[size] = (cpu_usage_t) {
145 .name = CPU_LABEL,
146 .active = active,
147 .total = total,
148 .is_online = online
149 };
150 }
151
152 size++;
153 }
154
155 fclose(file);
156 return size;
157}
158
159static ssize_t get_cooling_devices(thermal_module_t *module, cooling_device_t *list, size_t size) {
160 return 0;
161}
162
163static struct hw_module_methods_t thermal_module_methods = {
164 .open = NULL,
165};
166
167thermal_module_t HAL_MODULE_INFO_SYM = {
168 .common = {
169 .tag = HARDWARE_MODULE_TAG,
170 .module_api_version = THERMAL_HARDWARE_MODULE_API_VERSION_0_1,
171 .hal_api_version = HARDWARE_HAL_API_VERSION,
172 .id = THERMAL_HARDWARE_MODULE_ID,
173 .name = "Default Thermal HAL",
174 .author = "The Android Open Source Project",
175 .methods = &thermal_module_methods,
176 },
177
178 .getTemperatures = get_temperatures,
179 .getCpuUsages = get_cpu_usages,
180 .getCoolingDevices = get_cooling_devices,
181};