• 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 
24 #include <android-base/logging.h>
25 #include <android-base/properties.h>
26 #include <android-base/stringprintf.h>
27 
28 #include "thermal-helper.h"
29 
30 namespace android {
31 namespace hardware {
32 namespace thermal {
33 namespace V1_1 {
34 namespace implementation {
35 
36 using ::android::hardware::thermal::V1_0::TemperatureType;
37 
38 static unsigned int gSkinSensorNum;
39 static std::string gSkinSensorType;
40 static unsigned int gTsensOffset;
41 static unsigned int gSkinThrottlingThreshold;
42 static unsigned int gSkinShutdownThreshold;
43 static unsigned int gVrThrottledBelowMin;
44 
45 /**
46  * Initialization constants based on platform
47  *
48  * @return true on success or false on error.
49  */
initThermal()50 bool initThermal() {
51     std::string hardware = android::base::GetProperty("ro.hardware", "");
52     if (hardware == "walleye") {
53         LOG(ERROR) << "Initialization on Walleye";
54         gSkinSensorNum = kWalleyeSkinSensorNum;
55         gSkinSensorType = kWalleyeSkinSensorType;
56         gTsensOffset = kWalleyeTsensOffset;
57         gSkinThrottlingThreshold = kWalleyeSkinThrottlingThreshold;
58         gSkinShutdownThreshold = kWalleyeSkinShutdownThreshold;
59         gVrThrottledBelowMin = kWalleyeVrThrottledBelowMin;
60     } else if (hardware == "taimen") {
61         std::string rev = android::base::GetProperty("ro.revision", "");
62         if (rev == "rev_a" || rev == "rev_b") {
63             LOG(ERROR) << "Initialization on Taimen pre revision C";
64             gSkinSensorNum = kTaimenRabSkinSensorNum;
65             gSkinSensorType = kTaimenRabSkinSensorType;
66             gTsensOffset = kTaimenRabTsensOffset;
67             gSkinThrottlingThreshold = kTaimenRabSkinThrottlingThreshold;
68             gSkinShutdownThreshold = kTaimenRabSkinShutdownThreshold;
69             gVrThrottledBelowMin = kTaimenRabVrThrottledBelowMin;
70         } else {
71             LOG(ERROR) << "Initialization on Taimen revision C and later";
72             gSkinSensorNum = kTaimenRcSkinSensorNum;
73             gSkinSensorType = kTaimenRcSkinSensorType;
74             gTsensOffset = kTaimenRcTsensOffset;
75             gSkinThrottlingThreshold = kTaimenRcSkinThrottlingThreshold;
76             gSkinShutdownThreshold = kTaimenRcSkinShutdownThreshold;
77             gVrThrottledBelowMin = kTaimenRcVrThrottledBelowMin;
78         }
79     } else {
80         LOG(ERROR) << "Unsupported hardware: " << hardware;
81         return false;
82     }
83     return true;
84 }
85 
86 /**
87  * Reads device temperature.
88  *
89  * @param sensor_num Number of sensor file with temperature.
90  * @param type Device temperature type.
91  * @param name Device temperature name.
92  * @param mult Multiplier used to translate temperature to Celsius.
93  * @param throttling_threshold Throttling threshold for the temperature.
94  * @param shutdown_threshold Shutdown threshold for the temperature.
95  * @param out Pointer to temperature_t structure that will be filled with current
96  *     values.
97  *
98  * @return 0 on success or negative value -errno on error.
99  */
readTemperature(int sensor_num,TemperatureType type,const char * name,float mult,float throttling_threshold,float shutdown_threshold,float vr_throttling_threshold,Temperature * out)100 static ssize_t readTemperature(int sensor_num, TemperatureType type, const char *name, float mult,
101                                 float throttling_threshold, float shutdown_threshold,
102                                 float vr_throttling_threshold, Temperature *out) {
103     FILE *file;
104     char file_name[PATH_MAX];
105     float temp;
106 
107     sprintf(file_name, kTemperatureFileFormat, sensor_num);
108     file = fopen(file_name, "r");
109     if (file == NULL) {
110         PLOG(ERROR) << "readTemperature: failed to open file (" << file_name << ")";
111         return -errno;
112     }
113     if (1 != fscanf(file, "%f", &temp)) {
114         fclose(file);
115         PLOG(ERROR) << "readTemperature: failed to read a float";
116         return errno ? -errno : -EIO;
117     }
118 
119     fclose(file);
120 
121     (*out).type = type;
122     (*out).name = name;
123     (*out).currentValue = temp * mult;
124     (*out).throttlingThreshold = throttling_threshold;
125     (*out).shutdownThreshold = shutdown_threshold;
126     (*out).vrThrottlingThreshold = vr_throttling_threshold;
127 
128     LOG(DEBUG) << android::base::StringPrintf(
129         "readTemperature: %d, %d, %s, %g, %g, %g, %g",
130         sensor_num, type, name, temp * mult, throttling_threshold,
131         shutdown_threshold, vr_throttling_threshold);
132 
133     return 0;
134 }
135 
getCpuTemperatures(hidl_vec<Temperature> * temperatures)136 static ssize_t getCpuTemperatures(hidl_vec<Temperature> *temperatures) {
137     size_t cpu;
138 
139     for (cpu = 0; cpu < kCpuNum; cpu++) {
140         if (cpu >= temperatures->size()) {
141             break;
142         }
143         // temperature in decidegrees Celsius.
144         ssize_t result = readTemperature(kCpuTsensOffset[cpu] + gTsensOffset, TemperatureType::CPU, kCpuLabel[cpu],
145                                           0.1, kCpuThrottlingThreshold, kCpuShutdownThreshold, kCpuThrottlingThreshold,
146                                           &(*temperatures)[cpu]);
147         if (result != 0) {
148             return result;
149         }
150     }
151     return cpu;
152 }
153 
fillTemperatures(hidl_vec<Temperature> * temperatures)154 ssize_t fillTemperatures(hidl_vec<Temperature> *temperatures) {
155     ssize_t result = 0;
156     size_t current_index = 0;
157 
158     if (temperatures == NULL || temperatures->size() < kTemperatureNum) {
159         LOG(ERROR) << "fillTemperatures: incorrect buffer";
160         return -EINVAL;
161     }
162 
163     result = getCpuTemperatures(temperatures);
164     if (result < 0) {
165         return result;
166     }
167     current_index += result;
168 
169     // GPU temperature.
170     if (current_index < temperatures->size()) {
171         // temperature in decidegrees Celsius.
172         result = readTemperature(gTsensOffset + kGpuTsensOffset, TemperatureType::GPU, kGpuLabel, 0.1,
173                                   NAN, NAN, NAN, &(*temperatures)[current_index]);
174         if (result < 0) {
175             return result;
176         }
177         current_index++;
178     }
179 
180     // Battery temperature.
181     if (current_index < temperatures->size()) {
182         // battery: temperature in millidegrees Celsius.
183         result = readTemperature(kBatterySensorNum, TemperatureType::BATTERY, kBatteryLabel,
184                                   0.001, NAN, kBatteryShutdownThreshold, NAN,
185                                   &(*temperatures)[current_index]);
186         if (result < 0) {
187             return result;
188         }
189         current_index++;
190     }
191 
192     // Skin temperature.
193     if (current_index < temperatures->size()) {
194         // temperature in Celsius.
195         result = readTemperature(gSkinSensorNum, TemperatureType::SKIN, kSkinLabel, 1.,
196                                   gSkinThrottlingThreshold, gSkinShutdownThreshold, gVrThrottledBelowMin,
197                                   &(*temperatures)[current_index]);
198         if (result < 0) {
199             return result;
200         }
201         current_index++;
202     }
203     return kTemperatureNum;
204 }
205 
fillCpuUsages(hidl_vec<CpuUsage> * cpuUsages)206 ssize_t fillCpuUsages(hidl_vec<CpuUsage> *cpuUsages) {
207     int vals, cpu_num, online;
208     ssize_t read;
209     uint64_t user, nice, system, idle, active, total;
210     char *line = NULL;
211     size_t len = 0;
212     size_t size = 0;
213     char file_name[PATH_MAX];
214     FILE *file;
215     FILE *cpu_file;
216 
217     if (cpuUsages == NULL || cpuUsages->size() < kCpuNum ) {
218         LOG(ERROR) << "fillCpuUsages: incorrect buffer";
219         return -EINVAL;
220     }
221 
222     file = fopen(kCpuUsageFile, "r");
223     if (file == NULL) {
224         PLOG(ERROR) << "fillCpuUsages: failed to open file (" << kCpuUsageFile << ")";
225         return -errno;
226     }
227 
228     while ((read = getline(&line, &len, file)) != -1) {
229         // Skip non "cpu[0-9]" lines.
230         if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) {
231             free(line);
232             line = NULL;
233             len = 0;
234             continue;
235         }
236 
237         vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user,
238                 &nice, &system, &idle);
239 
240         free(line);
241         line = NULL;
242         len = 0;
243 
244         if (vals != 5 || size == kCpuNum) {
245             if (vals != 5) {
246                 PLOG(ERROR) << "fillCpuUsages: failed to read CPU information from file ("
247                             << kCpuUsageFile << ")";
248             } else {
249                 PLOG(ERROR) << "fillCpuUsages: file has incorrect format ("
250                             << kCpuUsageFile << ")";
251             }
252             fclose(file);
253             return errno ? -errno : -EIO;
254         }
255 
256         active = user + nice + system;
257         total = active + idle;
258 
259         // Read online CPU information.
260         snprintf(file_name, PATH_MAX, kCpuOnlineFileFormat, cpu_num);
261         cpu_file = fopen(file_name, "r");
262         online = 0;
263         if (cpu_file == NULL) {
264             PLOG(ERROR) << "fillCpuUsages: failed to open file (" << file_name << ")";
265             fclose(file);
266             return -errno;
267         }
268         if (1 != fscanf(cpu_file, "%d", &online)) {
269             PLOG(ERROR) << "fillCpuUsages: failed to read CPU online information from file ("
270                         << file_name << ")";
271             fclose(file);
272             fclose(cpu_file);
273             return errno ? -errno : -EIO;
274         }
275         fclose(cpu_file);
276 
277         (*cpuUsages)[size].name = kCpuLabel[size];
278         (*cpuUsages)[size].active = active;
279         (*cpuUsages)[size].total = total;
280         (*cpuUsages)[size].isOnline = static_cast<bool>(online);
281 
282         LOG(DEBUG) << "fillCpuUsages: "<< kCpuLabel[size] << ": "
283                    << active << " " << total << " " <<  online;
284         size++;
285     }
286     fclose(file);
287 
288     if (size != kCpuNum) {
289         PLOG(ERROR) << "fillCpuUsages: file has incorrect format (" << kCpuUsageFile << ")";
290         return -EIO;
291     }
292     return kCpuNum;
293 }
294 
getTargetSkinSensorType()295 std::string getTargetSkinSensorType() {
296     return gSkinSensorType;
297 }
298 
299 }  // namespace implementation
300 }  // namespace V1_1
301 }  // namespace thermal
302 }  // namespace hardware
303 }  // namespace android
304