1 /* 2 * Copyright (C) 2013 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 #define LOG_TAG "healthd" 18 19 #include <healthd/healthd.h> 20 #include <healthd/BatteryMonitor.h> 21 22 #include <dirent.h> 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <sys/types.h> 28 #include <unistd.h> 29 #include <memory> 30 31 #include <android-base/file.h> 32 #include <android-base/parseint.h> 33 #include <android-base/strings.h> 34 #include <batteryservice/BatteryService.h> 35 #include <cutils/klog.h> 36 #include <cutils/properties.h> 37 #include <utils/Errors.h> 38 #include <utils/String8.h> 39 #include <utils/Vector.h> 40 41 #define POWER_SUPPLY_SUBSYSTEM "power_supply" 42 #define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM 43 #define FAKE_BATTERY_CAPACITY 42 44 #define FAKE_BATTERY_TEMPERATURE 424 45 #define ALWAYS_PLUGGED_CAPACITY 100 46 #define MILLION 1.0e6 47 #define DEFAULT_VBUS_VOLTAGE 5000000 48 49 namespace android { 50 51 struct sysfsStringEnumMap { 52 const char* s; 53 int val; 54 }; 55 56 static int mapSysfsString(const char* str, 57 struct sysfsStringEnumMap map[]) { 58 for (int i = 0; map[i].s; i++) 59 if (!strcmp(str, map[i].s)) 60 return map[i].val; 61 62 return -1; 63 } 64 65 static void initBatteryProperties(BatteryProperties* props) { 66 props->chargerAcOnline = false; 67 props->chargerUsbOnline = false; 68 props->chargerWirelessOnline = false; 69 props->maxChargingCurrent = 0; 70 props->maxChargingVoltage = 0; 71 props->batteryStatus = BATTERY_STATUS_UNKNOWN; 72 props->batteryHealth = BATTERY_HEALTH_UNKNOWN; 73 props->batteryPresent = false; 74 props->batteryLevel = 0; 75 props->batteryVoltage = 0; 76 props->batteryTemperature = 0; 77 props->batteryCurrent = 0; 78 props->batteryCycleCount = 0; 79 props->batteryFullCharge = 0; 80 props->batteryChargeCounter = 0; 81 props->batteryTechnology.clear(); 82 } 83 84 BatteryMonitor::BatteryMonitor() : mHealthdConfig(nullptr), mBatteryDevicePresent(false), 85 mAlwaysPluggedDevice(false), mBatteryFixedCapacity(0), mBatteryFixedTemperature(0) { 86 initBatteryProperties(&props); 87 } 88 89 int BatteryMonitor::getBatteryStatus(const char* status) { 90 int ret; 91 struct sysfsStringEnumMap batteryStatusMap[] = { 92 { "Unknown", BATTERY_STATUS_UNKNOWN }, 93 { "Charging", BATTERY_STATUS_CHARGING }, 94 { "Discharging", BATTERY_STATUS_DISCHARGING }, 95 { "Not charging", BATTERY_STATUS_NOT_CHARGING }, 96 { "Full", BATTERY_STATUS_FULL }, 97 { NULL, 0 }, 98 }; 99 100 ret = mapSysfsString(status, batteryStatusMap); 101 if (ret < 0) { 102 KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status); 103 ret = BATTERY_STATUS_UNKNOWN; 104 } 105 106 return ret; 107 } 108 109 int BatteryMonitor::getBatteryHealth(const char* status) { 110 int ret; 111 struct sysfsStringEnumMap batteryHealthMap[] = { 112 { "Unknown", BATTERY_HEALTH_UNKNOWN }, 113 { "Good", BATTERY_HEALTH_GOOD }, 114 { "Overheat", BATTERY_HEALTH_OVERHEAT }, 115 { "Dead", BATTERY_HEALTH_DEAD }, 116 { "Over voltage", BATTERY_HEALTH_OVER_VOLTAGE }, 117 { "Unspecified failure", BATTERY_HEALTH_UNSPECIFIED_FAILURE }, 118 { "Cold", BATTERY_HEALTH_COLD }, 119 { NULL, 0 }, 120 }; 121 122 ret = mapSysfsString(status, batteryHealthMap); 123 if (ret < 0) { 124 KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status); 125 ret = BATTERY_HEALTH_UNKNOWN; 126 } 127 128 return ret; 129 } 130 131 int BatteryMonitor::readFromFile(const String8& path, std::string* buf) { 132 if (android::base::ReadFileToString(path.c_str(), buf)) { 133 *buf = android::base::Trim(*buf); 134 } 135 return buf->length(); 136 } 137 138 BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) { 139 std::string buf; 140 BatteryMonitor::PowerSupplyType ret; 141 struct sysfsStringEnumMap supplyTypeMap[] = { 142 { "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN }, 143 { "Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY }, 144 { "UPS", ANDROID_POWER_SUPPLY_TYPE_AC }, 145 { "Mains", ANDROID_POWER_SUPPLY_TYPE_AC }, 146 { "USB", ANDROID_POWER_SUPPLY_TYPE_USB }, 147 { "USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC }, 148 { "USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC }, 149 { "USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC }, 150 { "USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC }, 151 { "USB_C", ANDROID_POWER_SUPPLY_TYPE_AC }, 152 { "USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC }, 153 { "USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB }, 154 { "Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS }, 155 { NULL, 0 }, 156 }; 157 158 if (readFromFile(path, &buf) <= 0) 159 return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN; 160 161 ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf.c_str(), supplyTypeMap); 162 if (ret < 0) { 163 KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str()); 164 ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN; 165 } 166 167 return ret; 168 } 169 170 bool BatteryMonitor::getBooleanField(const String8& path) { 171 std::string buf; 172 bool value = false; 173 174 if (readFromFile(path, &buf) > 0) 175 if (buf[0] != '0') 176 value = true; 177 178 return value; 179 } 180 181 int BatteryMonitor::getIntField(const String8& path) { 182 std::string buf; 183 int value = 0; 184 185 if (readFromFile(path, &buf) > 0) 186 android::base::ParseInt(buf, &value); 187 188 return value; 189 } 190 191 bool BatteryMonitor::update(void) { 192 bool logthis; 193 194 initBatteryProperties(&props); 195 196 if (!mHealthdConfig->batteryPresentPath.isEmpty()) 197 props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath); 198 else 199 props.batteryPresent = mBatteryDevicePresent; 200 201 props.batteryLevel = mBatteryFixedCapacity ? 202 mBatteryFixedCapacity : 203 getIntField(mHealthdConfig->batteryCapacityPath); 204 props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000; 205 206 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) 207 props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath) / 1000; 208 209 if (!mHealthdConfig->batteryFullChargePath.isEmpty()) 210 props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath); 211 212 if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) 213 props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath); 214 215 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) 216 props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath); 217 218 props.batteryTemperature = mBatteryFixedTemperature ? 219 mBatteryFixedTemperature : 220 getIntField(mHealthdConfig->batteryTemperaturePath); 221 222 // For devices which do not have battery and are always plugged 223 // into power souce. 224 if (mAlwaysPluggedDevice) { 225 props.chargerAcOnline = true; 226 props.batteryPresent = true; 227 props.batteryStatus = BATTERY_STATUS_CHARGING; 228 props.batteryHealth = BATTERY_HEALTH_GOOD; 229 } 230 231 std::string buf; 232 233 if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0) 234 props.batteryStatus = getBatteryStatus(buf.c_str()); 235 236 if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0) 237 props.batteryHealth = getBatteryHealth(buf.c_str()); 238 239 if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0) 240 props.batteryTechnology = String8(buf.c_str()); 241 242 unsigned int i; 243 double MaxPower = 0; 244 245 for (i = 0; i < mChargerNames.size(); i++) { 246 String8 path; 247 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, 248 mChargerNames[i].string()); 249 if (getIntField(path)) { 250 path.clear(); 251 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, 252 mChargerNames[i].string()); 253 switch(readPowerSupplyType(path)) { 254 case ANDROID_POWER_SUPPLY_TYPE_AC: 255 props.chargerAcOnline = true; 256 break; 257 case ANDROID_POWER_SUPPLY_TYPE_USB: 258 props.chargerUsbOnline = true; 259 break; 260 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS: 261 props.chargerWirelessOnline = true; 262 break; 263 default: 264 KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n", 265 mChargerNames[i].string()); 266 } 267 path.clear(); 268 path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH, 269 mChargerNames[i].string()); 270 int ChargingCurrent = 271 (access(path.string(), R_OK) == 0) ? getIntField(path) : 0; 272 273 path.clear(); 274 path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH, 275 mChargerNames[i].string()); 276 277 int ChargingVoltage = 278 (access(path.string(), R_OK) == 0) ? getIntField(path) : 279 DEFAULT_VBUS_VOLTAGE; 280 281 double power = ((double)ChargingCurrent / MILLION) * 282 ((double)ChargingVoltage / MILLION); 283 if (MaxPower < power) { 284 props.maxChargingCurrent = ChargingCurrent; 285 props.maxChargingVoltage = ChargingVoltage; 286 MaxPower = power; 287 } 288 } 289 } 290 291 logthis = !healthd_board_battery_update(&props); 292 293 if (logthis) { 294 char dmesgline[256]; 295 size_t len; 296 if (props.batteryPresent) { 297 snprintf(dmesgline, sizeof(dmesgline), 298 "battery l=%d v=%d t=%s%d.%d h=%d st=%d", 299 props.batteryLevel, props.batteryVoltage, 300 props.batteryTemperature < 0 ? "-" : "", 301 abs(props.batteryTemperature / 10), 302 abs(props.batteryTemperature % 10), props.batteryHealth, 303 props.batteryStatus); 304 305 len = strlen(dmesgline); 306 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { 307 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, 308 " c=%d", props.batteryCurrent); 309 } 310 311 if (!mHealthdConfig->batteryFullChargePath.isEmpty()) { 312 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, 313 " fc=%d", props.batteryFullCharge); 314 } 315 316 if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) { 317 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, 318 " cc=%d", props.batteryCycleCount); 319 } 320 } else { 321 len = snprintf(dmesgline, sizeof(dmesgline), 322 "battery none"); 323 } 324 325 snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s", 326 props.chargerAcOnline ? "a" : "", 327 props.chargerUsbOnline ? "u" : "", 328 props.chargerWirelessOnline ? "w" : ""); 329 330 KLOG_WARNING(LOG_TAG, "%s\n", dmesgline); 331 } 332 333 healthd_mode_ops->battery_update(&props); 334 return props.chargerAcOnline | props.chargerUsbOnline | 335 props.chargerWirelessOnline; 336 } 337 338 int BatteryMonitor::getChargeStatus() { 339 int result = BATTERY_STATUS_UNKNOWN; 340 if (!mHealthdConfig->batteryStatusPath.isEmpty()) { 341 std::string buf; 342 if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0) 343 result = getBatteryStatus(buf.c_str()); 344 } 345 return result; 346 } 347 348 status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { 349 status_t ret = BAD_VALUE; 350 std::string buf; 351 352 val->valueInt64 = LONG_MIN; 353 354 switch(id) { 355 case BATTERY_PROP_CHARGE_COUNTER: 356 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) { 357 val->valueInt64 = 358 getIntField(mHealthdConfig->batteryChargeCounterPath); 359 ret = NO_ERROR; 360 } else { 361 ret = NAME_NOT_FOUND; 362 } 363 break; 364 365 case BATTERY_PROP_CURRENT_NOW: 366 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { 367 val->valueInt64 = 368 getIntField(mHealthdConfig->batteryCurrentNowPath); 369 ret = NO_ERROR; 370 } else { 371 ret = NAME_NOT_FOUND; 372 } 373 break; 374 375 case BATTERY_PROP_CURRENT_AVG: 376 if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { 377 val->valueInt64 = 378 getIntField(mHealthdConfig->batteryCurrentAvgPath); 379 ret = NO_ERROR; 380 } else { 381 ret = NAME_NOT_FOUND; 382 } 383 break; 384 385 case BATTERY_PROP_CAPACITY: 386 if (!mHealthdConfig->batteryCapacityPath.isEmpty()) { 387 val->valueInt64 = 388 getIntField(mHealthdConfig->batteryCapacityPath); 389 ret = NO_ERROR; 390 } else { 391 ret = NAME_NOT_FOUND; 392 } 393 break; 394 395 case BATTERY_PROP_ENERGY_COUNTER: 396 if (mHealthdConfig->energyCounter) { 397 ret = mHealthdConfig->energyCounter(&val->valueInt64); 398 } else { 399 ret = NAME_NOT_FOUND; 400 } 401 break; 402 403 case BATTERY_PROP_BATTERY_STATUS: 404 if (mAlwaysPluggedDevice) { 405 val->valueInt64 = BATTERY_STATUS_CHARGING; 406 } else { 407 val->valueInt64 = getChargeStatus(); 408 } 409 ret = NO_ERROR; 410 break; 411 412 default: 413 break; 414 } 415 416 return ret; 417 } 418 419 void BatteryMonitor::dumpState(int fd) { 420 int v; 421 char vs[128]; 422 423 snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d voltage_max: %d\n", 424 props.chargerAcOnline, props.chargerUsbOnline, 425 props.chargerWirelessOnline, props.maxChargingCurrent, 426 props.maxChargingVoltage); 427 write(fd, vs, strlen(vs)); 428 snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n", 429 props.batteryStatus, props.batteryHealth, props.batteryPresent); 430 write(fd, vs, strlen(vs)); 431 snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n", 432 props.batteryLevel, props.batteryVoltage, 433 props.batteryTemperature); 434 write(fd, vs, strlen(vs)); 435 436 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { 437 v = getIntField(mHealthdConfig->batteryCurrentNowPath); 438 snprintf(vs, sizeof(vs), "current now: %d\n", v); 439 write(fd, vs, strlen(vs)); 440 } 441 442 if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { 443 v = getIntField(mHealthdConfig->batteryCurrentAvgPath); 444 snprintf(vs, sizeof(vs), "current avg: %d\n", v); 445 write(fd, vs, strlen(vs)); 446 } 447 448 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) { 449 v = getIntField(mHealthdConfig->batteryChargeCounterPath); 450 snprintf(vs, sizeof(vs), "charge counter: %d\n", v); 451 write(fd, vs, strlen(vs)); 452 } 453 454 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { 455 snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrent); 456 write(fd, vs, strlen(vs)); 457 } 458 459 if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) { 460 snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount); 461 write(fd, vs, strlen(vs)); 462 } 463 464 if (!mHealthdConfig->batteryFullChargePath.isEmpty()) { 465 snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullCharge); 466 write(fd, vs, strlen(vs)); 467 } 468 } 469 470 void BatteryMonitor::init(struct healthd_config *hc) { 471 String8 path; 472 char pval[PROPERTY_VALUE_MAX]; 473 474 mHealthdConfig = hc; 475 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir); 476 if (dir == NULL) { 477 KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH); 478 } else { 479 struct dirent* entry; 480 481 while ((entry = readdir(dir.get()))) { 482 const char* name = entry->d_name; 483 484 if (!strcmp(name, ".") || !strcmp(name, "..")) 485 continue; 486 487 // Look for "type" file in each subdirectory 488 path.clear(); 489 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name); 490 switch(readPowerSupplyType(path)) { 491 case ANDROID_POWER_SUPPLY_TYPE_AC: 492 case ANDROID_POWER_SUPPLY_TYPE_USB: 493 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS: 494 path.clear(); 495 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); 496 if (access(path.string(), R_OK) == 0) 497 mChargerNames.add(String8(name)); 498 break; 499 500 case ANDROID_POWER_SUPPLY_TYPE_BATTERY: 501 mBatteryDevicePresent = true; 502 503 if (mHealthdConfig->batteryStatusPath.isEmpty()) { 504 path.clear(); 505 path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH, 506 name); 507 if (access(path, R_OK) == 0) 508 mHealthdConfig->batteryStatusPath = path; 509 } 510 511 if (mHealthdConfig->batteryHealthPath.isEmpty()) { 512 path.clear(); 513 path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, 514 name); 515 if (access(path, R_OK) == 0) 516 mHealthdConfig->batteryHealthPath = path; 517 } 518 519 if (mHealthdConfig->batteryPresentPath.isEmpty()) { 520 path.clear(); 521 path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH, 522 name); 523 if (access(path, R_OK) == 0) 524 mHealthdConfig->batteryPresentPath = path; 525 } 526 527 if (mHealthdConfig->batteryCapacityPath.isEmpty()) { 528 path.clear(); 529 path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH, 530 name); 531 if (access(path, R_OK) == 0) 532 mHealthdConfig->batteryCapacityPath = path; 533 } 534 535 if (mHealthdConfig->batteryVoltagePath.isEmpty()) { 536 path.clear(); 537 path.appendFormat("%s/%s/voltage_now", 538 POWER_SUPPLY_SYSFS_PATH, name); 539 if (access(path, R_OK) == 0) { 540 mHealthdConfig->batteryVoltagePath = path; 541 } else { 542 path.clear(); 543 path.appendFormat("%s/%s/batt_vol", 544 POWER_SUPPLY_SYSFS_PATH, name); 545 if (access(path, R_OK) == 0) 546 mHealthdConfig->batteryVoltagePath = path; 547 } 548 } 549 550 if (mHealthdConfig->batteryFullChargePath.isEmpty()) { 551 path.clear(); 552 path.appendFormat("%s/%s/charge_full", 553 POWER_SUPPLY_SYSFS_PATH, name); 554 if (access(path, R_OK) == 0) 555 mHealthdConfig->batteryFullChargePath = path; 556 } 557 558 if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) { 559 path.clear(); 560 path.appendFormat("%s/%s/current_now", 561 POWER_SUPPLY_SYSFS_PATH, name); 562 if (access(path, R_OK) == 0) 563 mHealthdConfig->batteryCurrentNowPath = path; 564 } 565 566 if (mHealthdConfig->batteryCycleCountPath.isEmpty()) { 567 path.clear(); 568 path.appendFormat("%s/%s/cycle_count", 569 POWER_SUPPLY_SYSFS_PATH, name); 570 if (access(path, R_OK) == 0) 571 mHealthdConfig->batteryCycleCountPath = path; 572 } 573 574 if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { 575 path.clear(); 576 path.appendFormat("%s/%s/current_avg", 577 POWER_SUPPLY_SYSFS_PATH, name); 578 if (access(path, R_OK) == 0) 579 mHealthdConfig->batteryCurrentAvgPath = path; 580 } 581 582 if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) { 583 path.clear(); 584 path.appendFormat("%s/%s/charge_counter", 585 POWER_SUPPLY_SYSFS_PATH, name); 586 if (access(path, R_OK) == 0) 587 mHealthdConfig->batteryChargeCounterPath = path; 588 } 589 590 if (mHealthdConfig->batteryTemperaturePath.isEmpty()) { 591 path.clear(); 592 path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH, 593 name); 594 if (access(path, R_OK) == 0) { 595 mHealthdConfig->batteryTemperaturePath = path; 596 } else { 597 path.clear(); 598 path.appendFormat("%s/%s/batt_temp", 599 POWER_SUPPLY_SYSFS_PATH, name); 600 if (access(path, R_OK) == 0) 601 mHealthdConfig->batteryTemperaturePath = path; 602 } 603 } 604 605 if (mHealthdConfig->batteryTechnologyPath.isEmpty()) { 606 path.clear(); 607 path.appendFormat("%s/%s/technology", 608 POWER_SUPPLY_SYSFS_PATH, name); 609 if (access(path, R_OK) == 0) 610 mHealthdConfig->batteryTechnologyPath = path; 611 } 612 613 break; 614 615 case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN: 616 break; 617 } 618 } 619 } 620 621 // Typically the case for devices which do not have a battery and 622 // and are always plugged into AC mains. 623 if (!mBatteryDevicePresent) { 624 KLOG_WARNING(LOG_TAG, "No battery devices found\n"); 625 hc->periodic_chores_interval_fast = -1; 626 hc->periodic_chores_interval_slow = -1; 627 mBatteryFixedCapacity = ALWAYS_PLUGGED_CAPACITY; 628 mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE; 629 mAlwaysPluggedDevice = true; 630 } else { 631 if (mHealthdConfig->batteryStatusPath.isEmpty()) 632 KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n"); 633 if (mHealthdConfig->batteryHealthPath.isEmpty()) 634 KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n"); 635 if (mHealthdConfig->batteryPresentPath.isEmpty()) 636 KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n"); 637 if (mHealthdConfig->batteryCapacityPath.isEmpty()) 638 KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n"); 639 if (mHealthdConfig->batteryVoltagePath.isEmpty()) 640 KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n"); 641 if (mHealthdConfig->batteryTemperaturePath.isEmpty()) 642 KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n"); 643 if (mHealthdConfig->batteryTechnologyPath.isEmpty()) 644 KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n"); 645 if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) 646 KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n"); 647 if (mHealthdConfig->batteryFullChargePath.isEmpty()) 648 KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n"); 649 if (mHealthdConfig->batteryCycleCountPath.isEmpty()) 650 KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n"); 651 } 652 653 if (property_get("ro.boot.fake_battery", pval, NULL) > 0 654 && strtol(pval, NULL, 10) != 0) { 655 mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY; 656 mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE; 657 } 658 } 659 660 }; // namespace android 661