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 */ 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 */ 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 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 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 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 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