• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
30 #include <algorithm>
31 #include <memory>
32 #include <optional>
33 
34 #include <android-base/file.h>
35 #include <android-base/parseint.h>
36 #include <android-base/strings.h>
37 #include <android/hardware/health/2.1/types.h>
38 #include <batteryservice/BatteryService.h>
39 #include <cutils/klog.h>
40 #include <cutils/properties.h>
41 #include <utils/Errors.h>
42 #include <utils/String8.h>
43 #include <utils/Vector.h>
44 
45 #define POWER_SUPPLY_SUBSYSTEM "power_supply"
46 #define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
47 #define FAKE_BATTERY_CAPACITY 42
48 #define FAKE_BATTERY_TEMPERATURE 424
49 #define MILLION 1.0e6
50 #define DEFAULT_VBUS_VOLTAGE 5000000
51 
52 using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
53 using HealthInfo_2_0 = android::hardware::health::V2_0::HealthInfo;
54 using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
55 using android::hardware::health::V1_0::BatteryHealth;
56 using android::hardware::health::V1_0::BatteryStatus;
57 using android::hardware::health::V2_1::BatteryCapacityLevel;
58 using android::hardware::health::V2_1::Constants;
59 
60 namespace android {
61 
62 template <typename T>
63 struct SysfsStringEnumMap {
64     const char* s;
65     T val;
66 };
67 
68 template <typename T>
mapSysfsString(const char * str,SysfsStringEnumMap<T> map[])69 static std::optional<T> mapSysfsString(const char* str, SysfsStringEnumMap<T> map[]) {
70     for (int i = 0; map[i].s; i++)
71         if (!strcmp(str, map[i].s))
72             return map[i].val;
73 
74     return std::nullopt;
75 }
76 
initHealthInfo(HealthInfo_2_1 * health_info_2_1)77 static void initHealthInfo(HealthInfo_2_1* health_info_2_1) {
78     *health_info_2_1 = HealthInfo_2_1{};
79 
80     // HIDL enum values are zero initialized, so they need to be initialized
81     // properly.
82     health_info_2_1->batteryCapacityLevel = BatteryCapacityLevel::UNSUPPORTED;
83     health_info_2_1->batteryChargeTimeToFullNowSeconds =
84             (int64_t)Constants::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
85     auto* props = &health_info_2_1->legacy.legacy;
86     props->batteryStatus = BatteryStatus::UNKNOWN;
87     props->batteryHealth = BatteryHealth::UNKNOWN;
88 }
89 
BatteryMonitor()90 BatteryMonitor::BatteryMonitor()
91     : mHealthdConfig(nullptr),
92       mBatteryDevicePresent(false),
93       mBatteryFixedCapacity(0),
94       mBatteryFixedTemperature(0),
95       mHealthInfo(std::make_unique<HealthInfo_2_1>()) {
96     initHealthInfo(mHealthInfo.get());
97 }
98 
~BatteryMonitor()99 BatteryMonitor::~BatteryMonitor() {}
100 
getHealthInfo_1_0() const101 const HealthInfo_1_0& BatteryMonitor::getHealthInfo_1_0() const {
102     return getHealthInfo_2_0().legacy;
103 }
104 
getHealthInfo_2_0() const105 const HealthInfo_2_0& BatteryMonitor::getHealthInfo_2_0() const {
106     return getHealthInfo_2_1().legacy;
107 }
108 
getHealthInfo_2_1() const109 const HealthInfo_2_1& BatteryMonitor::getHealthInfo_2_1() const {
110     return *mHealthInfo;
111 }
112 
getBatteryStatus(const char * status)113 BatteryStatus getBatteryStatus(const char* status) {
114     static SysfsStringEnumMap<BatteryStatus> batteryStatusMap[] = {
115             {"Unknown", BatteryStatus::UNKNOWN},
116             {"Charging", BatteryStatus::CHARGING},
117             {"Discharging", BatteryStatus::DISCHARGING},
118             {"Not charging", BatteryStatus::NOT_CHARGING},
119             {"Full", BatteryStatus::FULL},
120             {NULL, BatteryStatus::UNKNOWN},
121     };
122 
123     auto ret = mapSysfsString(status, batteryStatusMap);
124     if (!ret) {
125         KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status);
126         *ret = BatteryStatus::UNKNOWN;
127     }
128 
129     return *ret;
130 }
131 
getBatteryCapacityLevel(const char * capacityLevel)132 BatteryCapacityLevel getBatteryCapacityLevel(const char* capacityLevel) {
133     static SysfsStringEnumMap<BatteryCapacityLevel> batteryCapacityLevelMap[] = {
134             {"Unknown", BatteryCapacityLevel::UNKNOWN},
135             {"Critical", BatteryCapacityLevel::CRITICAL},
136             {"Low", BatteryCapacityLevel::LOW},
137             {"Normal", BatteryCapacityLevel::NORMAL},
138             {"High", BatteryCapacityLevel::HIGH},
139             {"Full", BatteryCapacityLevel::FULL},
140             {NULL, BatteryCapacityLevel::UNSUPPORTED},
141     };
142 
143     auto ret = mapSysfsString(capacityLevel, batteryCapacityLevelMap);
144     if (!ret) {
145         KLOG_WARNING(LOG_TAG, "Unsupported battery capacity level '%s'\n", capacityLevel);
146         *ret = BatteryCapacityLevel::UNSUPPORTED;
147     }
148 
149     return *ret;
150 }
151 
getBatteryHealth(const char * status)152 BatteryHealth getBatteryHealth(const char* status) {
153     static SysfsStringEnumMap<BatteryHealth> batteryHealthMap[] = {
154             {"Unknown", BatteryHealth::UNKNOWN},
155             {"Good", BatteryHealth::GOOD},
156             {"Overheat", BatteryHealth::OVERHEAT},
157             {"Dead", BatteryHealth::DEAD},
158             {"Over voltage", BatteryHealth::OVER_VOLTAGE},
159             {"Unspecified failure", BatteryHealth::UNSPECIFIED_FAILURE},
160             {"Cold", BatteryHealth::COLD},
161             // battery health values from JEITA spec
162             {"Warm", BatteryHealth::GOOD},
163             {"Cool", BatteryHealth::GOOD},
164             {"Hot", BatteryHealth::OVERHEAT},
165             {NULL, BatteryHealth::UNKNOWN},
166     };
167 
168     auto ret = mapSysfsString(status, batteryHealthMap);
169     if (!ret) {
170         KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status);
171         *ret = BatteryHealth::UNKNOWN;
172     }
173 
174     return *ret;
175 }
176 
readFromFile(const String8 & path,std::string * buf)177 int BatteryMonitor::readFromFile(const String8& path, std::string* buf) {
178     if (android::base::ReadFileToString(path.c_str(), buf)) {
179         *buf = android::base::Trim(*buf);
180     }
181     return buf->length();
182 }
183 
readPowerSupplyType(const String8 & path)184 BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
185     static SysfsStringEnumMap<int> supplyTypeMap[] = {
186             {"Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN},
187             {"Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY},
188             {"UPS", ANDROID_POWER_SUPPLY_TYPE_AC},
189             {"Mains", ANDROID_POWER_SUPPLY_TYPE_AC},
190             {"USB", ANDROID_POWER_SUPPLY_TYPE_USB},
191             {"USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC},
192             {"USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC},
193             {"USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC},
194             {"USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC},
195             {"USB_C", ANDROID_POWER_SUPPLY_TYPE_AC},
196             {"USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC},
197             {"USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB},
198             {"Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS},
199             {NULL, 0},
200     };
201     std::string buf;
202 
203     if (readFromFile(path, &buf) <= 0)
204         return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
205 
206     auto ret = mapSysfsString(buf.c_str(), supplyTypeMap);
207     if (!ret) {
208         KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
209         *ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
210     }
211 
212     return static_cast<BatteryMonitor::PowerSupplyType>(*ret);
213 }
214 
getBooleanField(const String8 & path)215 bool BatteryMonitor::getBooleanField(const String8& path) {
216     std::string buf;
217     bool value = false;
218 
219     if (readFromFile(path, &buf) > 0)
220         if (buf[0] != '0')
221             value = true;
222 
223     return value;
224 }
225 
getIntField(const String8 & path)226 int BatteryMonitor::getIntField(const String8& path) {
227     std::string buf;
228     int value = 0;
229 
230     if (readFromFile(path, &buf) > 0)
231         android::base::ParseInt(buf, &value);
232 
233     return value;
234 }
235 
isScopedPowerSupply(const char * name)236 bool BatteryMonitor::isScopedPowerSupply(const char* name) {
237     constexpr char kScopeDevice[] = "Device";
238 
239     String8 path;
240     path.appendFormat("%s/%s/scope", POWER_SUPPLY_SYSFS_PATH, name);
241     std::string scope;
242     return (readFromFile(path, &scope) > 0 && scope == kScopeDevice);
243 }
244 
updateValues(void)245 void BatteryMonitor::updateValues(void) {
246     initHealthInfo(mHealthInfo.get());
247 
248     HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
249 
250     if (!mHealthdConfig->batteryPresentPath.isEmpty())
251         props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
252     else
253         props.batteryPresent = mBatteryDevicePresent;
254 
255     props.batteryLevel = mBatteryFixedCapacity ?
256         mBatteryFixedCapacity :
257         getIntField(mHealthdConfig->batteryCapacityPath);
258     props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
259 
260     if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
261         props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath);
262 
263     if (!mHealthdConfig->batteryFullChargePath.isEmpty())
264         props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath);
265 
266     if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
267         props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
268 
269     if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
270         props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
271 
272     if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty())
273         mHealthInfo->legacy.batteryCurrentAverage =
274                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
275 
276     if (!mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
277         mHealthInfo->batteryChargeTimeToFullNowSeconds =
278                 getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath);
279 
280     if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
281         mHealthInfo->batteryFullChargeDesignCapacityUah =
282                 getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
283 
284     props.batteryTemperature = mBatteryFixedTemperature ?
285         mBatteryFixedTemperature :
286         getIntField(mHealthdConfig->batteryTemperaturePath);
287 
288     std::string buf;
289 
290     if (readFromFile(mHealthdConfig->batteryCapacityLevelPath, &buf) > 0)
291         mHealthInfo->batteryCapacityLevel = getBatteryCapacityLevel(buf.c_str());
292 
293     if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
294         props.batteryStatus = getBatteryStatus(buf.c_str());
295 
296     if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
297         props.batteryHealth = getBatteryHealth(buf.c_str());
298 
299     if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
300         props.batteryTechnology = String8(buf.c_str());
301 
302     double MaxPower = 0;
303 
304     for (size_t i = 0; i < mChargerNames.size(); i++) {
305         String8 path;
306         path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
307                           mChargerNames[i].string());
308         if (getIntField(path)) {
309             path.clear();
310             path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
311                               mChargerNames[i].string());
312             switch(readPowerSupplyType(path)) {
313             case ANDROID_POWER_SUPPLY_TYPE_AC:
314                 props.chargerAcOnline = true;
315                 break;
316             case ANDROID_POWER_SUPPLY_TYPE_USB:
317                 props.chargerUsbOnline = true;
318                 break;
319             case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
320                 props.chargerWirelessOnline = true;
321                 break;
322             default:
323                 KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
324                              mChargerNames[i].string());
325             }
326             path.clear();
327             path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
328                               mChargerNames[i].string());
329             int ChargingCurrent =
330                     (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
331 
332             path.clear();
333             path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
334                               mChargerNames[i].string());
335 
336             int ChargingVoltage =
337                 (access(path.string(), R_OK) == 0) ? getIntField(path) :
338                 DEFAULT_VBUS_VOLTAGE;
339 
340             double power = ((double)ChargingCurrent / MILLION) *
341                            ((double)ChargingVoltage / MILLION);
342             if (MaxPower < power) {
343                 props.maxChargingCurrent = ChargingCurrent;
344                 props.maxChargingVoltage = ChargingVoltage;
345                 MaxPower = power;
346             }
347         }
348     }
349 }
350 
logValues(void)351 void BatteryMonitor::logValues(void) {
352     logValues(*mHealthInfo, *mHealthdConfig);
353 }
354 
logValues(const android::hardware::health::V2_1::HealthInfo & health_info,const struct healthd_config & healthd_config)355 void BatteryMonitor::logValues(const android::hardware::health::V2_1::HealthInfo& health_info,
356                                const struct healthd_config& healthd_config) {
357     char dmesgline[256];
358     size_t len;
359     const HealthInfo_1_0& props = health_info.legacy.legacy;
360     if (props.batteryPresent) {
361         snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
362                  props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "",
363                  abs(props.batteryTemperature / 10), abs(props.batteryTemperature % 10),
364                  props.batteryHealth, props.batteryStatus);
365 
366         len = strlen(dmesgline);
367         if (!healthd_config.batteryCurrentNowPath.isEmpty()) {
368             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
369                             props.batteryCurrent);
370         }
371 
372         if (!healthd_config.batteryFullChargePath.isEmpty()) {
373             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
374                             props.batteryFullCharge);
375         }
376 
377         if (!healthd_config.batteryCycleCountPath.isEmpty()) {
378             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
379                             props.batteryCycleCount);
380         }
381     } else {
382         len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
383     }
384 
385     snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
386              props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
387              props.chargerWirelessOnline ? "w" : "");
388 
389     KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
390 }
391 
isChargerOnline()392 bool BatteryMonitor::isChargerOnline() {
393     const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
394     return props.chargerAcOnline | props.chargerUsbOnline |
395             props.chargerWirelessOnline;
396 }
397 
getChargeStatus()398 int BatteryMonitor::getChargeStatus() {
399     BatteryStatus result = BatteryStatus::UNKNOWN;
400     if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
401         std::string buf;
402         if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
403             result = getBatteryStatus(buf.c_str());
404     }
405     return static_cast<int>(result);
406 }
407 
getProperty(int id,struct BatteryProperty * val)408 status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
409     status_t ret = BAD_VALUE;
410     std::string buf;
411 
412     val->valueInt64 = LONG_MIN;
413 
414     switch(id) {
415     case BATTERY_PROP_CHARGE_COUNTER:
416         if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
417             val->valueInt64 =
418                 getIntField(mHealthdConfig->batteryChargeCounterPath);
419             ret = OK;
420         } else {
421             ret = NAME_NOT_FOUND;
422         }
423         break;
424 
425     case BATTERY_PROP_CURRENT_NOW:
426         if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
427             val->valueInt64 =
428                 getIntField(mHealthdConfig->batteryCurrentNowPath);
429             ret = OK;
430         } else {
431             ret = NAME_NOT_FOUND;
432         }
433         break;
434 
435     case BATTERY_PROP_CURRENT_AVG:
436         if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
437             val->valueInt64 =
438                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
439             ret = OK;
440         } else {
441             ret = NAME_NOT_FOUND;
442         }
443         break;
444 
445     case BATTERY_PROP_CAPACITY:
446         if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
447             val->valueInt64 =
448                 getIntField(mHealthdConfig->batteryCapacityPath);
449             ret = OK;
450         } else {
451             ret = NAME_NOT_FOUND;
452         }
453         break;
454 
455     case BATTERY_PROP_ENERGY_COUNTER:
456         if (mHealthdConfig->energyCounter) {
457             ret = mHealthdConfig->energyCounter(&val->valueInt64);
458         } else {
459             ret = NAME_NOT_FOUND;
460         }
461         break;
462 
463     case BATTERY_PROP_BATTERY_STATUS:
464         val->valueInt64 = getChargeStatus();
465         ret = OK;
466         break;
467 
468     default:
469         break;
470     }
471 
472     return ret;
473 }
474 
dumpState(int fd)475 void BatteryMonitor::dumpState(int fd) {
476     int v;
477     char vs[128];
478     const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
479 
480     snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d voltage_max: %d\n",
481              props.chargerAcOnline, props.chargerUsbOnline,
482              props.chargerWirelessOnline, props.maxChargingCurrent,
483              props.maxChargingVoltage);
484     write(fd, vs, strlen(vs));
485     snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
486              props.batteryStatus, props.batteryHealth, props.batteryPresent);
487     write(fd, vs, strlen(vs));
488     snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n",
489              props.batteryLevel, props.batteryVoltage,
490              props.batteryTemperature);
491     write(fd, vs, strlen(vs));
492 
493     if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
494         v = getIntField(mHealthdConfig->batteryCurrentNowPath);
495         snprintf(vs, sizeof(vs), "current now: %d\n", v);
496         write(fd, vs, strlen(vs));
497     }
498 
499     if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
500         v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
501         snprintf(vs, sizeof(vs), "current avg: %d\n", v);
502         write(fd, vs, strlen(vs));
503     }
504 
505     if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
506         v = getIntField(mHealthdConfig->batteryChargeCounterPath);
507         snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
508         write(fd, vs, strlen(vs));
509     }
510 
511     if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
512         snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrent);
513         write(fd, vs, strlen(vs));
514     }
515 
516     if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
517         snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
518         write(fd, vs, strlen(vs));
519     }
520 
521     if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
522         snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullCharge);
523         write(fd, vs, strlen(vs));
524     }
525 }
526 
init(struct healthd_config * hc)527 void BatteryMonitor::init(struct healthd_config *hc) {
528     String8 path;
529     char pval[PROPERTY_VALUE_MAX];
530 
531     mHealthdConfig = hc;
532     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
533     if (dir == NULL) {
534         KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
535     } else {
536         struct dirent* entry;
537 
538         while ((entry = readdir(dir.get()))) {
539             const char* name = entry->d_name;
540             std::vector<String8>::iterator itIgnoreName;
541 
542             if (!strcmp(name, ".") || !strcmp(name, ".."))
543                 continue;
544 
545             itIgnoreName = find(hc->ignorePowerSupplyNames.begin(),
546                                 hc->ignorePowerSupplyNames.end(), String8(name));
547             if (itIgnoreName != hc->ignorePowerSupplyNames.end())
548                 continue;
549 
550             // Look for "type" file in each subdirectory
551             path.clear();
552             path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
553             switch(readPowerSupplyType(path)) {
554             case ANDROID_POWER_SUPPLY_TYPE_AC:
555             case ANDROID_POWER_SUPPLY_TYPE_USB:
556             case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
557                 path.clear();
558                 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
559                 if (access(path.string(), R_OK) == 0)
560                     mChargerNames.add(String8(name));
561                 break;
562 
563             case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
564                 // Some devices expose the battery status of sub-component like
565                 // stylus. Such a device-scoped battery info needs to be skipped
566                 // in BatteryMonitor, which is intended to report the status of
567                 // the battery supplying the power to the whole system.
568                 if (isScopedPowerSupply(name)) continue;
569                 mBatteryDevicePresent = true;
570 
571                 if (mHealthdConfig->batteryStatusPath.isEmpty()) {
572                     path.clear();
573                     path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
574                                       name);
575                     if (access(path, R_OK) == 0)
576                         mHealthdConfig->batteryStatusPath = path;
577                 }
578 
579                 if (mHealthdConfig->batteryHealthPath.isEmpty()) {
580                     path.clear();
581                     path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
582                                       name);
583                     if (access(path, R_OK) == 0)
584                         mHealthdConfig->batteryHealthPath = path;
585                 }
586 
587                 if (mHealthdConfig->batteryPresentPath.isEmpty()) {
588                     path.clear();
589                     path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
590                                       name);
591                     if (access(path, R_OK) == 0)
592                         mHealthdConfig->batteryPresentPath = path;
593                 }
594 
595                 if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
596                     path.clear();
597                     path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
598                                       name);
599                     if (access(path, R_OK) == 0)
600                         mHealthdConfig->batteryCapacityPath = path;
601                 }
602 
603                 if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
604                     path.clear();
605                     path.appendFormat("%s/%s/voltage_now",
606                                       POWER_SUPPLY_SYSFS_PATH, name);
607                     if (access(path, R_OK) == 0) {
608                         mHealthdConfig->batteryVoltagePath = path;
609                     }
610                 }
611 
612                 if (mHealthdConfig->batteryFullChargePath.isEmpty()) {
613                     path.clear();
614                     path.appendFormat("%s/%s/charge_full",
615                                       POWER_SUPPLY_SYSFS_PATH, name);
616                     if (access(path, R_OK) == 0)
617                         mHealthdConfig->batteryFullChargePath = path;
618                 }
619 
620                 if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
621                     path.clear();
622                     path.appendFormat("%s/%s/current_now",
623                                       POWER_SUPPLY_SYSFS_PATH, name);
624                     if (access(path, R_OK) == 0)
625                         mHealthdConfig->batteryCurrentNowPath = path;
626                 }
627 
628                 if (mHealthdConfig->batteryCycleCountPath.isEmpty()) {
629                     path.clear();
630                     path.appendFormat("%s/%s/cycle_count",
631                                       POWER_SUPPLY_SYSFS_PATH, name);
632                     if (access(path, R_OK) == 0)
633                         mHealthdConfig->batteryCycleCountPath = path;
634                 }
635 
636                 if (mHealthdConfig->batteryCapacityLevelPath.isEmpty()) {
637                     path.clear();
638                     path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name);
639                     if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityLevelPath = path;
640                 }
641 
642                 if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) {
643                     path.clear();
644                     path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name);
645                     if (access(path, R_OK) == 0)
646                         mHealthdConfig->batteryChargeTimeToFullNowPath = path;
647                 }
648 
649                 if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) {
650                     path.clear();
651                     path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name);
652                     if (access(path, R_OK) == 0)
653                         mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path;
654                 }
655 
656                 if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
657                     path.clear();
658                     path.appendFormat("%s/%s/current_avg",
659                                       POWER_SUPPLY_SYSFS_PATH, name);
660                     if (access(path, R_OK) == 0)
661                         mHealthdConfig->batteryCurrentAvgPath = path;
662                 }
663 
664                 if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
665                     path.clear();
666                     path.appendFormat("%s/%s/charge_counter",
667                                       POWER_SUPPLY_SYSFS_PATH, name);
668                     if (access(path, R_OK) == 0)
669                         mHealthdConfig->batteryChargeCounterPath = path;
670                 }
671 
672                 if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
673                     path.clear();
674                     path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
675                                       name);
676                     if (access(path, R_OK) == 0) {
677                         mHealthdConfig->batteryTemperaturePath = path;
678                     }
679                 }
680 
681                 if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
682                     path.clear();
683                     path.appendFormat("%s/%s/technology",
684                                       POWER_SUPPLY_SYSFS_PATH, name);
685                     if (access(path, R_OK) == 0)
686                         mHealthdConfig->batteryTechnologyPath = path;
687                 }
688 
689                 break;
690 
691             case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
692                 break;
693             }
694         }
695     }
696 
697     // Typically the case for devices which do not have a battery and
698     // and are always plugged into AC mains.
699     if (!mBatteryDevicePresent) {
700         KLOG_WARNING(LOG_TAG, "No battery devices found\n");
701         hc->periodic_chores_interval_fast = -1;
702         hc->periodic_chores_interval_slow = -1;
703     } else {
704         if (mHealthdConfig->batteryStatusPath.isEmpty())
705             KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
706         if (mHealthdConfig->batteryHealthPath.isEmpty())
707             KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
708         if (mHealthdConfig->batteryPresentPath.isEmpty())
709             KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
710         if (mHealthdConfig->batteryCapacityPath.isEmpty())
711             KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
712         if (mHealthdConfig->batteryVoltagePath.isEmpty())
713             KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
714         if (mHealthdConfig->batteryTemperaturePath.isEmpty())
715             KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
716         if (mHealthdConfig->batteryTechnologyPath.isEmpty())
717             KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
718         if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
719             KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
720         if (mHealthdConfig->batteryFullChargePath.isEmpty())
721             KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
722         if (mHealthdConfig->batteryCycleCountPath.isEmpty())
723             KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
724         if (mHealthdConfig->batteryCapacityLevelPath.isEmpty())
725             KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n");
726         if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
727             KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n");
728         if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
729             KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n");
730     }
731 
732     if (property_get("ro.boot.fake_battery", pval, NULL) > 0
733                                                && strtol(pval, NULL, 10) != 0) {
734         mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
735         mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
736     }
737 }
738 
739 }; // namespace android
740