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