blob: 8c9f1c17b57176859a3b0b8dea068bba752c1201 [file] [log] [blame]
Todd Poynor752faf22013-06-12 13:25:59 -07001/*
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
Yabin Cuie98e1772016-02-17 12:21:34 -080019#include <healthd/healthd.h>
20#include <healthd/BatteryMonitor.h>
Todd Poynor752faf22013-06-12 13:25:59 -070021
22#include <dirent.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <stdlib.h>
Mark Salyzynacb1ddf2015-07-23 09:22:50 -070027#include <sys/types.h>
Todd Poynor752faf22013-06-12 13:25:59 -070028#include <unistd.h>
Thierry Strudelf73de6f2019-01-11 17:09:20 -080029
30#include <algorithm>
James Hawkins588a2ca2016-02-18 14:52:46 -080031#include <memory>
Yifan Hong1d4368b2019-10-07 11:18:04 -070032#include <optional>
Mark Salyzynacb1ddf2015-07-23 09:22:50 -070033
Yifan Hongb99d15c2022-03-01 12:12:34 -080034#include <aidl/android/hardware/health/HealthInfo.h>
Michael Scott3217c5c2016-06-05 11:20:13 -070035#include <android-base/file.h>
Elliott Hughesda46b392016-10-11 17:09:00 -070036#include <android-base/parseint.h>
Michael Scott3217c5c2016-06-05 11:20:13 -070037#include <android-base/strings.h>
Yifan Hong1d4368b2019-10-07 11:18:04 -070038#include <android/hardware/health/2.1/types.h>
Yifan Hongb99d15c2022-03-01 12:12:34 -080039#include <android/hardware/health/translate-ndk.h>
Todd Poynor752faf22013-06-12 13:25:59 -070040#include <batteryservice/BatteryService.h>
41#include <cutils/klog.h>
Todd Poynor3db03a52014-05-21 16:28:13 -070042#include <cutils/properties.h>
Todd Poynorc133b712013-08-14 17:39:13 -070043#include <utils/Errors.h>
Todd Poynor752faf22013-06-12 13:25:59 -070044#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
Ruchi Kandoia78fc232014-07-10 15:06:21 -070049#define FAKE_BATTERY_CAPACITY 42
50#define FAKE_BATTERY_TEMPERATURE 424
Ruchi Kandoi5c09ec12016-02-25 16:19:30 -080051#define MILLION 1.0e6
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -070052#define DEFAULT_VBUS_VOLTAGE 5000000
Stefan Berger06c6f502019-04-06 11:05:19 +020053#ifdef HEALTHD_USE_BATTERY_INFO
54#define SYSFS_BATTERY_CURRENT "/sys/class/power_supply/battery/current_now"
55#define SYSFS_BATTERY_VOLTAGE "/sys/class/power_supply/battery/voltage_now"
56#endif
Todd Poynor752faf22013-06-12 13:25:59 -070057
Yifan Hong1d4368b2019-10-07 11:18:04 -070058using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
59using HealthInfo_2_0 = android::hardware::health::V2_0::HealthInfo;
60using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
Yifan Hongb99d15c2022-03-01 12:12:34 -080061using aidl::android::hardware::health::BatteryCapacityLevel;
Jack Wue561d032022-11-24 12:19:41 +080062using aidl::android::hardware::health::BatteryChargingPolicy;
63using aidl::android::hardware::health::BatteryChargingState;
Yifan Hongb99d15c2022-03-01 12:12:34 -080064using aidl::android::hardware::health::BatteryHealth;
Jack Wue561d032022-11-24 12:19:41 +080065using aidl::android::hardware::health::BatteryHealthData;
David Andersond5ed26a2023-12-08 15:12:24 -080066using aidl::android::hardware::health::BatteryPartStatus;
Yifan Hongb99d15c2022-03-01 12:12:34 -080067using aidl::android::hardware::health::BatteryStatus;
68using aidl::android::hardware::health::HealthInfo;
69
70namespace {
71
72// Translate from AIDL back to HIDL definition for getHealthInfo_*_* calls.
73// Skips storageInfo and diskStats.
74void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
75 ::android::hardware::health::V1_0::HealthInfo* out) {
76 out->chargerAcOnline = in.chargerAcOnline;
77 out->chargerUsbOnline = in.chargerUsbOnline;
78 out->chargerWirelessOnline = in.chargerWirelessOnline;
79 out->maxChargingCurrent = in.maxChargingCurrentMicroamps;
80 out->maxChargingVoltage = in.maxChargingVoltageMicrovolts;
81 out->batteryStatus =
82 static_cast<::android::hardware::health::V1_0::BatteryStatus>(in.batteryStatus);
83 out->batteryHealth =
84 static_cast<::android::hardware::health::V1_0::BatteryHealth>(in.batteryHealth);
85 out->batteryPresent = in.batteryPresent;
86 out->batteryLevel = in.batteryLevel;
87 out->batteryVoltage = in.batteryVoltageMillivolts;
88 out->batteryTemperature = in.batteryTemperatureTenthsCelsius;
89 out->batteryCurrent = in.batteryCurrentMicroamps;
90 out->batteryCycleCount = in.batteryCycleCount;
91 out->batteryFullCharge = in.batteryFullChargeUah;
92 out->batteryChargeCounter = in.batteryChargeCounterUah;
93 out->batteryTechnology = in.batteryTechnology;
94}
95
96void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
97 ::android::hardware::health::V2_0::HealthInfo* out) {
98 translateToHidl(in, &out->legacy);
99 out->batteryCurrentAverage = in.batteryCurrentAverageMicroamps;
100 // Skip storageInfo and diskStats
101}
102
103void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
104 ::android::hardware::health::V2_1::HealthInfo* out) {
105 translateToHidl(in, &out->legacy);
106 out->batteryCapacityLevel = static_cast<android::hardware::health::V2_1::BatteryCapacityLevel>(
107 in.batteryCapacityLevel);
108 out->batteryChargeTimeToFullNowSeconds = in.batteryChargeTimeToFullNowSeconds;
109 out->batteryFullChargeDesignCapacityUah = in.batteryFullChargeDesignCapacityUah;
110}
111
112} // namespace
Yifan Hong1d4368b2019-10-07 11:18:04 -0700113
Todd Poynor752faf22013-06-12 13:25:59 -0700114namespace android {
115
Yifan Hong1d4368b2019-10-07 11:18:04 -0700116template <typename T>
117struct SysfsStringEnumMap {
Mark Salyzyn6f5b47f2014-05-15 15:00:59 -0700118 const char* s;
Yifan Hong1d4368b2019-10-07 11:18:04 -0700119 T val;
Todd Poynor752faf22013-06-12 13:25:59 -0700120};
121
Yifan Hong1d4368b2019-10-07 11:18:04 -0700122template <typename T>
123static std::optional<T> mapSysfsString(const char* str, SysfsStringEnumMap<T> map[]) {
Todd Poynor752faf22013-06-12 13:25:59 -0700124 for (int i = 0; map[i].s; i++)
125 if (!strcmp(str, map[i].s))
126 return map[i].val;
127
Yifan Hong1d4368b2019-10-07 11:18:04 -0700128 return std::nullopt;
Yabin Cuidb04a492016-02-16 17:19:23 -0800129}
130
Yifan Hongb99d15c2022-03-01 12:12:34 -0800131static void initHealthInfo(HealthInfo* health_info) {
Bart Van Assche024e18f2022-02-24 21:22:07 +0000132 *health_info = {
133 .batteryCapacityLevel = BatteryCapacityLevel::UNSUPPORTED,
134 .batteryChargeTimeToFullNowSeconds =
135 (int64_t)HealthInfo::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED,
136 .batteryStatus = BatteryStatus::UNKNOWN,
137 .batteryHealth = BatteryHealth::UNKNOWN,
Andrei Ciubotariu515f5b52025-02-12 21:31:23 -0800138 .batteryHealthData = std::nullopt,
Bart Van Assche024e18f2022-02-24 21:22:07 +0000139 };
Yifan Hong6cabe9b2019-11-05 17:04:50 -0800140}
141
Todd Poynore030a102018-01-19 14:03:59 -0800142BatteryMonitor::BatteryMonitor()
143 : mHealthdConfig(nullptr),
144 mBatteryDevicePresent(false),
145 mBatteryFixedCapacity(0),
Yifan Hong1d4368b2019-10-07 11:18:04 -0700146 mBatteryFixedTemperature(0),
Jack Wub57f68a2023-02-04 19:56:06 +0800147 mBatteryHealthStatus(BatteryMonitor::BH_UNKNOWN),
Yifan Hongb99d15c2022-03-01 12:12:34 -0800148 mHealthInfo(std::make_unique<HealthInfo>()) {
Yifan Hong6cabe9b2019-11-05 17:04:50 -0800149 initHealthInfo(mHealthInfo.get());
150}
Yifan Hong1d4368b2019-10-07 11:18:04 -0700151
152BatteryMonitor::~BatteryMonitor() {}
153
Yifan Hongb99d15c2022-03-01 12:12:34 -0800154HealthInfo_1_0 BatteryMonitor::getHealthInfo_1_0() const {
155 HealthInfo_1_0 health_info_1_0;
156 translateToHidl(*mHealthInfo, &health_info_1_0);
157 return health_info_1_0;
Yabin Cuidb04a492016-02-16 17:19:23 -0800158}
159
Yifan Hongb99d15c2022-03-01 12:12:34 -0800160HealthInfo_2_0 BatteryMonitor::getHealthInfo_2_0() const {
161 HealthInfo_2_0 health_info_2_0;
162 translateToHidl(*mHealthInfo, &health_info_2_0);
163 return health_info_2_0;
Hridya Valsaraju7fa72252018-01-12 17:44:33 -0800164}
165
Yifan Hongb99d15c2022-03-01 12:12:34 -0800166HealthInfo_2_1 BatteryMonitor::getHealthInfo_2_1() const {
167 HealthInfo_2_1 health_info_2_1;
168 translateToHidl(*mHealthInfo, &health_info_2_1);
169 return health_info_2_1;
170}
171
172const HealthInfo& BatteryMonitor::getHealthInfo() const {
Yifan Hong1d4368b2019-10-07 11:18:04 -0700173 return *mHealthInfo;
174}
175
176BatteryStatus getBatteryStatus(const char* status) {
177 static SysfsStringEnumMap<BatteryStatus> batteryStatusMap[] = {
178 {"Unknown", BatteryStatus::UNKNOWN},
179 {"Charging", BatteryStatus::CHARGING},
180 {"Discharging", BatteryStatus::DISCHARGING},
181 {"Not charging", BatteryStatus::NOT_CHARGING},
182 {"Full", BatteryStatus::FULL},
183 {NULL, BatteryStatus::UNKNOWN},
Todd Poynor752faf22013-06-12 13:25:59 -0700184 };
185
Yifan Hong1d4368b2019-10-07 11:18:04 -0700186 auto ret = mapSysfsString(status, batteryStatusMap);
187 if (!ret) {
Todd Poynor752faf22013-06-12 13:25:59 -0700188 KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status);
Yifan Hong1d4368b2019-10-07 11:18:04 -0700189 *ret = BatteryStatus::UNKNOWN;
Todd Poynor752faf22013-06-12 13:25:59 -0700190 }
191
Yifan Hong1d4368b2019-10-07 11:18:04 -0700192 return *ret;
Todd Poynor752faf22013-06-12 13:25:59 -0700193}
194
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800195BatteryCapacityLevel getBatteryCapacityLevel(const char* capacityLevel) {
196 static SysfsStringEnumMap<BatteryCapacityLevel> batteryCapacityLevelMap[] = {
197 {"Unknown", BatteryCapacityLevel::UNKNOWN},
198 {"Critical", BatteryCapacityLevel::CRITICAL},
199 {"Low", BatteryCapacityLevel::LOW},
200 {"Normal", BatteryCapacityLevel::NORMAL},
201 {"High", BatteryCapacityLevel::HIGH},
202 {"Full", BatteryCapacityLevel::FULL},
Stephane Lee06846042020-02-12 17:00:24 -0800203 {NULL, BatteryCapacityLevel::UNSUPPORTED},
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800204 };
205
206 auto ret = mapSysfsString(capacityLevel, batteryCapacityLevelMap);
207 if (!ret) {
Stephane Lee06846042020-02-12 17:00:24 -0800208 KLOG_WARNING(LOG_TAG, "Unsupported battery capacity level '%s'\n", capacityLevel);
209 *ret = BatteryCapacityLevel::UNSUPPORTED;
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800210 }
211
212 return *ret;
213}
214
Yifan Hong1d4368b2019-10-07 11:18:04 -0700215BatteryHealth getBatteryHealth(const char* status) {
216 static SysfsStringEnumMap<BatteryHealth> batteryHealthMap[] = {
217 {"Unknown", BatteryHealth::UNKNOWN},
218 {"Good", BatteryHealth::GOOD},
219 {"Overheat", BatteryHealth::OVERHEAT},
220 {"Dead", BatteryHealth::DEAD},
221 {"Over voltage", BatteryHealth::OVER_VOLTAGE},
222 {"Unspecified failure", BatteryHealth::UNSPECIFIED_FAILURE},
223 {"Cold", BatteryHealth::COLD},
224 // battery health values from JEITA spec
225 {"Warm", BatteryHealth::GOOD},
226 {"Cool", BatteryHealth::GOOD},
227 {"Hot", BatteryHealth::OVERHEAT},
David Anderson629a26b2023-12-11 15:25:13 -0800228 {"Calibration required", BatteryHealth::INCONSISTENT},
Yifan Hong1d4368b2019-10-07 11:18:04 -0700229 {NULL, BatteryHealth::UNKNOWN},
Todd Poynor752faf22013-06-12 13:25:59 -0700230 };
231
Yifan Hong1d4368b2019-10-07 11:18:04 -0700232 auto ret = mapSysfsString(status, batteryHealthMap);
233 if (!ret) {
Todd Poynor752faf22013-06-12 13:25:59 -0700234 KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status);
Yifan Hong1d4368b2019-10-07 11:18:04 -0700235 *ret = BatteryHealth::UNKNOWN;
Todd Poynor752faf22013-06-12 13:25:59 -0700236 }
237
Yifan Hong1d4368b2019-10-07 11:18:04 -0700238 return *ret;
Todd Poynor752faf22013-06-12 13:25:59 -0700239}
240
Jack Wub57f68a2023-02-04 19:56:06 +0800241BatteryHealth getBatteryHealthStatus(int status) {
242 BatteryHealth value;
243
244 if (status == BatteryMonitor::BH_NOMINAL)
245 value = BatteryHealth::GOOD;
246 else if (status == BatteryMonitor::BH_MARGINAL)
247 value = BatteryHealth::FAIR;
248 else if (status == BatteryMonitor::BH_NEEDS_REPLACEMENT)
249 value = BatteryHealth::DEAD;
250 else if (status == BatteryMonitor::BH_FAILED)
251 value = BatteryHealth::UNSPECIFIED_FAILURE;
Jack Wucf996f32023-04-13 19:37:46 +0800252 else if (status == BatteryMonitor::BH_NOT_AVAILABLE)
253 value = BatteryHealth::NOT_AVAILABLE;
Jack Wu8231c3f2023-05-19 14:31:53 +0800254 else if (status == BatteryMonitor::BH_INCONSISTENT)
255 value = BatteryHealth::INCONSISTENT;
Jack Wub57f68a2023-02-04 19:56:06 +0800256 else
257 value = BatteryHealth::UNKNOWN;
258
259 return value;
260}
261
Jack Wue561d032022-11-24 12:19:41 +0800262BatteryChargingPolicy getBatteryChargingPolicy(const char* chargingPolicy) {
263 static SysfsStringEnumMap<BatteryChargingPolicy> batteryChargingPolicyMap[] = {
264 {"0", BatteryChargingPolicy::INVALID}, {"1", BatteryChargingPolicy::DEFAULT},
265 {"2", BatteryChargingPolicy::LONG_LIFE}, {"3", BatteryChargingPolicy::ADAPTIVE},
266 {NULL, BatteryChargingPolicy::DEFAULT},
267 };
268
269 auto ret = mapSysfsString(chargingPolicy, batteryChargingPolicyMap);
270 if (!ret) {
271 *ret = BatteryChargingPolicy::DEFAULT;
272 }
273
274 return *ret;
275}
276
277BatteryChargingState getBatteryChargingState(const char* chargingState) {
278 static SysfsStringEnumMap<BatteryChargingState> batteryChargingStateMap[] = {
279 {"0", BatteryChargingState::INVALID}, {"1", BatteryChargingState::NORMAL},
280 {"2", BatteryChargingState::TOO_COLD}, {"3", BatteryChargingState::TOO_HOT},
281 {"4", BatteryChargingState::LONG_LIFE}, {"5", BatteryChargingState::ADAPTIVE},
282 {NULL, BatteryChargingState::NORMAL},
283 };
284
285 auto ret = mapSysfsString(chargingState, batteryChargingStateMap);
286 if (!ret) {
287 *ret = BatteryChargingState::NORMAL;
288 }
289
290 return *ret;
291}
292
Bart Van Assche095c9442022-03-02 17:36:34 +0000293static int readFromFile(const String8& path, std::string* buf) {
Bart Van Assche5a7e5082022-02-24 21:40:15 +0000294 buf->clear();
Steven Moreland2aac3352017-03-10 22:31:08 -0800295 if (android::base::ReadFileToString(path.c_str(), buf)) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700296 *buf = android::base::Trim(*buf);
Todd Poynor752faf22013-06-12 13:25:59 -0700297 }
Michael Scott3217c5c2016-06-05 11:20:13 -0700298 return buf->length();
Todd Poynor752faf22013-06-12 13:25:59 -0700299}
300
Jack Wue561d032022-11-24 12:19:41 +0800301static bool writeToFile(const String8& path, int32_t in_value) {
302 return android::base::WriteStringToFile(std::to_string(in_value), path.c_str());
303}
304
Bart Van Assche095c9442022-03-02 17:36:34 +0000305static BatteryMonitor::PowerSupplyType readPowerSupplyType(const String8& path) {
Yifan Hong1d4368b2019-10-07 11:18:04 -0700306 static SysfsStringEnumMap<int> supplyTypeMap[] = {
Bart Van Assche095c9442022-03-02 17:36:34 +0000307 {"Unknown", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN},
308 {"Battery", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_BATTERY},
309 {"UPS", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
310 {"Mains", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
311 {"USB", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_USB},
312 {"USB_DCP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
313 {"USB_HVDCP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
Abhijeet Dharmapurikaree19f9f2015-09-14 16:35:26 -0700314 {"USB_HVDCP_3", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
Bart Van Assche095c9442022-03-02 17:36:34 +0000315 {"USB_CDP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
316 {"USB_ACA", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
317 {"USB_C", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
318 {"USB_PD", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
319 {"USB_PD_DRP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_USB},
320 {"Wireless", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_WIRELESS},
321 {"Dock", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_DOCK},
Abhijeet Dharmapurikaree19f9f2015-09-14 16:35:26 -0700322 {"DASH", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
Yifan Hong1d4368b2019-10-07 11:18:04 -0700323 {NULL, 0},
Todd Poynor752faf22013-06-12 13:25:59 -0700324 };
Yifan Hong1d4368b2019-10-07 11:18:04 -0700325 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700326
Bart Van Assche095c9442022-03-02 17:36:34 +0000327 if (readFromFile(path, &buf) <= 0) {
328 return BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
329 }
Todd Poynor752faf22013-06-12 13:25:59 -0700330
Yifan Hong1d4368b2019-10-07 11:18:04 -0700331 auto ret = mapSysfsString(buf.c_str(), supplyTypeMap);
Abhijeet Dharmapurikar69332482016-05-24 15:12:11 -0700332 if (!ret)
Bart Van Assche095c9442022-03-02 17:36:34 +0000333 *ret = BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
Todd Poynor752faf22013-06-12 13:25:59 -0700334
Yifan Hong1d4368b2019-10-07 11:18:04 -0700335 return static_cast<BatteryMonitor::PowerSupplyType>(*ret);
Todd Poynor752faf22013-06-12 13:25:59 -0700336}
337
Bart Van Assche095c9442022-03-02 17:36:34 +0000338static bool getBooleanField(const String8& path) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700339 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700340 bool value = false;
Michael Scott3217c5c2016-06-05 11:20:13 -0700341
342 if (readFromFile(path, &buf) > 0)
343 if (buf[0] != '0')
Todd Poynor752faf22013-06-12 13:25:59 -0700344 value = true;
Todd Poynor752faf22013-06-12 13:25:59 -0700345
346 return value;
347}
348
David Andersonebdd01e2025-03-19 02:46:37 +0000349template <typename T = int>
350static T getIntField(const String8& path) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700351 std::string buf;
David Andersonebdd01e2025-03-19 02:46:37 +0000352 T value = 0;
Michael Scott3217c5c2016-06-05 11:20:13 -0700353
354 if (readFromFile(path, &buf) > 0)
Elliott Hughesda46b392016-10-11 17:09:00 -0700355 android::base::ParseInt(buf, &value);
Michael Scott3217c5c2016-06-05 11:20:13 -0700356
Todd Poynor752faf22013-06-12 13:25:59 -0700357 return value;
358}
359
Bart Van Assche095c9442022-03-02 17:36:34 +0000360static bool isScopedPowerSupply(const char* name) {
Kazuhiro Inaba8e4d9822019-06-12 13:46:08 +0900361 constexpr char kScopeDevice[] = "Device";
362
363 String8 path;
364 path.appendFormat("%s/%s/scope", POWER_SUPPLY_SYSFS_PATH, name);
365 std::string scope;
366 return (readFromFile(path, &scope) > 0 && scope == kScopeDevice);
367}
368
Andrei Ciubotariu515f5b52025-02-12 21:31:23 -0800369static BatteryHealthData *ensureBatteryHealthData(HealthInfo *info) {
370 if (!info->batteryHealthData.has_value()) {
371 return &info->batteryHealthData.emplace();
372 }
373
374 return &info->batteryHealthData.value();
375}
376
Yifan Hong1353e702019-10-07 10:41:30 -0700377void BatteryMonitor::updateValues(void) {
Yifan Hong6cabe9b2019-11-05 17:04:50 -0800378 initHealthInfo(mHealthInfo.get());
Yifan Hong1d4368b2019-10-07 11:18:04 -0700379
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000380 if (!mHealthdConfig->batteryPresentPath.empty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800381 mHealthInfo->batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
Todd Poynor752faf22013-06-12 13:25:59 -0700382 else
Yifan Hongb99d15c2022-03-01 12:12:34 -0800383 mHealthInfo->batteryPresent = mBatteryDevicePresent;
Todd Poynor752faf22013-06-12 13:25:59 -0700384
Yifan Hongb99d15c2022-03-01 12:12:34 -0800385 mHealthInfo->batteryLevel = mBatteryFixedCapacity
386 ? mBatteryFixedCapacity
387 : getIntField(mHealthdConfig->batteryCapacityPath);
388 mHealthInfo->batteryVoltageMillivolts = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
Todd Poynorb45f1f52013-07-30 18:57:16 -0700389
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000390 if (!mHealthdConfig->batteryCurrentNowPath.empty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800391 mHealthInfo->batteryCurrentMicroamps = getIntField(mHealthdConfig->batteryCurrentNowPath);
Ruchi Kandoicc338802015-08-24 13:01:16 -0700392
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000393 if (!mHealthdConfig->batteryFullChargePath.empty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800394 mHealthInfo->batteryFullChargeUah = getIntField(mHealthdConfig->batteryFullChargePath);
Ruchi Kandoicc338802015-08-24 13:01:16 -0700395
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000396 if (!mHealthdConfig->batteryCycleCountPath.empty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800397 mHealthInfo->batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
Ruchi Kandoicc338802015-08-24 13:01:16 -0700398
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000399 if (!mHealthdConfig->batteryChargeCounterPath.empty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800400 mHealthInfo->batteryChargeCounterUah =
401 getIntField(mHealthdConfig->batteryChargeCounterPath);
Ruchi Kandoi3f9886b2016-04-07 12:34:40 -0700402
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000403 if (!mHealthdConfig->batteryCurrentAvgPath.empty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800404 mHealthInfo->batteryCurrentAverageMicroamps =
Yifan Hong35cb0832019-10-07 13:58:29 -0700405 getIntField(mHealthdConfig->batteryCurrentAvgPath);
406
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000407 if (!mHealthdConfig->batteryChargeTimeToFullNowPath.empty())
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800408 mHealthInfo->batteryChargeTimeToFullNowSeconds =
409 getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath);
410
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000411 if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty())
Stephane Lee1c108ed2020-02-10 18:23:57 -0800412 mHealthInfo->batteryFullChargeDesignCapacityUah =
413 getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
Yifan Hong35cb0832019-10-07 13:58:29 -0700414
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000415 if (!mHealthdConfig->batteryHealthStatusPath.empty())
Jack Wub57f68a2023-02-04 19:56:06 +0800416 mBatteryHealthStatus = getIntField(mHealthdConfig->batteryHealthStatusPath);
417
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000418 if (!mHealthdConfig->batteryStateOfHealthPath.empty())
Andrei Ciubotariu515f5b52025-02-12 21:31:23 -0800419 ensureBatteryHealthData(mHealthInfo.get())->batteryStateOfHealth =
AleX Pelosiff708922023-02-17 01:39:21 +0000420 getIntField(mHealthdConfig->batteryStateOfHealthPath);
421
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000422 if (!mHealthdConfig->batteryManufacturingDatePath.empty())
Andrei Ciubotariu515f5b52025-02-12 21:31:23 -0800423 ensureBatteryHealthData(mHealthInfo.get())->batteryManufacturingDateSeconds =
David Andersonebdd01e2025-03-19 02:46:37 +0000424 getIntField<int64_t>(mHealthdConfig->batteryManufacturingDatePath);
Jack Wue561d032022-11-24 12:19:41 +0800425
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000426 if (!mHealthdConfig->batteryFirstUsageDatePath.empty())
Andrei Ciubotariu515f5b52025-02-12 21:31:23 -0800427 ensureBatteryHealthData(mHealthInfo.get())->batteryFirstUsageSeconds =
David Andersonebdd01e2025-03-19 02:46:37 +0000428 getIntField<int64_t>(mHealthdConfig->batteryFirstUsageDatePath);
Jack Wue561d032022-11-24 12:19:41 +0800429
Yifan Hongb99d15c2022-03-01 12:12:34 -0800430 mHealthInfo->batteryTemperatureTenthsCelsius =
431 mBatteryFixedTemperature ? mBatteryFixedTemperature
432 : getIntField(mHealthdConfig->batteryTemperaturePath);
Todd Poynor752faf22013-06-12 13:25:59 -0700433
Michael Scott3217c5c2016-06-05 11:20:13 -0700434 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700435
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800436 if (readFromFile(mHealthdConfig->batteryCapacityLevelPath, &buf) > 0)
437 mHealthInfo->batteryCapacityLevel = getBatteryCapacityLevel(buf.c_str());
438
Michael Scott3217c5c2016-06-05 11:20:13 -0700439 if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
Yifan Hongb99d15c2022-03-01 12:12:34 -0800440 mHealthInfo->batteryStatus = getBatteryStatus(buf.c_str());
Todd Poynor752faf22013-06-12 13:25:59 -0700441
Jack Wub57f68a2023-02-04 19:56:06 +0800442 // Backward compatible with android.hardware.health V1
443 if (mBatteryHealthStatus < BatteryMonitor::BH_MARGINAL) {
444 if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
445 mHealthInfo->batteryHealth = getBatteryHealth(buf.c_str());
446 } else {
447 mHealthInfo->batteryHealth = getBatteryHealthStatus(mBatteryHealthStatus);
448 }
Todd Poynor752faf22013-06-12 13:25:59 -0700449
Michael Scott3217c5c2016-06-05 11:20:13 -0700450 if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000451 mHealthInfo->batteryTechnology = buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700452
Jack Wue561d032022-11-24 12:19:41 +0800453 if (readFromFile(mHealthdConfig->chargingPolicyPath, &buf) > 0)
454 mHealthInfo->chargingPolicy = getBatteryChargingPolicy(buf.c_str());
455
456 if (readFromFile(mHealthdConfig->chargingStatePath, &buf) > 0)
457 mHealthInfo->chargingState = getBatteryChargingState(buf.c_str());
458
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700459 double MaxPower = 0;
Todd Poynor752faf22013-06-12 13:25:59 -0700460
Abhijeet Dharmapurikar69332482016-05-24 15:12:11 -0700461 // Rescan for the available charger types
462 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
463 if (dir == NULL) {
464 KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
465 } else {
466 struct dirent* entry;
467 String8 path;
468
469 mChargerNames.clear();
470
471 while ((entry = readdir(dir.get()))) {
472 const char* name = entry->d_name;
473
474 if (!strcmp(name, ".") || !strcmp(name, ".."))
475 continue;
476
477 // Look for "type" file in each subdirectory
478 path.clear();
479 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
480 switch(readPowerSupplyType(path)) {
481 case ANDROID_POWER_SUPPLY_TYPE_AC:
482 case ANDROID_POWER_SUPPLY_TYPE_USB:
483 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
484 case ANDROID_POWER_SUPPLY_TYPE_DOCK:
485 path.clear();
486 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
Michael Bestas49e82d72024-03-10 18:47:36 +0200487 if (access(path.c_str(), R_OK) == 0)
Abhijeet Dharmapurikar69332482016-05-24 15:12:11 -0700488 mChargerNames.add(String8(name));
489 break;
490 default:
491 break;
492 }
493
494 // Look for "is_dock" file
495 path.clear();
496 path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name);
Michael Bestas49e82d72024-03-10 18:47:36 +0200497 if (access(path.c_str(), R_OK) == 0) {
Abhijeet Dharmapurikar69332482016-05-24 15:12:11 -0700498 path.clear();
499 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
Michael Bestas49e82d72024-03-10 18:47:36 +0200500 if (access(path.c_str(), R_OK) == 0)
Abhijeet Dharmapurikar69332482016-05-24 15:12:11 -0700501 mChargerNames.add(String8(name));
502
503 }
504 }
505 }
506
ShevT9d98a6a2018-07-26 11:47:47 +0300507 for (size_t i = 0; i < mChargerNames.size(); i++) {
Todd Poynor752faf22013-06-12 13:25:59 -0700508 String8 path;
Tomasz Wasilczyk18b74612023-08-10 23:29:50 +0000509 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str());
Michael Scott3217c5c2016-06-05 11:20:13 -0700510 if (getIntField(path)) {
511 path.clear();
Tomasz Wasilczyk18b74612023-08-10 23:29:50 +0000512 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].c_str());
Michael Scott3217c5c2016-06-05 11:20:13 -0700513 switch(readPowerSupplyType(path)) {
514 case ANDROID_POWER_SUPPLY_TYPE_AC:
Yifan Hongb99d15c2022-03-01 12:12:34 -0800515 mHealthInfo->chargerAcOnline = true;
Michael Scott3217c5c2016-06-05 11:20:13 -0700516 break;
517 case ANDROID_POWER_SUPPLY_TYPE_USB:
Yifan Hongb99d15c2022-03-01 12:12:34 -0800518 mHealthInfo->chargerUsbOnline = true;
Michael Scott3217c5c2016-06-05 11:20:13 -0700519 break;
520 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
Yifan Hongb99d15c2022-03-01 12:12:34 -0800521 mHealthInfo->chargerWirelessOnline = true;
Michael Scott3217c5c2016-06-05 11:20:13 -0700522 break;
Jack Wu06b90412021-12-15 20:40:21 +0800523 case ANDROID_POWER_SUPPLY_TYPE_DOCK:
Yifan Hongb99d15c2022-03-01 12:12:34 -0800524 mHealthInfo->chargerDockOnline = true;
Jack Wu06b90412021-12-15 20:40:21 +0800525 break;
Michael Scott3217c5c2016-06-05 11:20:13 -0700526 default:
Jack Wu06b90412021-12-15 20:40:21 +0800527 path.clear();
528 path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH,
Tomasz Wasilczyk18b74612023-08-10 23:29:50 +0000529 mChargerNames[i].c_str());
530 if (access(path.c_str(), R_OK) == 0)
Yifan Hongb99d15c2022-03-01 12:12:34 -0800531 mHealthInfo->chargerDockOnline = true;
532 else
Jack Wu06b90412021-12-15 20:40:21 +0800533 KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
Tomasz Wasilczyk18b74612023-08-10 23:29:50 +0000534 mChargerNames[i].c_str());
Michael Scott3217c5c2016-06-05 11:20:13 -0700535 }
Stefan Berger06c6f502019-04-06 11:05:19 +0200536
537#ifdef HEALTHD_USE_BATTERY_INFO
538 int ChargingCurrent = (access(SYSFS_BATTERY_CURRENT, R_OK) == 0) ?
539 abs(getIntField(String8(SYSFS_BATTERY_CURRENT))) : 0;
540
541 int ChargingVoltage = (access(SYSFS_BATTERY_VOLTAGE, R_OK) == 0) ?
542 getIntField(String8(SYSFS_BATTERY_VOLTAGE)) : DEFAULT_VBUS_VOLTAGE;
543#else
Michael Scott3217c5c2016-06-05 11:20:13 -0700544 path.clear();
545 path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
Tomasz Wasilczyk18b74612023-08-10 23:29:50 +0000546 mChargerNames[i].c_str());
547 int ChargingCurrent = (access(path.c_str(), R_OK) == 0) ? getIntField(path) : 0;
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700548
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700549 path.clear();
550 path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
Tomasz Wasilczyk18b74612023-08-10 23:29:50 +0000551 mChargerNames[i].c_str());
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700552
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700553 int ChargingVoltage =
Tomasz Wasilczyk18b74612023-08-10 23:29:50 +0000554 (access(path.c_str(), R_OK) == 0) ? getIntField(path) : DEFAULT_VBUS_VOLTAGE;
Stefan Berger06c6f502019-04-06 11:05:19 +0200555#endif
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700556
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700557 double power = ((double)ChargingCurrent / MILLION) *
558 ((double)ChargingVoltage / MILLION);
559 if (MaxPower < power) {
Yifan Hongb99d15c2022-03-01 12:12:34 -0800560 mHealthInfo->maxChargingCurrentMicroamps = ChargingCurrent;
561 mHealthInfo->maxChargingVoltageMicrovolts = ChargingVoltage;
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700562 MaxPower = power;
Todd Poynor752faf22013-06-12 13:25:59 -0700563 }
564 }
565 }
Yifan Hong1353e702019-10-07 10:41:30 -0700566}
Todd Poynor752faf22013-06-12 13:25:59 -0700567
Bart Van Assche095c9442022-03-02 17:36:34 +0000568static void doLogValues(const HealthInfo& props, const struct healthd_config& healthd_config) {
Yifan Hong1353e702019-10-07 10:41:30 -0700569 char dmesgline[256];
570 size_t len;
571 if (props.batteryPresent) {
572 snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
Yifan Hongb99d15c2022-03-01 12:12:34 -0800573 props.batteryLevel, props.batteryVoltageMillivolts,
574 props.batteryTemperatureTenthsCelsius < 0 ? "-" : "",
575 abs(props.batteryTemperatureTenthsCelsius / 10),
576 abs(props.batteryTemperatureTenthsCelsius % 10), props.batteryHealth,
577 props.batteryStatus);
Todd Poynorb45f1f52013-07-30 18:57:16 -0700578
Yifan Hong1353e702019-10-07 10:41:30 -0700579 len = strlen(dmesgline);
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000580 if (!healthd_config.batteryCurrentNowPath.empty()) {
Yifan Hong1353e702019-10-07 10:41:30 -0700581 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
Yifan Hongb99d15c2022-03-01 12:12:34 -0800582 props.batteryCurrentMicroamps);
Todd Poynor10b235e2013-08-07 15:25:14 -0700583 }
584
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000585 if (!healthd_config.batteryFullChargePath.empty()) {
Yifan Hong1353e702019-10-07 10:41:30 -0700586 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
Yifan Hongb99d15c2022-03-01 12:12:34 -0800587 props.batteryFullChargeUah);
Yifan Hong1353e702019-10-07 10:41:30 -0700588 }
Mark Salyzynacb1ddf2015-07-23 09:22:50 -0700589
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000590 if (!healthd_config.batteryCycleCountPath.empty()) {
Yifan Hong1353e702019-10-07 10:41:30 -0700591 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
592 props.batteryCycleCount);
593 }
594 } else {
595 len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
Todd Poynorb45f1f52013-07-30 18:57:16 -0700596 }
597
Yifan Hongb99d15c2022-03-01 12:12:34 -0800598 snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s%s",
Yifan Hong1353e702019-10-07 10:41:30 -0700599 props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
Yifan Hongb99d15c2022-03-01 12:12:34 -0800600 props.chargerWirelessOnline ? "w" : "", props.chargerDockOnline ? "d" : "");
Yifan Hong1353e702019-10-07 10:41:30 -0700601
AleX Pelosif08aede2024-02-15 18:42:11 +0000602 KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
Yifan Hong1353e702019-10-07 10:41:30 -0700603}
604
Bart Van Assche095c9442022-03-02 17:36:34 +0000605void BatteryMonitor::logValues(const HealthInfo_2_1& health_info,
606 const struct healthd_config& healthd_config) {
607 HealthInfo aidl_health_info;
608 (void)android::h2a::translate(health_info, &aidl_health_info);
609 doLogValues(aidl_health_info, healthd_config);
610}
611
612void BatteryMonitor::logValues(void) {
613 doLogValues(*mHealthInfo, *mHealthdConfig);
614}
615
Yifan Hong1353e702019-10-07 10:41:30 -0700616bool BatteryMonitor::isChargerOnline() {
Yifan Hongb99d15c2022-03-01 12:12:34 -0800617 const HealthInfo& props = *mHealthInfo;
Jack Wu06b90412021-12-15 20:40:21 +0800618 return props.chargerAcOnline | props.chargerUsbOnline | props.chargerWirelessOnline |
Yifan Hongb99d15c2022-03-01 12:12:34 -0800619 props.chargerDockOnline;
Todd Poynor752faf22013-06-12 13:25:59 -0700620}
621
Yabin Cuiaedf6032016-02-19 18:03:23 -0800622int BatteryMonitor::getChargeStatus() {
Yifan Hong1d4368b2019-10-07 11:18:04 -0700623 BatteryStatus result = BatteryStatus::UNKNOWN;
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000624 if (!mHealthdConfig->batteryStatusPath.empty()) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700625 std::string buf;
626 if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
627 result = getBatteryStatus(buf.c_str());
Yabin Cuiaedf6032016-02-19 18:03:23 -0800628 }
Yifan Hong1d4368b2019-10-07 11:18:04 -0700629 return static_cast<int>(result);
Yabin Cuiaedf6032016-02-19 18:03:23 -0800630}
631
Jack Wue561d032022-11-24 12:19:41 +0800632status_t BatteryMonitor::setChargingPolicy(int value) {
633 status_t ret = NAME_NOT_FOUND;
634 bool result;
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000635 if (!mHealthdConfig->chargingPolicyPath.empty()) {
Jack Wue561d032022-11-24 12:19:41 +0800636 result = writeToFile(mHealthdConfig->chargingPolicyPath, value);
637 if (!result) {
638 KLOG_WARNING(LOG_TAG, "setChargingPolicy fail\n");
639 ret = BAD_VALUE;
640 } else {
641 ret = OK;
642 }
643 }
644 return ret;
645}
646
647int BatteryMonitor::getChargingPolicy() {
648 BatteryChargingPolicy result = BatteryChargingPolicy::DEFAULT;
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000649 if (!mHealthdConfig->chargingPolicyPath.empty()) {
Jack Wue561d032022-11-24 12:19:41 +0800650 std::string buf;
651 if (readFromFile(mHealthdConfig->chargingPolicyPath, &buf) > 0)
652 result = getBatteryChargingPolicy(buf.c_str());
653 }
654 return static_cast<int>(result);
655}
656
657int BatteryMonitor::getBatteryHealthData(int id) {
658 if (id == BATTERY_PROP_MANUFACTURING_DATE) {
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000659 if (!mHealthdConfig->batteryManufacturingDatePath.empty())
Jack Wue561d032022-11-24 12:19:41 +0800660 return getIntField(mHealthdConfig->batteryManufacturingDatePath);
661 }
662 if (id == BATTERY_PROP_FIRST_USAGE_DATE) {
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000663 if (!mHealthdConfig->batteryFirstUsageDatePath.empty())
Jack Wue561d032022-11-24 12:19:41 +0800664 return getIntField(mHealthdConfig->batteryFirstUsageDatePath);
665 }
AleX Pelosiff708922023-02-17 01:39:21 +0000666 if (id == BATTERY_PROP_STATE_OF_HEALTH) {
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000667 if (!mHealthdConfig->batteryStateOfHealthPath.empty())
AleX Pelosiff708922023-02-17 01:39:21 +0000668 return getIntField(mHealthdConfig->batteryStateOfHealthPath);
669 }
David Andersond5ed26a2023-12-08 15:12:24 -0800670 if (id == BATTERY_PROP_PART_STATUS) {
671 return static_cast<int>(BatteryPartStatus::UNSUPPORTED);
672 }
Jack Wue561d032022-11-24 12:19:41 +0800673 return 0;
674}
675
Todd Poynorc133b712013-08-14 17:39:13 -0700676status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
677 status_t ret = BAD_VALUE;
Jin Qian72adf112017-02-02 17:31:13 -0800678 std::string buf;
Todd Poynorc133b712013-08-14 17:39:13 -0700679
Todd Poynor8f132af2014-05-08 17:15:45 -0700680 val->valueInt64 = LONG_MIN;
681
Todd Poynorc133b712013-08-14 17:39:13 -0700682 switch(id) {
683 case BATTERY_PROP_CHARGE_COUNTER:
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000684 if (!mHealthdConfig->batteryChargeCounterPath.empty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700685 val->valueInt64 =
Todd Poynorc133b712013-08-14 17:39:13 -0700686 getIntField(mHealthdConfig->batteryChargeCounterPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700687 ret = OK;
Todd Poynorc133b712013-08-14 17:39:13 -0700688 } else {
689 ret = NAME_NOT_FOUND;
690 }
691 break;
692
693 case BATTERY_PROP_CURRENT_NOW:
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000694 if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700695 val->valueInt64 =
Todd Poynorc133b712013-08-14 17:39:13 -0700696 getIntField(mHealthdConfig->batteryCurrentNowPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700697 ret = OK;
Todd Poynorc133b712013-08-14 17:39:13 -0700698 } else {
699 ret = NAME_NOT_FOUND;
700 }
701 break;
702
Todd Poynorbc102112013-08-27 18:11:49 -0700703 case BATTERY_PROP_CURRENT_AVG:
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000704 if (!mHealthdConfig->batteryCurrentAvgPath.empty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700705 val->valueInt64 =
Todd Poynorbc102112013-08-27 18:11:49 -0700706 getIntField(mHealthdConfig->batteryCurrentAvgPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700707 ret = OK;
Todd Poynorbc102112013-08-27 18:11:49 -0700708 } else {
709 ret = NAME_NOT_FOUND;
710 }
711 break;
712
Paul Lawrence347c8de2014-03-19 15:04:40 -0700713 case BATTERY_PROP_CAPACITY:
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000714 if (!mHealthdConfig->batteryCapacityPath.empty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700715 val->valueInt64 =
Paul Lawrence347c8de2014-03-19 15:04:40 -0700716 getIntField(mHealthdConfig->batteryCapacityPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700717 ret = OK;
Paul Lawrence347c8de2014-03-19 15:04:40 -0700718 } else {
719 ret = NAME_NOT_FOUND;
720 }
721 break;
722
Todd Poynor8f132af2014-05-08 17:15:45 -0700723 case BATTERY_PROP_ENERGY_COUNTER:
Todd Poynore14b37e2014-05-20 13:54:40 -0700724 if (mHealthdConfig->energyCounter) {
725 ret = mHealthdConfig->energyCounter(&val->valueInt64);
726 } else {
727 ret = NAME_NOT_FOUND;
728 }
Todd Poynor8f132af2014-05-08 17:15:45 -0700729 break;
730
Jin Qian72adf112017-02-02 17:31:13 -0800731 case BATTERY_PROP_BATTERY_STATUS:
Todd Poynore030a102018-01-19 14:03:59 -0800732 val->valueInt64 = getChargeStatus();
Elliott Hughes643268f2018-10-08 11:10:11 -0700733 ret = OK;
Jin Qian72adf112017-02-02 17:31:13 -0800734 break;
735
Jack Wue561d032022-11-24 12:19:41 +0800736 case BATTERY_PROP_CHARGING_POLICY:
737 val->valueInt64 = getChargingPolicy();
738 ret = OK;
739 break;
740
741 case BATTERY_PROP_MANUFACTURING_DATE:
742 val->valueInt64 = getBatteryHealthData(BATTERY_PROP_MANUFACTURING_DATE);
743 ret = OK;
744 break;
745
746 case BATTERY_PROP_FIRST_USAGE_DATE:
747 val->valueInt64 = getBatteryHealthData(BATTERY_PROP_FIRST_USAGE_DATE);
748 ret = OK;
749 break;
750
AleX Pelosiff708922023-02-17 01:39:21 +0000751 case BATTERY_PROP_STATE_OF_HEALTH:
752 val->valueInt64 = getBatteryHealthData(BATTERY_PROP_STATE_OF_HEALTH);
753 ret = OK;
754 break;
755
David Andersond5ed26a2023-12-08 15:12:24 -0800756 case BATTERY_PROP_PART_STATUS:
757 val->valueInt64 = getBatteryHealthData(BATTERY_PROP_PART_STATUS);
758 ret = OK;
759 break;
760
Todd Poynorc133b712013-08-14 17:39:13 -0700761 default:
762 break;
763 }
764
Todd Poynorc133b712013-08-14 17:39:13 -0700765 return ret;
766}
767
David Andersond5ed26a2023-12-08 15:12:24 -0800768status_t BatteryMonitor::getSerialNumber(std::optional<std::string>* out) {
769 *out = std::nullopt;
770 return OK;
771}
772
Todd Poynor020369d2013-09-18 20:09:33 -0700773void BatteryMonitor::dumpState(int fd) {
774 int v;
775 char vs[128];
Yifan Hongb99d15c2022-03-01 12:12:34 -0800776 const HealthInfo& props = *mHealthInfo;
Todd Poynor020369d2013-09-18 20:09:33 -0700777
YiKai Pengae455db2025-03-10 23:41:17 -0700778 snprintf(vs, sizeof(vs), "Cached HealthInfo:\n");
779 write(fd, vs, strlen(vs));
Jack Wu06b90412021-12-15 20:40:21 +0800780 snprintf(vs, sizeof(vs),
YiKai Pengae455db2025-03-10 23:41:17 -0700781 " ac: %d usb: %d wireless: %d dock: %d current_max: %d voltage_max: %d\n",
Jack Wu06b90412021-12-15 20:40:21 +0800782 props.chargerAcOnline, props.chargerUsbOnline, props.chargerWirelessOnline,
Yifan Hongb99d15c2022-03-01 12:12:34 -0800783 props.chargerDockOnline, props.maxChargingCurrentMicroamps,
784 props.maxChargingVoltageMicrovolts);
Todd Poynor020369d2013-09-18 20:09:33 -0700785 write(fd, vs, strlen(vs));
YiKai Pengae455db2025-03-10 23:41:17 -0700786 snprintf(vs, sizeof(vs), " status: %d health: %d present: %d\n",
Todd Poynor020369d2013-09-18 20:09:33 -0700787 props.batteryStatus, props.batteryHealth, props.batteryPresent);
788 write(fd, vs, strlen(vs));
YiKai Pengae455db2025-03-10 23:41:17 -0700789 snprintf(vs, sizeof(vs), " level: %d voltage: %d temp: %d\n", props.batteryLevel,
Yifan Hongb99d15c2022-03-01 12:12:34 -0800790 props.batteryVoltageMillivolts, props.batteryTemperatureTenthsCelsius);
Todd Poynor020369d2013-09-18 20:09:33 -0700791 write(fd, vs, strlen(vs));
792
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000793 if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
YiKai Pengae455db2025-03-10 23:41:17 -0700794 snprintf(vs, sizeof(vs), " current now: %d\n", props.batteryCurrentMicroamps);
795 write(fd, vs, strlen(vs));
796 }
797
798 if (!mHealthdConfig->batteryCycleCountPath.empty()) {
799 snprintf(vs, sizeof(vs), " cycle count: %d\n", props.batteryCycleCount);
800 write(fd, vs, strlen(vs));
801 }
802
803 if (!mHealthdConfig->batteryFullChargePath.empty()) {
804 snprintf(vs, sizeof(vs), " Full charge: %d\n", props.batteryFullChargeUah);
805 write(fd, vs, strlen(vs));
806 }
807
808 snprintf(vs, sizeof(vs), "Real-time Values:\n");
809 write(fd, vs, strlen(vs));
810
811 if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
Todd Poynor020369d2013-09-18 20:09:33 -0700812 v = getIntField(mHealthdConfig->batteryCurrentNowPath);
YiKai Pengae455db2025-03-10 23:41:17 -0700813 snprintf(vs, sizeof(vs), " current now: %d\n", v);
Todd Poynor020369d2013-09-18 20:09:33 -0700814 write(fd, vs, strlen(vs));
815 }
816
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000817 if (!mHealthdConfig->batteryCurrentAvgPath.empty()) {
Todd Poynor020369d2013-09-18 20:09:33 -0700818 v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
YiKai Pengae455db2025-03-10 23:41:17 -0700819 snprintf(vs, sizeof(vs), " current avg: %d\n", v);
Todd Poynor020369d2013-09-18 20:09:33 -0700820 write(fd, vs, strlen(vs));
821 }
822
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000823 if (!mHealthdConfig->batteryChargeCounterPath.empty()) {
Todd Poynor020369d2013-09-18 20:09:33 -0700824 v = getIntField(mHealthdConfig->batteryChargeCounterPath);
YiKai Pengae455db2025-03-10 23:41:17 -0700825 snprintf(vs, sizeof(vs), " charge counter: %d\n", v);
Ruchi Kandoicc338802015-08-24 13:01:16 -0700826 write(fd, vs, strlen(vs));
827 }
Todd Poynor020369d2013-09-18 20:09:33 -0700828}
829
Todd Poynorc7464c92013-09-10 12:40:00 -0700830void BatteryMonitor::init(struct healthd_config *hc) {
Todd Poynor752faf22013-06-12 13:25:59 -0700831 String8 path;
Todd Poynor3db03a52014-05-21 16:28:13 -0700832 char pval[PROPERTY_VALUE_MAX];
Todd Poynor752faf22013-06-12 13:25:59 -0700833
Todd Poynorf5d30122013-08-12 17:03:35 -0700834 mHealthdConfig = hc;
James Hawkins588a2ca2016-02-18 14:52:46 -0800835 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
Todd Poynor752faf22013-06-12 13:25:59 -0700836 if (dir == NULL) {
837 KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
838 } else {
839 struct dirent* entry;
840
James Hawkins588a2ca2016-02-18 14:52:46 -0800841 while ((entry = readdir(dir.get()))) {
Todd Poynor752faf22013-06-12 13:25:59 -0700842 const char* name = entry->d_name;
843
844 if (!strcmp(name, ".") || !strcmp(name, ".."))
845 continue;
846
Bart Van Assche25b2a8d2022-02-24 21:51:34 +0000847 std::vector<String8>::iterator itIgnoreName =
848 find(hc->ignorePowerSupplyNames.begin(), hc->ignorePowerSupplyNames.end(),
849 String8(name));
Thierry Strudelf73de6f2019-01-11 17:09:20 -0800850 if (itIgnoreName != hc->ignorePowerSupplyNames.end())
851 continue;
852
Todd Poynor752faf22013-06-12 13:25:59 -0700853 // Look for "type" file in each subdirectory
854 path.clear();
855 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
856 switch(readPowerSupplyType(path)) {
857 case ANDROID_POWER_SUPPLY_TYPE_AC:
858 case ANDROID_POWER_SUPPLY_TYPE_USB:
859 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
Jack Wu06b90412021-12-15 20:40:21 +0800860 case ANDROID_POWER_SUPPLY_TYPE_DOCK:
Todd Poynor752faf22013-06-12 13:25:59 -0700861 path.clear();
862 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk18b74612023-08-10 23:29:50 +0000863 if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name));
Todd Poynor752faf22013-06-12 13:25:59 -0700864 break;
865
866 case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
Kazuhiro Inaba8e4d9822019-06-12 13:46:08 +0900867 // Some devices expose the battery status of sub-component like
868 // stylus. Such a device-scoped battery info needs to be skipped
869 // in BatteryMonitor, which is intended to report the status of
870 // the battery supplying the power to the whole system.
871 if (isScopedPowerSupply(name)) continue;
Todd Poynor6dcc45e2013-10-21 20:26:25 -0700872 mBatteryDevicePresent = true;
873
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000874 if (mHealthdConfig->batteryStatusPath.empty()) {
Todd Poynor752faf22013-06-12 13:25:59 -0700875 path.clear();
Todd Poynorf5d30122013-08-12 17:03:35 -0700876 path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
877 name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000878 if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryStatusPath = path;
Todd Poynor752faf22013-06-12 13:25:59 -0700879 }
880
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000881 if (mHealthdConfig->batteryHealthPath.empty()) {
Todd Poynor752faf22013-06-12 13:25:59 -0700882 path.clear();
Todd Poynorf5d30122013-08-12 17:03:35 -0700883 path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
884 name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000885 if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryHealthPath = path;
Todd Poynor752faf22013-06-12 13:25:59 -0700886 }
887
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000888 if (mHealthdConfig->batteryPresentPath.empty()) {
Todd Poynorf5d30122013-08-12 17:03:35 -0700889 path.clear();
890 path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
891 name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000892 if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryPresentPath = path;
Todd Poynorf5d30122013-08-12 17:03:35 -0700893 }
894
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000895 if (mHealthdConfig->batteryCapacityPath.empty()) {
Todd Poynorf5d30122013-08-12 17:03:35 -0700896 path.clear();
897 path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
898 name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000899 if (access(path.c_str(), R_OK) == 0) mHealthdConfig->batteryCapacityPath = path;
Todd Poynorf5d30122013-08-12 17:03:35 -0700900 }
901
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000902 if (mHealthdConfig->batteryVoltagePath.empty()) {
Todd Poynorf5d30122013-08-12 17:03:35 -0700903 path.clear();
904 path.appendFormat("%s/%s/voltage_now",
905 POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000906 if (access(path.c_str(), R_OK) == 0) {
Todd Poynorf5d30122013-08-12 17:03:35 -0700907 mHealthdConfig->batteryVoltagePath = path;
Todd Poynorf5d30122013-08-12 17:03:35 -0700908 }
909 }
910
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000911 if (mHealthdConfig->batteryFullChargePath.empty()) {
Ruchi Kandoicc338802015-08-24 13:01:16 -0700912 path.clear();
913 path.appendFormat("%s/%s/charge_full",
914 POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000915 if (access(path.c_str(), R_OK) == 0)
Ruchi Kandoicc338802015-08-24 13:01:16 -0700916 mHealthdConfig->batteryFullChargePath = path;
917 }
918
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000919 if (mHealthdConfig->batteryCurrentNowPath.empty()) {
Todd Poynorf5d30122013-08-12 17:03:35 -0700920 path.clear();
921 path.appendFormat("%s/%s/current_now",
922 POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000923 if (access(path.c_str(), R_OK) == 0)
Todd Poynorf5d30122013-08-12 17:03:35 -0700924 mHealthdConfig->batteryCurrentNowPath = path;
925 }
926
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000927 if (mHealthdConfig->batteryCycleCountPath.empty()) {
Ruchi Kandoicc338802015-08-24 13:01:16 -0700928 path.clear();
929 path.appendFormat("%s/%s/cycle_count",
930 POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000931 if (access(path.c_str(), R_OK) == 0)
Ruchi Kandoicc338802015-08-24 13:01:16 -0700932 mHealthdConfig->batteryCycleCountPath = path;
933 }
934
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000935 if (mHealthdConfig->batteryCapacityLevelPath.empty()) {
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800936 path.clear();
937 path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000938 if (access(path.c_str(), R_OK) == 0) {
939 mHealthdConfig->batteryCapacityLevelPath = path;
940 }
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800941 }
942
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000943 if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) {
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800944 path.clear();
945 path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000946 if (access(path.c_str(), R_OK) == 0)
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800947 mHealthdConfig->batteryChargeTimeToFullNowPath = path;
948 }
949
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000950 if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) {
Stephane Lee1c108ed2020-02-10 18:23:57 -0800951 path.clear();
952 path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000953 if (access(path.c_str(), R_OK) == 0)
Stephane Lee1c108ed2020-02-10 18:23:57 -0800954 mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path;
955 }
956
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000957 if (mHealthdConfig->batteryCurrentAvgPath.empty()) {
Todd Poynorbc102112013-08-27 18:11:49 -0700958 path.clear();
959 path.appendFormat("%s/%s/current_avg",
960 POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000961 if (access(path.c_str(), R_OK) == 0)
Todd Poynorbc102112013-08-27 18:11:49 -0700962 mHealthdConfig->batteryCurrentAvgPath = path;
963 }
964
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000965 if (mHealthdConfig->batteryChargeCounterPath.empty()) {
Todd Poynorf5d30122013-08-12 17:03:35 -0700966 path.clear();
967 path.appendFormat("%s/%s/charge_counter",
968 POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000969 if (access(path.c_str(), R_OK) == 0)
Todd Poynorf5d30122013-08-12 17:03:35 -0700970 mHealthdConfig->batteryChargeCounterPath = path;
971 }
972
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000973 if (mHealthdConfig->batteryTemperaturePath.empty()) {
Todd Poynorf5d30122013-08-12 17:03:35 -0700974 path.clear();
975 path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
976 name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000977 if (access(path.c_str(), R_OK) == 0) {
Todd Poynorf5d30122013-08-12 17:03:35 -0700978 mHealthdConfig->batteryTemperaturePath = path;
Todd Poynorf5d30122013-08-12 17:03:35 -0700979 }
980 }
981
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000982 if (mHealthdConfig->batteryTechnologyPath.empty()) {
Todd Poynorf5d30122013-08-12 17:03:35 -0700983 path.clear();
984 path.appendFormat("%s/%s/technology",
985 POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000986 if (access(path.c_str(), R_OK) == 0)
Todd Poynorf5d30122013-08-12 17:03:35 -0700987 mHealthdConfig->batteryTechnologyPath = path;
988 }
989
Tomasz Wasilczykf5971292023-08-14 18:18:26 +0000990 if (mHealthdConfig->batteryStateOfHealthPath.empty()) {
Jack Wue561d032022-11-24 12:19:41 +0800991 path.clear();
992 path.appendFormat("%s/%s/state_of_health", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000993 if (access(path.c_str(), R_OK) == 0) {
Jack Wue561d032022-11-24 12:19:41 +0800994 mHealthdConfig->batteryStateOfHealthPath = path;
995 } else {
996 path.clear();
997 path.appendFormat("%s/%s/health_index", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +0000998 if (access(path.c_str(), R_OK) == 0)
Jack Wue561d032022-11-24 12:19:41 +0800999 mHealthdConfig->batteryStateOfHealthPath = path;
1000 }
1001 }
1002
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001003 if (mHealthdConfig->batteryHealthStatusPath.empty()) {
Jack Wub57f68a2023-02-04 19:56:06 +08001004 path.clear();
1005 path.appendFormat("%s/%s/health_status", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +00001006 if (access(path.c_str(), R_OK) == 0) {
1007 mHealthdConfig->batteryHealthStatusPath = path;
1008 }
Jack Wub57f68a2023-02-04 19:56:06 +08001009 }
1010
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001011 if (mHealthdConfig->batteryManufacturingDatePath.empty()) {
Jack Wue561d032022-11-24 12:19:41 +08001012 path.clear();
1013 path.appendFormat("%s/%s/manufacturing_date", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +00001014 if (access(path.c_str(), R_OK) == 0)
Jack Wue561d032022-11-24 12:19:41 +08001015 mHealthdConfig->batteryManufacturingDatePath = path;
1016 }
1017
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001018 if (mHealthdConfig->batteryFirstUsageDatePath.empty()) {
Jack Wue561d032022-11-24 12:19:41 +08001019 path.clear();
1020 path.appendFormat("%s/%s/first_usage_date", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +00001021 if (access(path.c_str(), R_OK) == 0) {
1022 mHealthdConfig->batteryFirstUsageDatePath = path;
1023 }
Jack Wue561d032022-11-24 12:19:41 +08001024 }
1025
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001026 if (mHealthdConfig->chargingStatePath.empty()) {
Jack Wue561d032022-11-24 12:19:41 +08001027 path.clear();
1028 path.appendFormat("%s/%s/charging_state", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +00001029 if (access(path.c_str(), R_OK) == 0) mHealthdConfig->chargingStatePath = path;
Jack Wue561d032022-11-24 12:19:41 +08001030 }
1031
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001032 if (mHealthdConfig->chargingPolicyPath.empty()) {
Jack Wue561d032022-11-24 12:19:41 +08001033 path.clear();
1034 path.appendFormat("%s/%s/charging_policy", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk2b1a0592023-09-12 15:26:15 +00001035 if (access(path.c_str(), R_OK) == 0) mHealthdConfig->chargingPolicyPath = path;
Jack Wue561d032022-11-24 12:19:41 +08001036 }
1037
Todd Poynor752faf22013-06-12 13:25:59 -07001038 break;
1039
1040 case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
1041 break;
1042 }
Jack Wu06b90412021-12-15 20:40:21 +08001043
1044 // Look for "is_dock" file
1045 path.clear();
1046 path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk18b74612023-08-10 23:29:50 +00001047 if (access(path.c_str(), R_OK) == 0) {
Jack Wu06b90412021-12-15 20:40:21 +08001048 path.clear();
1049 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
Tomasz Wasilczyk18b74612023-08-10 23:29:50 +00001050 if (access(path.c_str(), R_OK) == 0) mChargerNames.add(String8(name));
Jack Wu06b90412021-12-15 20:40:21 +08001051 }
Todd Poynor752faf22013-06-12 13:25:59 -07001052 }
Todd Poynor752faf22013-06-12 13:25:59 -07001053 }
1054
Ian Pedowitz585ab652015-10-12 19:01:00 -07001055 // Typically the case for devices which do not have a battery and
1056 // and are always plugged into AC mains.
Todd Poynor6dcc45e2013-10-21 20:26:25 -07001057 if (!mBatteryDevicePresent) {
Todd Poynorebeb0c02014-09-23 14:54:24 -07001058 KLOG_WARNING(LOG_TAG, "No battery devices found\n");
Todd Poynor6dcc45e2013-10-21 20:26:25 -07001059 hc->periodic_chores_interval_fast = -1;
1060 hc->periodic_chores_interval_slow = -1;
1061 } else {
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001062 if (mHealthdConfig->batteryStatusPath.empty())
Todd Poynor6dcc45e2013-10-21 20:26:25 -07001063 KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001064 if (mHealthdConfig->batteryHealthPath.empty())
Todd Poynor6dcc45e2013-10-21 20:26:25 -07001065 KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001066 if (mHealthdConfig->batteryPresentPath.empty())
Todd Poynor6dcc45e2013-10-21 20:26:25 -07001067 KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001068 if (mHealthdConfig->batteryCapacityPath.empty())
Todd Poynor6dcc45e2013-10-21 20:26:25 -07001069 KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001070 if (mHealthdConfig->batteryVoltagePath.empty())
Todd Poynor6dcc45e2013-10-21 20:26:25 -07001071 KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001072 if (mHealthdConfig->batteryTemperaturePath.empty())
Todd Poynor6dcc45e2013-10-21 20:26:25 -07001073 KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001074 if (mHealthdConfig->batteryTechnologyPath.empty())
Todd Poynor6dcc45e2013-10-21 20:26:25 -07001075 KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001076 if (mHealthdConfig->batteryCurrentNowPath.empty())
Ruchi Kandoicc338802015-08-24 13:01:16 -07001077 KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001078 if (mHealthdConfig->batteryFullChargePath.empty())
Ruchi Kandoicc338802015-08-24 13:01:16 -07001079 KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001080 if (mHealthdConfig->batteryCycleCountPath.empty())
Ruchi Kandoicc338802015-08-24 13:01:16 -07001081 KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001082 if (mHealthdConfig->batteryCapacityLevelPath.empty())
Stephane Lee86f9f6a2019-12-19 15:09:41 -08001083 KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001084 if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty())
Stephane Lee86f9f6a2019-12-19 15:09:41 -08001085 KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001086 if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty())
Stephane Lee1c108ed2020-02-10 18:23:57 -08001087 KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001088 if (mHealthdConfig->batteryStateOfHealthPath.empty())
Jack Wue561d032022-11-24 12:19:41 +08001089 KLOG_WARNING(LOG_TAG, "batteryStateOfHealthPath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001090 if (mHealthdConfig->batteryHealthStatusPath.empty())
Jack Wub57f68a2023-02-04 19:56:06 +08001091 KLOG_WARNING(LOG_TAG, "batteryHealthStatusPath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001092 if (mHealthdConfig->batteryManufacturingDatePath.empty())
Jack Wue561d032022-11-24 12:19:41 +08001093 KLOG_WARNING(LOG_TAG, "batteryManufacturingDatePath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001094 if (mHealthdConfig->batteryFirstUsageDatePath.empty())
Jack Wue561d032022-11-24 12:19:41 +08001095 KLOG_WARNING(LOG_TAG, "batteryFirstUsageDatePath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001096 if (mHealthdConfig->chargingStatePath.empty())
Jack Wue561d032022-11-24 12:19:41 +08001097 KLOG_WARNING(LOG_TAG, "chargingStatePath not found\n");
Tomasz Wasilczykf5971292023-08-14 18:18:26 +00001098 if (mHealthdConfig->chargingPolicyPath.empty())
Jack Wue561d032022-11-24 12:19:41 +08001099 KLOG_WARNING(LOG_TAG, "chargingPolicyPath not found\n");
Todd Poynor6dcc45e2013-10-21 20:26:25 -07001100 }
Todd Poynor3db03a52014-05-21 16:28:13 -07001101
Ruchi Kandoia78fc232014-07-10 15:06:21 -07001102 if (property_get("ro.boot.fake_battery", pval, NULL) > 0
1103 && strtol(pval, NULL, 10) != 0) {
1104 mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
1105 mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
1106 }
Todd Poynor752faf22013-06-12 13:25:59 -07001107}
1108
1109}; // namespace android