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