• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 <cctype>
18 #include <cerrno>
19 #include <cinttypes>
20 #include <cmath>
21 #include <cstdlib>
22 #include <cstring>
23 #include <tuple>
24 #include <unordered_map>
25 #include <vector>
26 
27 #include <android-base/file.h>
28 #include <android-base/logging.h>
29 #include <android-base/properties.h>
30 #include <android-base/strings.h>
31 #include <android-base/stringprintf.h>
32 
33 #include "sensors.h"
34 #include "thermal-helper.h"
35 
36 namespace android {
37 namespace hardware {
38 namespace thermal {
39 namespace V1_1 {
40 namespace implementation {
41 
42 constexpr const char kThermalSensorsRoot[] = "/sys/class/thermal";
43 constexpr char kThermalZoneDirSuffix[] = "thermal_zone";
44 constexpr char kSensorTypeFileSuffix[] = "type";
45 constexpr char kTemperatureFileSuffix[] = "temp";
46 // This is a golden set of thermal sensor names, their types, and their
47 // multiplier. Used when we read in sensor values. The tuple value stored is
48 // formatted as such:
49 // <temperature type, multiplier value for reading temp>
50 const std::unordered_map<std::string, std::tuple<TemperatureType, float>>
51 kValidThermalSensorsMap = {
52     {"tsens_tz_sensor1", {TemperatureType::CPU, 0.1}},   // CPU0
53     {"tsens_tz_sensor2", {TemperatureType::CPU, 0.1}},   // CPU1
54     {"tsens_tz_sensor4", {TemperatureType::CPU, 0.1}},   // CPU2
55     {"tsens_tz_sensor3", {TemperatureType::CPU, 0.1}},   // CPU3
56     {"tsens_tz_sensor7", {TemperatureType::CPU, 0.1}},   // CPU4
57     {"tsens_tz_sensor8", {TemperatureType::CPU, 0.1}},   // CPU5
58     {"tsens_tz_sensor9", {TemperatureType::CPU, 0.1}},   // CPU6
59     {"tsens_tz_sensor10", {TemperatureType::CPU, 0.1}},  // CPU7
60     // GPU thermal sensor.
61     {"tsens_tz_sensor13", {TemperatureType::GPU, 0.1}},
62     // Battery thermal sensor.
63     {"battery", {TemperatureType::BATTERY, 0.001}},
64     // Skin thermal sensors. We use back_therm for walleye. For taimen we use
65     // bd_therm and bd_therm2.
66     {"back_therm", {TemperatureType::SKIN, 1.}},
67     {"bd_therm", {TemperatureType::SKIN, 1.}},
68     {"bd_therm2", {TemperatureType::SKIN, 1.}},
69     // USBC thermal sensor.
70     {"usb_port_temp", {TemperatureType::UNKNOWN, 0.1}},
71 };
72 
73 namespace {
74 
75 using ::android::hardware::thermal::V1_0::TemperatureType;
76 
77 static std::string gSkinSensorType;
78 static unsigned int gSkinThrottlingThreshold;
79 static unsigned int gSkinShutdownThreshold;
80 static unsigned int gVrThrottledBelowMin;
81 Sensors gSensors;
82 
83 // A map containing hardcoded thresholds per sensor type.  Its not const
84 // because initThermal() will modify the skin sensor thresholds depending on the
85 // hardware type. The tuple is formatted as follows:
86 // <throttling threshold, shutdown threshold, vr threshold>
87 std::unordered_map<TemperatureType, std::tuple<float, float, float>>
88 gSensorTypeToThresholdsMap = {
89     {TemperatureType::CPU, {kCpuThrottlingThreshold, kCpuShutdownThreshold,
90                              kCpuThrottlingThreshold}},
91     {TemperatureType::GPU, {NAN, NAN, NAN}},
92     {TemperatureType::BATTERY, {NAN, kBatteryShutdownThreshold, NAN}},
93     {TemperatureType::SKIN, {NAN, NAN, NAN}},
94     {TemperatureType::UNKNOWN, {NAN, NAN, NAN}}
95 };
96 
initializeSensors()97 bool initializeSensors() {
98     auto thermal_zone_dir = std::unique_ptr<DIR, int (*)(DIR*)>(
99         opendir(kThermalSensorsRoot), closedir);
100     struct dirent* dp;
101     size_t num_thermal_zones = 0;
102     while ((dp = readdir(thermal_zone_dir.get())) != nullptr) {
103         std::string dir_name(dp->d_name);
104         if (dir_name.find(kThermalZoneDirSuffix) != std::string::npos) {
105             ++num_thermal_zones;
106         }
107     }
108 
109     for (size_t sensor_zone_num = 0; sensor_zone_num < num_thermal_zones;
110             ++sensor_zone_num) {
111         std::string path = android::base::StringPrintf("%s/%s%zu",
112                                                        kThermalSensorsRoot,
113                                                        kThermalZoneDirSuffix,
114                                                        sensor_zone_num);
115         std::string sensor_name;
116         if (android::base::ReadFileToString(
117                 path + "/" + kSensorTypeFileSuffix, &sensor_name)) {
118             sensor_name = android::base::Trim(sensor_name);
119             if (kValidThermalSensorsMap.find(sensor_name) !=
120                 kValidThermalSensorsMap.end()) {
121                   TemperatureType type = std::get<0>(
122                       kValidThermalSensorsMap.at(sensor_name));
123                   auto thresholds = gSensorTypeToThresholdsMap.at(type);
124                   if (!gSensors.addSensor(
125                           sensor_name, path + "/" + kTemperatureFileSuffix,
126                           std::get<0>(thresholds), std::get<1>(thresholds),
127                           std::get<2>(thresholds), type)) {
128                         LOG(ERROR) << "Could not add " << sensor_name
129                                    << "to sensors map";
130                   }
131             }
132         }
133     }
134     return (gSensors.getNumSensors() == kTemperatureNum);
135 }
136 
137 }  // namespace
138 
139 /**
140  * Initialization constants based on platform
141  *
142  * @return true on success or false on error.
143  */
initThermal()144 bool initThermal() {
145     std::string hardware = android::base::GetProperty("ro.hardware", "");
146     if (hardware == "walleye") {
147         LOG(ERROR) << "Initialization on Walleye";
148         gSkinThrottlingThreshold = kWalleyeSkinThrottlingThreshold;
149         gSkinShutdownThreshold = kWalleyeSkinShutdownThreshold;
150         gVrThrottledBelowMin = kWalleyeVrThrottledBelowMin;
151     } else if (hardware == "taimen") {
152         std::string rev = android::base::GetProperty("ro.revision", "");
153         if (rev == "rev_a" || rev == "rev_b") {
154             LOG(ERROR) << "Initialization on Taimen pre revision C";
155             gSkinThrottlingThreshold = kTaimenRabSkinThrottlingThreshold;
156             gSkinShutdownThreshold = kTaimenRabSkinShutdownThreshold;
157             gVrThrottledBelowMin = kTaimenRabVrThrottledBelowMin;
158         } else {
159             LOG(ERROR) << "Initialization on Taimen revision C and later";
160             gSkinThrottlingThreshold = kTaimenRcSkinThrottlingThreshold;
161             gSkinShutdownThreshold = kTaimenRcSkinShutdownThreshold;
162             gVrThrottledBelowMin = kTaimenRcVrThrottledBelowMin;
163         }
164     } else {
165         LOG(ERROR) << "Unsupported hardware: " << hardware;
166         return false;
167     }
168     gSensorTypeToThresholdsMap[TemperatureType::SKIN] =
169         std::make_tuple(gSkinThrottlingThreshold, gSkinShutdownThreshold,
170                         gVrThrottledBelowMin);
171     return initializeSensors();
172 }
173 
fillTemperatures(hidl_vec<Temperature> * temperatures)174 ssize_t fillTemperatures(hidl_vec<Temperature>* temperatures) {
175     temperatures->resize(gSensors.getNumSensors());
176     ssize_t current_index = 0;
177     for (const auto& name_type_mult_pair : kValidThermalSensorsMap) {
178         Temperature temp;
179         if (gSensors.readTemperature(name_type_mult_pair.first,
180                                      std::get<1>(name_type_mult_pair.second),
181                                      &temp)) {
182             (*temperatures)[current_index] = temp;
183             ++current_index;
184         }
185     }
186     return current_index;
187 }
188 
fillCpuUsages(hidl_vec<CpuUsage> * cpuUsages)189 ssize_t fillCpuUsages(hidl_vec<CpuUsage> *cpuUsages) {
190     int vals, cpu_num, online;
191     ssize_t read;
192     uint64_t user, nice, system, idle, active, total;
193     char *line = NULL;
194     size_t len = 0;
195     size_t size = 0;
196     char file_name[PATH_MAX];
197     FILE *file;
198     FILE *cpu_file;
199 
200     if (cpuUsages == NULL || cpuUsages->size() < kCpuNum ) {
201         LOG(ERROR) << "fillCpuUsages: incorrect buffer";
202         return -EINVAL;
203     }
204 
205     file = fopen(kCpuUsageFile, "r");
206     if (file == NULL) {
207         PLOG(ERROR) << "fillCpuUsages: failed to open file (" << kCpuUsageFile << ")";
208         return -errno;
209     }
210 
211     while ((read = getline(&line, &len, file)) != -1) {
212         // Skip non "cpu[0-9]" lines.
213         if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) {
214             free(line);
215             line = NULL;
216             len = 0;
217             continue;
218         }
219 
220         vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user,
221                 &nice, &system, &idle);
222 
223         free(line);
224         line = NULL;
225         len = 0;
226 
227         if (vals != 5 || size == kCpuNum) {
228             if (vals != 5) {
229                 PLOG(ERROR) << "fillCpuUsages: failed to read CPU information from file ("
230                             << kCpuUsageFile << ")";
231             } else {
232                 PLOG(ERROR) << "fillCpuUsages: file has incorrect format ("
233                             << kCpuUsageFile << ")";
234             }
235             fclose(file);
236             return errno ? -errno : -EIO;
237         }
238 
239         active = user + nice + system;
240         total = active + idle;
241 
242         // Read online CPU information.
243         snprintf(file_name, PATH_MAX, kCpuOnlineFileFormat, cpu_num);
244         cpu_file = fopen(file_name, "r");
245         online = 0;
246         if (cpu_file == NULL) {
247             PLOG(ERROR) << "fillCpuUsages: failed to open file (" << file_name << ")";
248             fclose(file);
249             return -errno;
250         }
251         if (1 != fscanf(cpu_file, "%d", &online)) {
252             PLOG(ERROR) << "fillCpuUsages: failed to read CPU online information from file ("
253                         << file_name << ")";
254             fclose(file);
255             fclose(cpu_file);
256             return errno ? -errno : -EIO;
257         }
258         fclose(cpu_file);
259 
260         (*cpuUsages)[size].name = kCpuLabel[size];
261         (*cpuUsages)[size].active = active;
262         (*cpuUsages)[size].total = total;
263         (*cpuUsages)[size].isOnline = static_cast<bool>(online);
264 
265         LOG(DEBUG) << "fillCpuUsages: "<< kCpuLabel[size] << ": "
266                    << active << " " << total << " " <<  online;
267         size++;
268     }
269     fclose(file);
270 
271     if (size != kCpuNum) {
272         PLOG(ERROR) << "fillCpuUsages: file has incorrect format (" << kCpuUsageFile << ")";
273         return -EIO;
274     }
275     return kCpuNum;
276 }
277 
getTargetSkinSensorType()278 std::string getTargetSkinSensorType() {
279     return gSkinSensorType;
280 }
281 
282 }  // namespace implementation
283 }  // namespace V1_1
284 }  // namespace thermal
285 }  // namespace hardware
286 }  // namespace android
287