xref: /aosp_15_r20/system/core/healthd/BatteryMonitor_v1.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
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.empty())
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.empty())
315         mHealthInfo->batteryCurrentMicroamps = getIntField(mHealthdConfig->batteryCurrentNowPath);
316 
317     if (!mHealthdConfig->batteryFullChargePath.empty())
318         mHealthInfo->batteryFullChargeUah = getIntField(mHealthdConfig->batteryFullChargePath);
319 
320     if (!mHealthdConfig->batteryCycleCountPath.empty())
321         mHealthInfo->batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
322 
323     if (!mHealthdConfig->batteryChargeCounterPath.empty())
324         mHealthInfo->batteryChargeCounterUah =
325                 getIntField(mHealthdConfig->batteryChargeCounterPath);
326 
327     if (!mHealthdConfig->batteryCurrentAvgPath.empty())
328         mHealthInfo->batteryCurrentAverageMicroamps =
329                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
330 
331     if (!mHealthdConfig->batteryChargeTimeToFullNowPath.empty())
332         mHealthInfo->batteryChargeTimeToFullNowSeconds =
333                 getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath);
334 
335     if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty())
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 = buf;
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, mChargerNames[i].c_str());
362         if (getIntField(path)) {
363             path.clear();
364             path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str());
365             switch(readPowerSupplyType(path)) {
366             case ANDROID_POWER_SUPPLY_TYPE_AC:
367                 mHealthInfo->chargerAcOnline = true;
368                 break;
369             case ANDROID_POWER_SUPPLY_TYPE_USB:
370                 mHealthInfo->chargerUsbOnline = true;
371                 break;
372             case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
373                 mHealthInfo->chargerWirelessOnline = true;
374                 break;
375             case ANDROID_POWER_SUPPLY_TYPE_DOCK:
376                 mHealthInfo->chargerDockOnline = true;
377                 break;
378             default:
379                 path.clear();
380                 path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH,
381                                   mChargerNames[i].c_str());
382                 if (access(path.c_str(), R_OK) == 0)
383                     mHealthInfo->chargerDockOnline = true;
384                 else
385                     KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
386                                  mChargerNames[i].c_str());
387             }
388             path.clear();
389             path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
390                               mChargerNames[i].c_str());
391             int ChargingCurrent = (access(path.c_str(), R_OK) == 0) ? getIntField(path) : 0;
392 
393             path.clear();
394             path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
395                               mChargerNames[i].c_str());
396 
397             int ChargingVoltage =
398                     (access(path.c_str(), R_OK) == 0) ? getIntField(path) : DEFAULT_VBUS_VOLTAGE;
399 
400             double power = ((double)ChargingCurrent / MILLION) *
401                            ((double)ChargingVoltage / MILLION);
402             if (MaxPower < power) {
403                 mHealthInfo->maxChargingCurrentMicroamps = ChargingCurrent;
404                 mHealthInfo->maxChargingVoltageMicrovolts = ChargingVoltage;
405                 MaxPower = power;
406             }
407         }
408     }
409 }
410 
doLogValues(const HealthInfo & props,const struct healthd_config & healthd_config)411 static void doLogValues(const HealthInfo& props, const struct healthd_config& healthd_config) {
412     char dmesgline[256];
413     size_t len;
414     if (props.batteryPresent) {
415         snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
416                  props.batteryLevel, props.batteryVoltageMillivolts,
417                  props.batteryTemperatureTenthsCelsius < 0 ? "-" : "",
418                  abs(props.batteryTemperatureTenthsCelsius / 10),
419                  abs(props.batteryTemperatureTenthsCelsius % 10), props.batteryHealth,
420                  props.batteryStatus);
421 
422         len = strlen(dmesgline);
423         if (!healthd_config.batteryCurrentNowPath.empty()) {
424             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
425                             props.batteryCurrentMicroamps);
426         }
427 
428         if (!healthd_config.batteryFullChargePath.empty()) {
429             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
430                             props.batteryFullChargeUah);
431         }
432 
433         if (!healthd_config.batteryCycleCountPath.empty()) {
434             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
435                             props.batteryCycleCount);
436         }
437     } else {
438         len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
439     }
440 
441     snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s%s",
442              props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
443              props.chargerWirelessOnline ? "w" : "", props.chargerDockOnline ? "d" : "");
444 
445     KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
446 }
447 
logValues(const HealthInfo_2_1 & health_info,const struct healthd_config & healthd_config)448 void BatteryMonitor::logValues(const HealthInfo_2_1& health_info,
449                                const struct healthd_config& healthd_config) {
450     HealthInfo aidl_health_info;
451     (void)android::h2a::translate(health_info, &aidl_health_info);
452     doLogValues(aidl_health_info, healthd_config);
453 }
454 
logValues(void)455 void BatteryMonitor::logValues(void) {
456     doLogValues(*mHealthInfo, *mHealthdConfig);
457 }
458 
isChargerOnline()459 bool BatteryMonitor::isChargerOnline() {
460     const HealthInfo& props = *mHealthInfo;
461     return props.chargerAcOnline | props.chargerUsbOnline | props.chargerWirelessOnline |
462            props.chargerDockOnline;
463 }
464 
getChargeStatus()465 int BatteryMonitor::getChargeStatus() {
466     BatteryStatus result = BatteryStatus::UNKNOWN;
467     if (!mHealthdConfig->batteryStatusPath.empty()) {
468         std::string buf;
469         if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
470             result = getBatteryStatus(buf.c_str());
471     }
472     return static_cast<int>(result);
473 }
474 
getProperty(int id,struct BatteryProperty * val)475 status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
476     status_t ret = BAD_VALUE;
477     std::string buf;
478 
479     val->valueInt64 = LONG_MIN;
480 
481     switch(id) {
482     case BATTERY_PROP_CHARGE_COUNTER:
483         if (!mHealthdConfig->batteryChargeCounterPath.empty()) {
484             val->valueInt64 =
485                 getIntField(mHealthdConfig->batteryChargeCounterPath);
486             ret = OK;
487         } else {
488             ret = NAME_NOT_FOUND;
489         }
490         break;
491 
492     case BATTERY_PROP_CURRENT_NOW:
493         if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
494             val->valueInt64 =
495                 getIntField(mHealthdConfig->batteryCurrentNowPath);
496             ret = OK;
497         } else {
498             ret = NAME_NOT_FOUND;
499         }
500         break;
501 
502     case BATTERY_PROP_CURRENT_AVG:
503         if (!mHealthdConfig->batteryCurrentAvgPath.empty()) {
504             val->valueInt64 =
505                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
506             ret = OK;
507         } else {
508             ret = NAME_NOT_FOUND;
509         }
510         break;
511 
512     case BATTERY_PROP_CAPACITY:
513         if (!mHealthdConfig->batteryCapacityPath.empty()) {
514             val->valueInt64 =
515                 getIntField(mHealthdConfig->batteryCapacityPath);
516             ret = OK;
517         } else {
518             ret = NAME_NOT_FOUND;
519         }
520         break;
521 
522     case BATTERY_PROP_ENERGY_COUNTER:
523         if (mHealthdConfig->energyCounter) {
524             ret = mHealthdConfig->energyCounter(&val->valueInt64);
525         } else {
526             ret = NAME_NOT_FOUND;
527         }
528         break;
529 
530     case BATTERY_PROP_BATTERY_STATUS:
531         val->valueInt64 = getChargeStatus();
532         ret = OK;
533         break;
534 
535     default:
536         break;
537     }
538 
539     return ret;
540 }
541 
dumpState(int fd)542 void BatteryMonitor::dumpState(int fd) {
543     int v;
544     char vs[128];
545     const HealthInfo& props = *mHealthInfo;
546 
547     snprintf(vs, sizeof(vs),
548              "ac: %d usb: %d wireless: %d dock: %d current_max: %d voltage_max: %d\n",
549              props.chargerAcOnline, props.chargerUsbOnline, props.chargerWirelessOnline,
550              props.chargerDockOnline, props.maxChargingCurrentMicroamps,
551              props.maxChargingVoltageMicrovolts);
552     write(fd, vs, strlen(vs));
553     snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
554              props.batteryStatus, props.batteryHealth, props.batteryPresent);
555     write(fd, vs, strlen(vs));
556     snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n", props.batteryLevel,
557              props.batteryVoltageMillivolts, props.batteryTemperatureTenthsCelsius);
558     write(fd, vs, strlen(vs));
559 
560     if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
561         v = getIntField(mHealthdConfig->batteryCurrentNowPath);
562         snprintf(vs, sizeof(vs), "current now: %d\n", v);
563         write(fd, vs, strlen(vs));
564     }
565 
566     if (!mHealthdConfig->batteryCurrentAvgPath.empty()) {
567         v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
568         snprintf(vs, sizeof(vs), "current avg: %d\n", v);
569         write(fd, vs, strlen(vs));
570     }
571 
572     if (!mHealthdConfig->batteryChargeCounterPath.empty()) {
573         v = getIntField(mHealthdConfig->batteryChargeCounterPath);
574         snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
575         write(fd, vs, strlen(vs));
576     }
577 
578     if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
579         snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrentMicroamps);
580         write(fd, vs, strlen(vs));
581     }
582 
583     if (!mHealthdConfig->batteryCycleCountPath.empty()) {
584         snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
585         write(fd, vs, strlen(vs));
586     }
587 
588     if (!mHealthdConfig->batteryFullChargePath.empty()) {
589         snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullChargeUah);
590         write(fd, vs, strlen(vs));
591     }
592 }
593 
init(struct healthd_config * hc)594 void BatteryMonitor::init(struct healthd_config *hc) {
595     String8 path;
596     char pval[PROPERTY_VALUE_MAX];
597 
598     mHealthdConfig = hc;
599     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
600     if (dir == NULL) {
601         KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
602     } else {
603         struct dirent* entry;
604 
605         while ((entry = readdir(dir.get()))) {
606             const char* name = entry->d_name;
607 
608             if (!strcmp(name, ".") || !strcmp(name, ".."))
609                 continue;
610 
611             std::vector<String8>::iterator itIgnoreName =
612                     find(hc->ignorePowerSupplyNames.begin(), hc->ignorePowerSupplyNames.end(),
613                          String8(name));
614             if (itIgnoreName != hc->ignorePowerSupplyNames.end())
615                 continue;
616 
617             // Look for "type" file in each subdirectory
618             path.clear();
619             path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
620             switch(readPowerSupplyType(path)) {
621             case ANDROID_POWER_SUPPLY_TYPE_AC:
622             case ANDROID_POWER_SUPPLY_TYPE_USB:
623             case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
624             case ANDROID_POWER_SUPPLY_TYPE_DOCK:
625                 path.clear();
626                 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
627                 if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name));
628                 break;
629 
630             case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
631                 // Some devices expose the battery status of sub-component like
632                 // stylus. Such a device-scoped battery info needs to be skipped
633                 // in BatteryMonitor, which is intended to report the status of
634                 // the battery supplying the power to the whole system.
635                 if (isScopedPowerSupply(name)) continue;
636                 mBatteryDevicePresent = true;
637 
638                 if (mHealthdConfig->batteryStatusPath.empty()) {
639                     path.clear();
640                     path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
641                                       name);
642                     if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryStatusPath = path;
643                 }
644 
645                 if (mHealthdConfig->batteryHealthPath.empty()) {
646                     path.clear();
647                     path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
648                                       name);
649                     if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryHealthPath = path;
650                 }
651 
652                 if (mHealthdConfig->batteryPresentPath.empty()) {
653                     path.clear();
654                     path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
655                                       name);
656                     if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryPresentPath = path;
657                 }
658 
659                 if (mHealthdConfig->batteryCapacityPath.empty()) {
660                     path.clear();
661                     path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
662                                       name);
663                     if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryCapacityPath = path;
664                 }
665 
666                 if (mHealthdConfig->batteryVoltagePath.empty()) {
667                     path.clear();
668                     path.appendFormat("%s/%s/voltage_now",
669                                       POWER_SUPPLY_SYSFS_PATH, name);
670                     if (access(path.c_str(), R_OK) == 0) {
671                         mHealthdConfig->batteryVoltagePath = path;
672                     }
673                 }
674 
675                 if (mHealthdConfig->batteryFullChargePath.empty()) {
676                     path.clear();
677                     path.appendFormat("%s/%s/charge_full",
678                                       POWER_SUPPLY_SYSFS_PATH, name);
679                     if (access(path.c_str(), R_OK) == 0)
680                         mHealthdConfig->batteryFullChargePath = path;
681                 }
682 
683                 if (mHealthdConfig->batteryCurrentNowPath.empty()) {
684                     path.clear();
685                     path.appendFormat("%s/%s/current_now",
686                                       POWER_SUPPLY_SYSFS_PATH, name);
687                     if (access(path.c_str(), R_OK) == 0)
688                         mHealthdConfig->batteryCurrentNowPath = path;
689                 }
690 
691                 if (mHealthdConfig->batteryCycleCountPath.empty()) {
692                     path.clear();
693                     path.appendFormat("%s/%s/cycle_count",
694                                       POWER_SUPPLY_SYSFS_PATH, name);
695                     if (access(path.c_str(), R_OK) == 0)
696                         mHealthdConfig->batteryCycleCountPath = path;
697                 }
698 
699                 if (mHealthdConfig->batteryCapacityLevelPath.empty()) {
700                     path.clear();
701                     path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name);
702                     if (access(path.c_str(), R_OK) == 0) {
703                         mHealthdConfig->batteryCapacityLevelPath = path;
704                     }
705                 }
706 
707                 if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) {
708                     path.clear();
709                     path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name);
710                     if (access(path.c_str(), R_OK) == 0)
711                         mHealthdConfig->batteryChargeTimeToFullNowPath = path;
712                 }
713 
714                 if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) {
715                     path.clear();
716                     path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name);
717                     if (access(path.c_str(), R_OK) == 0)
718                         mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path;
719                 }
720 
721                 if (mHealthdConfig->batteryCurrentAvgPath.empty()) {
722                     path.clear();
723                     path.appendFormat("%s/%s/current_avg",
724                                       POWER_SUPPLY_SYSFS_PATH, name);
725                     if (access(path.c_str(), R_OK) == 0)
726                         mHealthdConfig->batteryCurrentAvgPath = path;
727                 }
728 
729                 if (mHealthdConfig->batteryChargeCounterPath.empty()) {
730                     path.clear();
731                     path.appendFormat("%s/%s/charge_counter",
732                                       POWER_SUPPLY_SYSFS_PATH, name);
733                     if (access(path.c_str(), R_OK) == 0)
734                         mHealthdConfig->batteryChargeCounterPath = path;
735                 }
736 
737                 if (mHealthdConfig->batteryTemperaturePath.empty()) {
738                     path.clear();
739                     path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
740                                       name);
741                     if (access(path.c_str(), R_OK) == 0) {
742                         mHealthdConfig->batteryTemperaturePath = path;
743                     }
744                 }
745 
746                 if (mHealthdConfig->batteryTechnologyPath.empty()) {
747                     path.clear();
748                     path.appendFormat("%s/%s/technology",
749                                       POWER_SUPPLY_SYSFS_PATH, name);
750                     if (access(path.c_str(), R_OK) == 0)
751                         mHealthdConfig->batteryTechnologyPath = path;
752                 }
753 
754                 break;
755 
756             case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
757                 break;
758             }
759 
760             // Look for "is_dock" file
761             path.clear();
762             path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name);
763             if (access(path.c_str(), R_OK) == 0) {
764                 path.clear();
765                 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
766                 if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name));
767             }
768         }
769     }
770 
771     // Typically the case for devices which do not have a battery and
772     // and are always plugged into AC mains.
773     if (!mBatteryDevicePresent) {
774         KLOG_WARNING(LOG_TAG, "No battery devices found\n");
775         hc->periodic_chores_interval_fast = -1;
776         hc->periodic_chores_interval_slow = -1;
777     } else {
778         if (mHealthdConfig->batteryStatusPath.empty())
779             KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
780         if (mHealthdConfig->batteryHealthPath.empty())
781             KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
782         if (mHealthdConfig->batteryPresentPath.empty())
783             KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
784         if (mHealthdConfig->batteryCapacityPath.empty())
785             KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
786         if (mHealthdConfig->batteryVoltagePath.empty())
787             KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
788         if (mHealthdConfig->batteryTemperaturePath.empty())
789             KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
790         if (mHealthdConfig->batteryTechnologyPath.empty())
791             KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
792         if (mHealthdConfig->batteryCurrentNowPath.empty())
793             KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
794         if (mHealthdConfig->batteryFullChargePath.empty())
795             KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
796         if (mHealthdConfig->batteryCycleCountPath.empty())
797             KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
798         if (mHealthdConfig->batteryCapacityLevelPath.empty())
799             KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n");
800         if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty())
801             KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n");
802         if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty())
803             KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n");
804     }
805 
806     if (property_get("ro.boot.fake_battery", pval, NULL) > 0
807                                                && strtol(pval, NULL, 10) != 0) {
808         mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
809         mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
810     }
811 }
812 
813 }; // namespace android
814