125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko/*
225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko * Copyright (C) 2016 The Android Open Source Project
325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko *
425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko * Licensed under the Apache License, Version 2.0 (the "License");
525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko * you may not use this file except in compliance with the License.
625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko * You may obtain a copy of the License at
725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko *
825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko *      http://www.apache.org/licenses/LICENSE-2.0
925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko *
1025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko * Unless required by applicable law or agreed to in writing, software
1125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko * distributed under the License is distributed on an "AS IS" BASIS,
1225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko * See the License for the specific language governing permissions and
1425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko * limitations under the License.
1525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko */
1625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
1725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#include <errno.h>
1825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#include <ctype.h>
1925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#include <dirent.h>
2025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#include <inttypes.h>
2125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#include <stdlib.h>
2225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#include <string.h>
2325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
2425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#define LOG_TAG "ThermalHAL"
2525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#include <utils/Log.h>
2625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
2725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#include <hardware/hardware.h>
2825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#include <hardware/thermal.h>
2925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
3025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#define CPU_LABEL               "CPU"
3125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#define MAX_LENGTH              50
3225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
3325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#define CPU_USAGE_FILE          "/proc/stat"
3425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#define TEMPERATURE_DIR         "/sys/class/thermal"
3525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#define THERMAL_DIR             "thermal_zone"
3625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#define CPU_ONLINE_FILE_FORMAT  "/sys/devices/system/cpu/cpu%d/online"
3725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko#define UNKNOWN_LABEL           "UNKNOWN"
3825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
3925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenkostatic ssize_t get_temperatures(thermal_module_t *module, temperature_t *list, size_t size) {
4025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    char file_name[MAX_LENGTH];
4125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    FILE *file;
4225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    float temp;
4325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    size_t idx = 0;
4425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    DIR *dir;
4525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    struct dirent *de;
4625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
4725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    /** Read all available temperatures from
4825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko     * /sys/class/thermal/thermal_zone[0-9]+/temp files.
4925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko     * Don't guarantee that all temperatures are in Celsius. */
5025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    dir = opendir(TEMPERATURE_DIR);
5125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    if (dir == 0) {
5225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        ALOGE("%s: failed to open directory %s: %s", __func__, TEMPERATURE_DIR, strerror(-errno));
5325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        return -errno;
5425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    }
5525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
5625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    while ((de = readdir(dir))) {
5725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        if (!strncmp(de->d_name, THERMAL_DIR, strlen(THERMAL_DIR))) {
5825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            snprintf(file_name, MAX_LENGTH, "%s/%s/temp", TEMPERATURE_DIR, de->d_name);
5925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            file = fopen(file_name, "r");
6025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            if (file == NULL) {
6125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                continue;
6225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            }
6325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            if (1 != fscanf(file, "%f", &temp)) {
6425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                fclose(file);
6525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                continue;
6625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            }
6725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
6825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            if (list != NULL && idx < size) {
6925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                list[idx] = (temperature_t) {
7025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                    .name = UNKNOWN_LABEL,
7125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                    .type = DEVICE_TEMPERATURE_UNKNOWN,
7225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                    .current_value = temp,
7325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                    .throttling_threshold = UNKNOWN_TEMPERATURE,
7425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                    .shutdown_threshold = UNKNOWN_TEMPERATURE,
7553b134045f686972eb0a5ec1d4301fc04e3f095aRuben Brunk                    .vr_throttling_threshold = UNKNOWN_TEMPERATURE,
7625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                };
7725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            }
7825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            fclose(file);
7925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            idx++;
8025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        }
8125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    }
8225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    closedir(dir);
8325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    return idx;
8425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko}
8525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
8625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenkostatic ssize_t get_cpu_usages(thermal_module_t *module, cpu_usage_t *list) {
8725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    int vals, cpu_num, online;
8825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    ssize_t read;
8925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    uint64_t user, nice, system, idle, active, total;
9025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    char *line = NULL;
9125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    size_t len = 0;
9225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    size_t size = 0;
9325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    char file_name[MAX_LENGTH];
9425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    FILE *cpu_file;
9525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    FILE *file = fopen(CPU_USAGE_FILE, "r");
9625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
9725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    if (file == NULL) {
9825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        ALOGE("%s: failed to open: %s", __func__, strerror(errno));
9925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        return -errno;
10025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    }
10125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
10225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    while ((read = getline(&line, &len, file)) != -1) {
10325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        // Skip non "cpu[0-9]" lines.
10425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) {
10525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            free(line);
10625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            line = NULL;
10725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            len = 0;
10825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            continue;
10925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        }
11025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user,
11125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                &nice, &system, &idle);
11225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
11325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        free(line);
11425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        line = NULL;
11525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        len = 0;
11625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
11725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        if (vals != 5) {
11825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            ALOGE("%s: failed to read CPU information from file: %s", __func__, strerror(errno));
11925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            fclose(file);
12025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            return errno ? -errno : -EIO;
12125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        }
12225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
12325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        active = user + nice + system;
12425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        total = active + idle;
12525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
12625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        // Read online CPU information.
12725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        snprintf(file_name, MAX_LENGTH, CPU_ONLINE_FILE_FORMAT, cpu_num);
12825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        cpu_file = fopen(file_name, "r");
12925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        online = 0;
13025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        if (cpu_file == NULL) {
13125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            ALOGE("%s: failed to open file: %s (%s)", __func__, file_name, strerror(errno));
13225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            // /sys/devices/system/cpu/cpu0/online is missing on some systems, because cpu0 can't
13325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            // be offline.
13425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            online = cpu_num == 0;
13525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        } else if (1 != fscanf(cpu_file, "%d", &online)) {
13625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            ALOGE("%s: failed to read CPU online information from file: %s (%s)", __func__,
13725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                    file_name, strerror(errno));
13825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            fclose(file);
13925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            fclose(cpu_file);
14025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            return errno ? -errno : -EIO;
14125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        }
14225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        fclose(cpu_file);
14325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
14425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        if (list != NULL) {
14525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            list[size] = (cpu_usage_t) {
14625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                .name = CPU_LABEL,
14725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                .active = active,
14825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                .total = total,
14925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko                .is_online = online
15025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko            };
15125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        }
15225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
15325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        size++;
15425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    }
15525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
15625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    fclose(file);
15725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    return size;
15825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko}
15925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
16025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenkostatic ssize_t get_cooling_devices(thermal_module_t *module, cooling_device_t *list, size_t size) {
16125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    return 0;
16225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko}
16325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
16425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenkostatic struct hw_module_methods_t thermal_module_methods = {
16525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    .open = NULL,
16625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko};
16725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
16825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenkothermal_module_t HAL_MODULE_INFO_SYM = {
16925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    .common = {
17025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        .tag = HARDWARE_MODULE_TAG,
17125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        .module_api_version = THERMAL_HARDWARE_MODULE_API_VERSION_0_1,
17225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        .hal_api_version = HARDWARE_HAL_API_VERSION,
17325cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        .id = THERMAL_HARDWARE_MODULE_ID,
17425cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        .name = "Default Thermal HAL",
17525cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        .author = "The Android Open Source Project",
17625cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko        .methods = &thermal_module_methods,
17725cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    },
17825cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko
17925cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    .getTemperatures = get_temperatures,
18025cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    .getCpuUsages = get_cpu_usages,
18125cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko    .getCoolingDevices = get_cooling_devices,
18225cd7f0fb0969683eceb00c9493e2ba8b80228e9Polina Bondarenko};
183