blob: 4ea452a10f407bff022f0c33d2d0375062f25bec [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
Todd Poynor752faf22013-06-12 13:25:59 -070053
Yifan Hong1d4368b2019-10-07 11:18:04 -070054using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
55using HealthInfo_2_0 = android::hardware::health::V2_0::HealthInfo;
56using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
Yifan Hongb99d15c2022-03-01 12:12:34 -080057using aidl::android::hardware::health::BatteryCapacityLevel;
Jack Wue561d032022-11-24 12:19:41 +080058using aidl::android::hardware::health::BatteryChargingPolicy;
59using aidl::android::hardware::health::BatteryChargingState;
Yifan Hongb99d15c2022-03-01 12:12:34 -080060using aidl::android::hardware::health::BatteryHealth;
Jack Wue561d032022-11-24 12:19:41 +080061using aidl::android::hardware::health::BatteryHealthData;
Yifan Hongb99d15c2022-03-01 12:12:34 -080062using aidl::android::hardware::health::BatteryStatus;
63using aidl::android::hardware::health::HealthInfo;
64
65namespace {
66
67// Translate from AIDL back to HIDL definition for getHealthInfo_*_* calls.
68// Skips storageInfo and diskStats.
69void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
70 ::android::hardware::health::V1_0::HealthInfo* out) {
71 out->chargerAcOnline = in.chargerAcOnline;
72 out->chargerUsbOnline = in.chargerUsbOnline;
73 out->chargerWirelessOnline = in.chargerWirelessOnline;
74 out->maxChargingCurrent = in.maxChargingCurrentMicroamps;
75 out->maxChargingVoltage = in.maxChargingVoltageMicrovolts;
76 out->batteryStatus =
77 static_cast<::android::hardware::health::V1_0::BatteryStatus>(in.batteryStatus);
78 out->batteryHealth =
79 static_cast<::android::hardware::health::V1_0::BatteryHealth>(in.batteryHealth);
80 out->batteryPresent = in.batteryPresent;
81 out->batteryLevel = in.batteryLevel;
82 out->batteryVoltage = in.batteryVoltageMillivolts;
83 out->batteryTemperature = in.batteryTemperatureTenthsCelsius;
84 out->batteryCurrent = in.batteryCurrentMicroamps;
85 out->batteryCycleCount = in.batteryCycleCount;
86 out->batteryFullCharge = in.batteryFullChargeUah;
87 out->batteryChargeCounter = in.batteryChargeCounterUah;
88 out->batteryTechnology = in.batteryTechnology;
89}
90
91void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
92 ::android::hardware::health::V2_0::HealthInfo* out) {
93 translateToHidl(in, &out->legacy);
94 out->batteryCurrentAverage = in.batteryCurrentAverageMicroamps;
95 // Skip storageInfo and diskStats
96}
97
98void translateToHidl(const ::aidl::android::hardware::health::HealthInfo& in,
99 ::android::hardware::health::V2_1::HealthInfo* out) {
100 translateToHidl(in, &out->legacy);
101 out->batteryCapacityLevel = static_cast<android::hardware::health::V2_1::BatteryCapacityLevel>(
102 in.batteryCapacityLevel);
103 out->batteryChargeTimeToFullNowSeconds = in.batteryChargeTimeToFullNowSeconds;
104 out->batteryFullChargeDesignCapacityUah = in.batteryFullChargeDesignCapacityUah;
105}
106
107} // namespace
Yifan Hong1d4368b2019-10-07 11:18:04 -0700108
Todd Poynor752faf22013-06-12 13:25:59 -0700109namespace android {
110
Yifan Hong1d4368b2019-10-07 11:18:04 -0700111template <typename T>
112struct SysfsStringEnumMap {
Mark Salyzyn6f5b47f2014-05-15 15:00:59 -0700113 const char* s;
Yifan Hong1d4368b2019-10-07 11:18:04 -0700114 T val;
Todd Poynor752faf22013-06-12 13:25:59 -0700115};
116
Yifan Hong1d4368b2019-10-07 11:18:04 -0700117template <typename T>
118static std::optional<T> mapSysfsString(const char* str, SysfsStringEnumMap<T> map[]) {
Todd Poynor752faf22013-06-12 13:25:59 -0700119 for (int i = 0; map[i].s; i++)
120 if (!strcmp(str, map[i].s))
121 return map[i].val;
122
Yifan Hong1d4368b2019-10-07 11:18:04 -0700123 return std::nullopt;
Yabin Cuidb04a492016-02-16 17:19:23 -0800124}
125
Yifan Hongb99d15c2022-03-01 12:12:34 -0800126static void initHealthInfo(HealthInfo* health_info) {
Bart Van Assche024e18f2022-02-24 21:22:07 +0000127 *health_info = {
128 .batteryCapacityLevel = BatteryCapacityLevel::UNSUPPORTED,
129 .batteryChargeTimeToFullNowSeconds =
130 (int64_t)HealthInfo::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED,
131 .batteryStatus = BatteryStatus::UNKNOWN,
132 .batteryHealth = BatteryHealth::UNKNOWN,
133 };
Yifan Hong6cabe9b2019-11-05 17:04:50 -0800134}
135
Todd Poynore030a102018-01-19 14:03:59 -0800136BatteryMonitor::BatteryMonitor()
137 : mHealthdConfig(nullptr),
138 mBatteryDevicePresent(false),
139 mBatteryFixedCapacity(0),
Yifan Hong1d4368b2019-10-07 11:18:04 -0700140 mBatteryFixedTemperature(0),
Yifan Hongb99d15c2022-03-01 12:12:34 -0800141 mHealthInfo(std::make_unique<HealthInfo>()) {
Yifan Hong6cabe9b2019-11-05 17:04:50 -0800142 initHealthInfo(mHealthInfo.get());
143}
Yifan Hong1d4368b2019-10-07 11:18:04 -0700144
145BatteryMonitor::~BatteryMonitor() {}
146
Yifan Hongb99d15c2022-03-01 12:12:34 -0800147HealthInfo_1_0 BatteryMonitor::getHealthInfo_1_0() const {
148 HealthInfo_1_0 health_info_1_0;
149 translateToHidl(*mHealthInfo, &health_info_1_0);
150 return health_info_1_0;
Yabin Cuidb04a492016-02-16 17:19:23 -0800151}
152
Yifan Hongb99d15c2022-03-01 12:12:34 -0800153HealthInfo_2_0 BatteryMonitor::getHealthInfo_2_0() const {
154 HealthInfo_2_0 health_info_2_0;
155 translateToHidl(*mHealthInfo, &health_info_2_0);
156 return health_info_2_0;
Hridya Valsaraju7fa72252018-01-12 17:44:33 -0800157}
158
Yifan Hongb99d15c2022-03-01 12:12:34 -0800159HealthInfo_2_1 BatteryMonitor::getHealthInfo_2_1() const {
160 HealthInfo_2_1 health_info_2_1;
161 translateToHidl(*mHealthInfo, &health_info_2_1);
162 return health_info_2_1;
163}
164
165const HealthInfo& BatteryMonitor::getHealthInfo() const {
Yifan Hong1d4368b2019-10-07 11:18:04 -0700166 return *mHealthInfo;
167}
168
169BatteryStatus getBatteryStatus(const char* status) {
170 static SysfsStringEnumMap<BatteryStatus> batteryStatusMap[] = {
171 {"Unknown", BatteryStatus::UNKNOWN},
172 {"Charging", BatteryStatus::CHARGING},
173 {"Discharging", BatteryStatus::DISCHARGING},
174 {"Not charging", BatteryStatus::NOT_CHARGING},
175 {"Full", BatteryStatus::FULL},
176 {NULL, BatteryStatus::UNKNOWN},
Todd Poynor752faf22013-06-12 13:25:59 -0700177 };
178
Yifan Hong1d4368b2019-10-07 11:18:04 -0700179 auto ret = mapSysfsString(status, batteryStatusMap);
180 if (!ret) {
Todd Poynor752faf22013-06-12 13:25:59 -0700181 KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status);
Yifan Hong1d4368b2019-10-07 11:18:04 -0700182 *ret = BatteryStatus::UNKNOWN;
Todd Poynor752faf22013-06-12 13:25:59 -0700183 }
184
Yifan Hong1d4368b2019-10-07 11:18:04 -0700185 return *ret;
Todd Poynor752faf22013-06-12 13:25:59 -0700186}
187
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800188BatteryCapacityLevel getBatteryCapacityLevel(const char* capacityLevel) {
189 static SysfsStringEnumMap<BatteryCapacityLevel> batteryCapacityLevelMap[] = {
190 {"Unknown", BatteryCapacityLevel::UNKNOWN},
191 {"Critical", BatteryCapacityLevel::CRITICAL},
192 {"Low", BatteryCapacityLevel::LOW},
193 {"Normal", BatteryCapacityLevel::NORMAL},
194 {"High", BatteryCapacityLevel::HIGH},
195 {"Full", BatteryCapacityLevel::FULL},
Stephane Lee06846042020-02-12 17:00:24 -0800196 {NULL, BatteryCapacityLevel::UNSUPPORTED},
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800197 };
198
199 auto ret = mapSysfsString(capacityLevel, batteryCapacityLevelMap);
200 if (!ret) {
Stephane Lee06846042020-02-12 17:00:24 -0800201 KLOG_WARNING(LOG_TAG, "Unsupported battery capacity level '%s'\n", capacityLevel);
202 *ret = BatteryCapacityLevel::UNSUPPORTED;
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800203 }
204
205 return *ret;
206}
207
Yifan Hong1d4368b2019-10-07 11:18:04 -0700208BatteryHealth getBatteryHealth(const char* status) {
209 static SysfsStringEnumMap<BatteryHealth> batteryHealthMap[] = {
210 {"Unknown", BatteryHealth::UNKNOWN},
211 {"Good", BatteryHealth::GOOD},
212 {"Overheat", BatteryHealth::OVERHEAT},
213 {"Dead", BatteryHealth::DEAD},
214 {"Over voltage", BatteryHealth::OVER_VOLTAGE},
215 {"Unspecified failure", BatteryHealth::UNSPECIFIED_FAILURE},
216 {"Cold", BatteryHealth::COLD},
217 // battery health values from JEITA spec
218 {"Warm", BatteryHealth::GOOD},
219 {"Cool", BatteryHealth::GOOD},
220 {"Hot", BatteryHealth::OVERHEAT},
221 {NULL, BatteryHealth::UNKNOWN},
Todd Poynor752faf22013-06-12 13:25:59 -0700222 };
223
Yifan Hong1d4368b2019-10-07 11:18:04 -0700224 auto ret = mapSysfsString(status, batteryHealthMap);
225 if (!ret) {
Todd Poynor752faf22013-06-12 13:25:59 -0700226 KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status);
Yifan Hong1d4368b2019-10-07 11:18:04 -0700227 *ret = BatteryHealth::UNKNOWN;
Todd Poynor752faf22013-06-12 13:25:59 -0700228 }
229
Yifan Hong1d4368b2019-10-07 11:18:04 -0700230 return *ret;
Todd Poynor752faf22013-06-12 13:25:59 -0700231}
232
Jack Wue561d032022-11-24 12:19:41 +0800233BatteryChargingPolicy getBatteryChargingPolicy(const char* chargingPolicy) {
234 static SysfsStringEnumMap<BatteryChargingPolicy> batteryChargingPolicyMap[] = {
235 {"0", BatteryChargingPolicy::INVALID}, {"1", BatteryChargingPolicy::DEFAULT},
236 {"2", BatteryChargingPolicy::LONG_LIFE}, {"3", BatteryChargingPolicy::ADAPTIVE},
237 {NULL, BatteryChargingPolicy::DEFAULT},
238 };
239
240 auto ret = mapSysfsString(chargingPolicy, batteryChargingPolicyMap);
241 if (!ret) {
242 *ret = BatteryChargingPolicy::DEFAULT;
243 }
244
245 return *ret;
246}
247
248BatteryChargingState getBatteryChargingState(const char* chargingState) {
249 static SysfsStringEnumMap<BatteryChargingState> batteryChargingStateMap[] = {
250 {"0", BatteryChargingState::INVALID}, {"1", BatteryChargingState::NORMAL},
251 {"2", BatteryChargingState::TOO_COLD}, {"3", BatteryChargingState::TOO_HOT},
252 {"4", BatteryChargingState::LONG_LIFE}, {"5", BatteryChargingState::ADAPTIVE},
253 {NULL, BatteryChargingState::NORMAL},
254 };
255
256 auto ret = mapSysfsString(chargingState, batteryChargingStateMap);
257 if (!ret) {
258 *ret = BatteryChargingState::NORMAL;
259 }
260
261 return *ret;
262}
263
Bart Van Assche095c9442022-03-02 17:36:34 +0000264static int readFromFile(const String8& path, std::string* buf) {
Bart Van Assche5a7e5082022-02-24 21:40:15 +0000265 buf->clear();
Steven Moreland2aac3352017-03-10 22:31:08 -0800266 if (android::base::ReadFileToString(path.c_str(), buf)) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700267 *buf = android::base::Trim(*buf);
Todd Poynor752faf22013-06-12 13:25:59 -0700268 }
Michael Scott3217c5c2016-06-05 11:20:13 -0700269 return buf->length();
Todd Poynor752faf22013-06-12 13:25:59 -0700270}
271
Jack Wue561d032022-11-24 12:19:41 +0800272static bool writeToFile(const String8& path, int32_t in_value) {
273 return android::base::WriteStringToFile(std::to_string(in_value), path.c_str());
274}
275
Bart Van Assche095c9442022-03-02 17:36:34 +0000276static BatteryMonitor::PowerSupplyType readPowerSupplyType(const String8& path) {
Yifan Hong1d4368b2019-10-07 11:18:04 -0700277 static SysfsStringEnumMap<int> supplyTypeMap[] = {
Bart Van Assche095c9442022-03-02 17:36:34 +0000278 {"Unknown", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN},
279 {"Battery", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_BATTERY},
280 {"UPS", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
281 {"Mains", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
282 {"USB", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_USB},
283 {"USB_DCP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
284 {"USB_HVDCP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
285 {"USB_CDP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
286 {"USB_ACA", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
287 {"USB_C", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
288 {"USB_PD", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_AC},
289 {"USB_PD_DRP", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_USB},
290 {"Wireless", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_WIRELESS},
291 {"Dock", BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_DOCK},
Yifan Hong1d4368b2019-10-07 11:18:04 -0700292 {NULL, 0},
Todd Poynor752faf22013-06-12 13:25:59 -0700293 };
Yifan Hong1d4368b2019-10-07 11:18:04 -0700294 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700295
Bart Van Assche095c9442022-03-02 17:36:34 +0000296 if (readFromFile(path, &buf) <= 0) {
297 return BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
298 }
Todd Poynor752faf22013-06-12 13:25:59 -0700299
Yifan Hong1d4368b2019-10-07 11:18:04 -0700300 auto ret = mapSysfsString(buf.c_str(), supplyTypeMap);
John Stultz47a6bf02019-11-06 00:23:34 +0000301 if (!ret) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700302 KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
Bart Van Assche095c9442022-03-02 17:36:34 +0000303 *ret = BatteryMonitor::ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
Johan Redestig32828612016-02-03 13:45:54 +0100304 }
Todd Poynor752faf22013-06-12 13:25:59 -0700305
Yifan Hong1d4368b2019-10-07 11:18:04 -0700306 return static_cast<BatteryMonitor::PowerSupplyType>(*ret);
Todd Poynor752faf22013-06-12 13:25:59 -0700307}
308
Bart Van Assche095c9442022-03-02 17:36:34 +0000309static bool getBooleanField(const String8& path) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700310 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700311 bool value = false;
Michael Scott3217c5c2016-06-05 11:20:13 -0700312
313 if (readFromFile(path, &buf) > 0)
314 if (buf[0] != '0')
Todd Poynor752faf22013-06-12 13:25:59 -0700315 value = true;
Todd Poynor752faf22013-06-12 13:25:59 -0700316
317 return value;
318}
319
Bart Van Assche095c9442022-03-02 17:36:34 +0000320static int getIntField(const String8& path) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700321 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700322 int value = 0;
Michael Scott3217c5c2016-06-05 11:20:13 -0700323
324 if (readFromFile(path, &buf) > 0)
Elliott Hughesda46b392016-10-11 17:09:00 -0700325 android::base::ParseInt(buf, &value);
Michael Scott3217c5c2016-06-05 11:20:13 -0700326
Todd Poynor752faf22013-06-12 13:25:59 -0700327 return value;
328}
329
Bart Van Assche095c9442022-03-02 17:36:34 +0000330static bool isScopedPowerSupply(const char* name) {
Kazuhiro Inaba8e4d9822019-06-12 13:46:08 +0900331 constexpr char kScopeDevice[] = "Device";
332
333 String8 path;
334 path.appendFormat("%s/%s/scope", POWER_SUPPLY_SYSFS_PATH, name);
335 std::string scope;
336 return (readFromFile(path, &scope) > 0 && scope == kScopeDevice);
337}
338
Yifan Hong1353e702019-10-07 10:41:30 -0700339void BatteryMonitor::updateValues(void) {
Yifan Hong6cabe9b2019-11-05 17:04:50 -0800340 initHealthInfo(mHealthInfo.get());
Yifan Hong1d4368b2019-10-07 11:18:04 -0700341
Todd Poynorf5d30122013-08-12 17:03:35 -0700342 if (!mHealthdConfig->batteryPresentPath.isEmpty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800343 mHealthInfo->batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
Todd Poynor752faf22013-06-12 13:25:59 -0700344 else
Yifan Hongb99d15c2022-03-01 12:12:34 -0800345 mHealthInfo->batteryPresent = mBatteryDevicePresent;
Todd Poynor752faf22013-06-12 13:25:59 -0700346
Yifan Hongb99d15c2022-03-01 12:12:34 -0800347 mHealthInfo->batteryLevel = mBatteryFixedCapacity
348 ? mBatteryFixedCapacity
349 : getIntField(mHealthdConfig->batteryCapacityPath);
350 mHealthInfo->batteryVoltageMillivolts = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
Todd Poynorb45f1f52013-07-30 18:57:16 -0700351
Ruchi Kandoicc338802015-08-24 13:01:16 -0700352 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800353 mHealthInfo->batteryCurrentMicroamps = getIntField(mHealthdConfig->batteryCurrentNowPath);
Ruchi Kandoicc338802015-08-24 13:01:16 -0700354
355 if (!mHealthdConfig->batteryFullChargePath.isEmpty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800356 mHealthInfo->batteryFullChargeUah = getIntField(mHealthdConfig->batteryFullChargePath);
Ruchi Kandoicc338802015-08-24 13:01:16 -0700357
358 if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800359 mHealthInfo->batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
Ruchi Kandoicc338802015-08-24 13:01:16 -0700360
Ruchi Kandoi3f9886b2016-04-07 12:34:40 -0700361 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800362 mHealthInfo->batteryChargeCounterUah =
363 getIntField(mHealthdConfig->batteryChargeCounterPath);
Ruchi Kandoi3f9886b2016-04-07 12:34:40 -0700364
Yifan Hong35cb0832019-10-07 13:58:29 -0700365 if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty())
Yifan Hongb99d15c2022-03-01 12:12:34 -0800366 mHealthInfo->batteryCurrentAverageMicroamps =
Yifan Hong35cb0832019-10-07 13:58:29 -0700367 getIntField(mHealthdConfig->batteryCurrentAvgPath);
368
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800369 if (!mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
370 mHealthInfo->batteryChargeTimeToFullNowSeconds =
371 getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath);
372
Stephane Lee1c108ed2020-02-10 18:23:57 -0800373 if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
374 mHealthInfo->batteryFullChargeDesignCapacityUah =
375 getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
Yifan Hong35cb0832019-10-07 13:58:29 -0700376
Jack Wue561d032022-11-24 12:19:41 +0800377 if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty())
378 mHealthInfo->batteryStateOfHealth = getIntField(mHealthdConfig->batteryStateOfHealthPath);
379
380 if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty())
381 mHealthInfo->batteryHealthData->batteryManufacturingDateSeconds =
382 getIntField(mHealthdConfig->batteryManufacturingDatePath);
383
384 if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
385 mHealthInfo->batteryHealthData->batteryFirstUsageSeconds =
386 getIntField(mHealthdConfig->batteryFirstUsageDatePath);
387
Yifan Hongb99d15c2022-03-01 12:12:34 -0800388 mHealthInfo->batteryTemperatureTenthsCelsius =
389 mBatteryFixedTemperature ? mBatteryFixedTemperature
390 : getIntField(mHealthdConfig->batteryTemperaturePath);
Todd Poynor752faf22013-06-12 13:25:59 -0700391
Michael Scott3217c5c2016-06-05 11:20:13 -0700392 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700393
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800394 if (readFromFile(mHealthdConfig->batteryCapacityLevelPath, &buf) > 0)
395 mHealthInfo->batteryCapacityLevel = getBatteryCapacityLevel(buf.c_str());
396
Michael Scott3217c5c2016-06-05 11:20:13 -0700397 if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
Yifan Hongb99d15c2022-03-01 12:12:34 -0800398 mHealthInfo->batteryStatus = getBatteryStatus(buf.c_str());
Todd Poynor752faf22013-06-12 13:25:59 -0700399
Michael Scott3217c5c2016-06-05 11:20:13 -0700400 if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
Yifan Hongb99d15c2022-03-01 12:12:34 -0800401 mHealthInfo->batteryHealth = getBatteryHealth(buf.c_str());
Todd Poynor752faf22013-06-12 13:25:59 -0700402
Michael Scott3217c5c2016-06-05 11:20:13 -0700403 if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
Yifan Hongb99d15c2022-03-01 12:12:34 -0800404 mHealthInfo->batteryTechnology = String8(buf.c_str());
Todd Poynor752faf22013-06-12 13:25:59 -0700405
Jack Wue561d032022-11-24 12:19:41 +0800406 if (readFromFile(mHealthdConfig->chargingPolicyPath, &buf) > 0)
407 mHealthInfo->chargingPolicy = getBatteryChargingPolicy(buf.c_str());
408
409 if (readFromFile(mHealthdConfig->chargingStatePath, &buf) > 0)
410 mHealthInfo->chargingState = getBatteryChargingState(buf.c_str());
411
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700412 double MaxPower = 0;
Todd Poynor752faf22013-06-12 13:25:59 -0700413
ShevT9d98a6a2018-07-26 11:47:47 +0300414 for (size_t i = 0; i < mChargerNames.size(); i++) {
Todd Poynor752faf22013-06-12 13:25:59 -0700415 String8 path;
416 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
417 mChargerNames[i].string());
Michael Scott3217c5c2016-06-05 11:20:13 -0700418 if (getIntField(path)) {
419 path.clear();
420 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
421 mChargerNames[i].string());
422 switch(readPowerSupplyType(path)) {
423 case ANDROID_POWER_SUPPLY_TYPE_AC:
Yifan Hongb99d15c2022-03-01 12:12:34 -0800424 mHealthInfo->chargerAcOnline = true;
Michael Scott3217c5c2016-06-05 11:20:13 -0700425 break;
426 case ANDROID_POWER_SUPPLY_TYPE_USB:
Yifan Hongb99d15c2022-03-01 12:12:34 -0800427 mHealthInfo->chargerUsbOnline = true;
Michael Scott3217c5c2016-06-05 11:20:13 -0700428 break;
429 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
Yifan Hongb99d15c2022-03-01 12:12:34 -0800430 mHealthInfo->chargerWirelessOnline = true;
Michael Scott3217c5c2016-06-05 11:20:13 -0700431 break;
Jack Wu06b90412021-12-15 20:40:21 +0800432 case ANDROID_POWER_SUPPLY_TYPE_DOCK:
Yifan Hongb99d15c2022-03-01 12:12:34 -0800433 mHealthInfo->chargerDockOnline = true;
Jack Wu06b90412021-12-15 20:40:21 +0800434 break;
Michael Scott3217c5c2016-06-05 11:20:13 -0700435 default:
Jack Wu06b90412021-12-15 20:40:21 +0800436 path.clear();
437 path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH,
438 mChargerNames[i].string());
Yifan Hongb99d15c2022-03-01 12:12:34 -0800439 if (access(path.string(), R_OK) == 0)
440 mHealthInfo->chargerDockOnline = true;
441 else
Jack Wu06b90412021-12-15 20:40:21 +0800442 KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
443 mChargerNames[i].string());
Michael Scott3217c5c2016-06-05 11:20:13 -0700444 }
445 path.clear();
446 path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
447 mChargerNames[i].string());
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700448 int ChargingCurrent =
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700449 (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
450
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700451 path.clear();
452 path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
453 mChargerNames[i].string());
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700454
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700455 int ChargingVoltage =
456 (access(path.string(), R_OK) == 0) ? getIntField(path) :
457 DEFAULT_VBUS_VOLTAGE;
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700458
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700459 double power = ((double)ChargingCurrent / MILLION) *
460 ((double)ChargingVoltage / MILLION);
461 if (MaxPower < power) {
Yifan Hongb99d15c2022-03-01 12:12:34 -0800462 mHealthInfo->maxChargingCurrentMicroamps = ChargingCurrent;
463 mHealthInfo->maxChargingVoltageMicrovolts = ChargingVoltage;
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700464 MaxPower = power;
Todd Poynor752faf22013-06-12 13:25:59 -0700465 }
466 }
467 }
Yifan Hong1353e702019-10-07 10:41:30 -0700468}
Todd Poynor752faf22013-06-12 13:25:59 -0700469
Bart Van Assche095c9442022-03-02 17:36:34 +0000470static void doLogValues(const HealthInfo& props, const struct healthd_config& healthd_config) {
Yifan Hong1353e702019-10-07 10:41:30 -0700471 char dmesgline[256];
472 size_t len;
473 if (props.batteryPresent) {
474 snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
Yifan Hongb99d15c2022-03-01 12:12:34 -0800475 props.batteryLevel, props.batteryVoltageMillivolts,
476 props.batteryTemperatureTenthsCelsius < 0 ? "-" : "",
477 abs(props.batteryTemperatureTenthsCelsius / 10),
478 abs(props.batteryTemperatureTenthsCelsius % 10), props.batteryHealth,
479 props.batteryStatus);
Todd Poynorb45f1f52013-07-30 18:57:16 -0700480
Yifan Hong1353e702019-10-07 10:41:30 -0700481 len = strlen(dmesgline);
Yifan Hong605e7d22021-02-08 15:14:48 -0800482 if (!healthd_config.batteryCurrentNowPath.isEmpty()) {
Yifan Hong1353e702019-10-07 10:41:30 -0700483 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
Yifan Hongb99d15c2022-03-01 12:12:34 -0800484 props.batteryCurrentMicroamps);
Todd Poynor10b235e2013-08-07 15:25:14 -0700485 }
486
Yifan Hong605e7d22021-02-08 15:14:48 -0800487 if (!healthd_config.batteryFullChargePath.isEmpty()) {
Yifan Hong1353e702019-10-07 10:41:30 -0700488 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
Yifan Hongb99d15c2022-03-01 12:12:34 -0800489 props.batteryFullChargeUah);
Yifan Hong1353e702019-10-07 10:41:30 -0700490 }
Mark Salyzynacb1ddf2015-07-23 09:22:50 -0700491
Yifan Hong605e7d22021-02-08 15:14:48 -0800492 if (!healthd_config.batteryCycleCountPath.isEmpty()) {
Yifan Hong1353e702019-10-07 10:41:30 -0700493 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
494 props.batteryCycleCount);
495 }
496 } else {
497 len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
Todd Poynorb45f1f52013-07-30 18:57:16 -0700498 }
499
Yifan Hongb99d15c2022-03-01 12:12:34 -0800500 snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s%s",
Yifan Hong1353e702019-10-07 10:41:30 -0700501 props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
Yifan Hongb99d15c2022-03-01 12:12:34 -0800502 props.chargerWirelessOnline ? "w" : "", props.chargerDockOnline ? "d" : "");
Yifan Hong1353e702019-10-07 10:41:30 -0700503
504 KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
505}
506
Bart Van Assche095c9442022-03-02 17:36:34 +0000507void BatteryMonitor::logValues(const HealthInfo_2_1& health_info,
508 const struct healthd_config& healthd_config) {
509 HealthInfo aidl_health_info;
510 (void)android::h2a::translate(health_info, &aidl_health_info);
511 doLogValues(aidl_health_info, healthd_config);
512}
513
514void BatteryMonitor::logValues(void) {
515 doLogValues(*mHealthInfo, *mHealthdConfig);
516}
517
Yifan Hong1353e702019-10-07 10:41:30 -0700518bool BatteryMonitor::isChargerOnline() {
Yifan Hongb99d15c2022-03-01 12:12:34 -0800519 const HealthInfo& props = *mHealthInfo;
Jack Wu06b90412021-12-15 20:40:21 +0800520 return props.chargerAcOnline | props.chargerUsbOnline | props.chargerWirelessOnline |
Yifan Hongb99d15c2022-03-01 12:12:34 -0800521 props.chargerDockOnline;
Todd Poynor752faf22013-06-12 13:25:59 -0700522}
523
Yabin Cuiaedf6032016-02-19 18:03:23 -0800524int BatteryMonitor::getChargeStatus() {
Yifan Hong1d4368b2019-10-07 11:18:04 -0700525 BatteryStatus result = BatteryStatus::UNKNOWN;
Yabin Cuiaedf6032016-02-19 18:03:23 -0800526 if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700527 std::string buf;
528 if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
529 result = getBatteryStatus(buf.c_str());
Yabin Cuiaedf6032016-02-19 18:03:23 -0800530 }
Yifan Hong1d4368b2019-10-07 11:18:04 -0700531 return static_cast<int>(result);
Yabin Cuiaedf6032016-02-19 18:03:23 -0800532}
533
Jack Wue561d032022-11-24 12:19:41 +0800534status_t BatteryMonitor::setChargingPolicy(int value) {
535 status_t ret = NAME_NOT_FOUND;
536 bool result;
537 if (!mHealthdConfig->chargingPolicyPath.isEmpty()) {
538 result = writeToFile(mHealthdConfig->chargingPolicyPath, value);
539 if (!result) {
540 KLOG_WARNING(LOG_TAG, "setChargingPolicy fail\n");
541 ret = BAD_VALUE;
542 } else {
543 ret = OK;
544 }
545 }
546 return ret;
547}
548
549int BatteryMonitor::getChargingPolicy() {
550 BatteryChargingPolicy result = BatteryChargingPolicy::DEFAULT;
551 if (!mHealthdConfig->chargingPolicyPath.isEmpty()) {
552 std::string buf;
553 if (readFromFile(mHealthdConfig->chargingPolicyPath, &buf) > 0)
554 result = getBatteryChargingPolicy(buf.c_str());
555 }
556 return static_cast<int>(result);
557}
558
559int BatteryMonitor::getBatteryHealthData(int id) {
560 if (id == BATTERY_PROP_MANUFACTURING_DATE) {
561 if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty())
562 return getIntField(mHealthdConfig->batteryManufacturingDatePath);
563 }
564 if (id == BATTERY_PROP_FIRST_USAGE_DATE) {
565 if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
566 return getIntField(mHealthdConfig->batteryFirstUsageDatePath);
567 }
568 return 0;
569}
570
Todd Poynorc133b712013-08-14 17:39:13 -0700571status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
572 status_t ret = BAD_VALUE;
Jin Qian72adf112017-02-02 17:31:13 -0800573 std::string buf;
Todd Poynorc133b712013-08-14 17:39:13 -0700574
Todd Poynor8f132af2014-05-08 17:15:45 -0700575 val->valueInt64 = LONG_MIN;
576
Todd Poynorc133b712013-08-14 17:39:13 -0700577 switch(id) {
578 case BATTERY_PROP_CHARGE_COUNTER:
579 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700580 val->valueInt64 =
Todd Poynorc133b712013-08-14 17:39:13 -0700581 getIntField(mHealthdConfig->batteryChargeCounterPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700582 ret = OK;
Todd Poynorc133b712013-08-14 17:39:13 -0700583 } else {
584 ret = NAME_NOT_FOUND;
585 }
586 break;
587
588 case BATTERY_PROP_CURRENT_NOW:
589 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700590 val->valueInt64 =
Todd Poynorc133b712013-08-14 17:39:13 -0700591 getIntField(mHealthdConfig->batteryCurrentNowPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700592 ret = OK;
Todd Poynorc133b712013-08-14 17:39:13 -0700593 } else {
594 ret = NAME_NOT_FOUND;
595 }
596 break;
597
Todd Poynorbc102112013-08-27 18:11:49 -0700598 case BATTERY_PROP_CURRENT_AVG:
599 if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700600 val->valueInt64 =
Todd Poynorbc102112013-08-27 18:11:49 -0700601 getIntField(mHealthdConfig->batteryCurrentAvgPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700602 ret = OK;
Todd Poynorbc102112013-08-27 18:11:49 -0700603 } else {
604 ret = NAME_NOT_FOUND;
605 }
606 break;
607
Paul Lawrence347c8de2014-03-19 15:04:40 -0700608 case BATTERY_PROP_CAPACITY:
609 if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700610 val->valueInt64 =
Paul Lawrence347c8de2014-03-19 15:04:40 -0700611 getIntField(mHealthdConfig->batteryCapacityPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700612 ret = OK;
Paul Lawrence347c8de2014-03-19 15:04:40 -0700613 } else {
614 ret = NAME_NOT_FOUND;
615 }
616 break;
617
Todd Poynor8f132af2014-05-08 17:15:45 -0700618 case BATTERY_PROP_ENERGY_COUNTER:
Todd Poynore14b37e2014-05-20 13:54:40 -0700619 if (mHealthdConfig->energyCounter) {
620 ret = mHealthdConfig->energyCounter(&val->valueInt64);
621 } else {
622 ret = NAME_NOT_FOUND;
623 }
Todd Poynor8f132af2014-05-08 17:15:45 -0700624 break;
625
Jin Qian72adf112017-02-02 17:31:13 -0800626 case BATTERY_PROP_BATTERY_STATUS:
Todd Poynore030a102018-01-19 14:03:59 -0800627 val->valueInt64 = getChargeStatus();
Elliott Hughes643268f2018-10-08 11:10:11 -0700628 ret = OK;
Jin Qian72adf112017-02-02 17:31:13 -0800629 break;
630
Jack Wue561d032022-11-24 12:19:41 +0800631 case BATTERY_PROP_CHARGING_POLICY:
632 val->valueInt64 = getChargingPolicy();
633 ret = OK;
634 break;
635
636 case BATTERY_PROP_MANUFACTURING_DATE:
637 val->valueInt64 = getBatteryHealthData(BATTERY_PROP_MANUFACTURING_DATE);
638 ret = OK;
639 break;
640
641 case BATTERY_PROP_FIRST_USAGE_DATE:
642 val->valueInt64 = getBatteryHealthData(BATTERY_PROP_FIRST_USAGE_DATE);
643 ret = OK;
644 break;
645
Todd Poynorc133b712013-08-14 17:39:13 -0700646 default:
647 break;
648 }
649
Todd Poynorc133b712013-08-14 17:39:13 -0700650 return ret;
651}
652
Todd Poynor020369d2013-09-18 20:09:33 -0700653void BatteryMonitor::dumpState(int fd) {
654 int v;
655 char vs[128];
Yifan Hongb99d15c2022-03-01 12:12:34 -0800656 const HealthInfo& props = *mHealthInfo;
Todd Poynor020369d2013-09-18 20:09:33 -0700657
Jack Wu06b90412021-12-15 20:40:21 +0800658 snprintf(vs, sizeof(vs),
659 "ac: %d usb: %d wireless: %d dock: %d current_max: %d voltage_max: %d\n",
660 props.chargerAcOnline, props.chargerUsbOnline, props.chargerWirelessOnline,
Yifan Hongb99d15c2022-03-01 12:12:34 -0800661 props.chargerDockOnline, props.maxChargingCurrentMicroamps,
662 props.maxChargingVoltageMicrovolts);
Todd Poynor020369d2013-09-18 20:09:33 -0700663 write(fd, vs, strlen(vs));
664 snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
665 props.batteryStatus, props.batteryHealth, props.batteryPresent);
666 write(fd, vs, strlen(vs));
Yifan Hongb99d15c2022-03-01 12:12:34 -0800667 snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n", props.batteryLevel,
668 props.batteryVoltageMillivolts, props.batteryTemperatureTenthsCelsius);
Todd Poynor020369d2013-09-18 20:09:33 -0700669 write(fd, vs, strlen(vs));
670
671 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
672 v = getIntField(mHealthdConfig->batteryCurrentNowPath);
673 snprintf(vs, sizeof(vs), "current now: %d\n", v);
674 write(fd, vs, strlen(vs));
675 }
676
677 if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
678 v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
679 snprintf(vs, sizeof(vs), "current avg: %d\n", v);
680 write(fd, vs, strlen(vs));
681 }
682
683 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
684 v = getIntField(mHealthdConfig->batteryChargeCounterPath);
685 snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
686 write(fd, vs, strlen(vs));
687 }
Ruchi Kandoicc338802015-08-24 13:01:16 -0700688
689 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
Yifan Hongb99d15c2022-03-01 12:12:34 -0800690 snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrentMicroamps);
Ruchi Kandoicc338802015-08-24 13:01:16 -0700691 write(fd, vs, strlen(vs));
692 }
693
694 if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
695 snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
696 write(fd, vs, strlen(vs));
697 }
698
699 if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
Yifan Hongb99d15c2022-03-01 12:12:34 -0800700 snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullChargeUah);
Ruchi Kandoicc338802015-08-24 13:01:16 -0700701 write(fd, vs, strlen(vs));
702 }
Todd Poynor020369d2013-09-18 20:09:33 -0700703}
704
Todd Poynorc7464c92013-09-10 12:40:00 -0700705void BatteryMonitor::init(struct healthd_config *hc) {
Todd Poynor752faf22013-06-12 13:25:59 -0700706 String8 path;
Todd Poynor3db03a52014-05-21 16:28:13 -0700707 char pval[PROPERTY_VALUE_MAX];
Todd Poynor752faf22013-06-12 13:25:59 -0700708
Todd Poynorf5d30122013-08-12 17:03:35 -0700709 mHealthdConfig = hc;
James Hawkins588a2ca2016-02-18 14:52:46 -0800710 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
Todd Poynor752faf22013-06-12 13:25:59 -0700711 if (dir == NULL) {
712 KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
713 } else {
714 struct dirent* entry;
715
James Hawkins588a2ca2016-02-18 14:52:46 -0800716 while ((entry = readdir(dir.get()))) {
Todd Poynor752faf22013-06-12 13:25:59 -0700717 const char* name = entry->d_name;
718
719 if (!strcmp(name, ".") || !strcmp(name, ".."))
720 continue;
721
Bart Van Assche25b2a8d2022-02-24 21:51:34 +0000722 std::vector<String8>::iterator itIgnoreName =
723 find(hc->ignorePowerSupplyNames.begin(), hc->ignorePowerSupplyNames.end(),
724 String8(name));
Thierry Strudelf73de6f2019-01-11 17:09:20 -0800725 if (itIgnoreName != hc->ignorePowerSupplyNames.end())
726 continue;
727
Todd Poynor752faf22013-06-12 13:25:59 -0700728 // Look for "type" file in each subdirectory
729 path.clear();
730 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
731 switch(readPowerSupplyType(path)) {
732 case ANDROID_POWER_SUPPLY_TYPE_AC:
733 case ANDROID_POWER_SUPPLY_TYPE_USB:
734 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
Jack Wu06b90412021-12-15 20:40:21 +0800735 case ANDROID_POWER_SUPPLY_TYPE_DOCK:
Todd Poynor752faf22013-06-12 13:25:59 -0700736 path.clear();
737 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
738 if (access(path.string(), R_OK) == 0)
739 mChargerNames.add(String8(name));
740 break;
741
742 case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
Kazuhiro Inaba8e4d9822019-06-12 13:46:08 +0900743 // Some devices expose the battery status of sub-component like
744 // stylus. Such a device-scoped battery info needs to be skipped
745 // in BatteryMonitor, which is intended to report the status of
746 // the battery supplying the power to the whole system.
747 if (isScopedPowerSupply(name)) continue;
Todd Poynor6dcc45e2013-10-21 20:26:25 -0700748 mBatteryDevicePresent = true;
749
Todd Poynorf5d30122013-08-12 17:03:35 -0700750 if (mHealthdConfig->batteryStatusPath.isEmpty()) {
Todd Poynor752faf22013-06-12 13:25:59 -0700751 path.clear();
Todd Poynorf5d30122013-08-12 17:03:35 -0700752 path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
753 name);
Todd Poynor752faf22013-06-12 13:25:59 -0700754 if (access(path, R_OK) == 0)
Todd Poynorf5d30122013-08-12 17:03:35 -0700755 mHealthdConfig->batteryStatusPath = path;
Todd Poynor752faf22013-06-12 13:25:59 -0700756 }
757
Todd Poynorf5d30122013-08-12 17:03:35 -0700758 if (mHealthdConfig->batteryHealthPath.isEmpty()) {
Todd Poynor752faf22013-06-12 13:25:59 -0700759 path.clear();
Todd Poynorf5d30122013-08-12 17:03:35 -0700760 path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
761 name);
Todd Poynor752faf22013-06-12 13:25:59 -0700762 if (access(path, R_OK) == 0)
Todd Poynorf5d30122013-08-12 17:03:35 -0700763 mHealthdConfig->batteryHealthPath = path;
Todd Poynor752faf22013-06-12 13:25:59 -0700764 }
765
Todd Poynorf5d30122013-08-12 17:03:35 -0700766 if (mHealthdConfig->batteryPresentPath.isEmpty()) {
767 path.clear();
768 path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
769 name);
770 if (access(path, R_OK) == 0)
771 mHealthdConfig->batteryPresentPath = path;
772 }
773
774 if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
775 path.clear();
776 path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
777 name);
778 if (access(path, R_OK) == 0)
779 mHealthdConfig->batteryCapacityPath = path;
780 }
781
782 if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
783 path.clear();
784 path.appendFormat("%s/%s/voltage_now",
785 POWER_SUPPLY_SYSFS_PATH, name);
786 if (access(path, R_OK) == 0) {
787 mHealthdConfig->batteryVoltagePath = path;
Todd Poynorf5d30122013-08-12 17:03:35 -0700788 }
789 }
790
Ruchi Kandoicc338802015-08-24 13:01:16 -0700791 if (mHealthdConfig->batteryFullChargePath.isEmpty()) {
792 path.clear();
793 path.appendFormat("%s/%s/charge_full",
794 POWER_SUPPLY_SYSFS_PATH, name);
795 if (access(path, R_OK) == 0)
796 mHealthdConfig->batteryFullChargePath = path;
797 }
798
Todd Poynorf5d30122013-08-12 17:03:35 -0700799 if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
800 path.clear();
801 path.appendFormat("%s/%s/current_now",
802 POWER_SUPPLY_SYSFS_PATH, name);
803 if (access(path, R_OK) == 0)
804 mHealthdConfig->batteryCurrentNowPath = path;
805 }
806
Ruchi Kandoicc338802015-08-24 13:01:16 -0700807 if (mHealthdConfig->batteryCycleCountPath.isEmpty()) {
808 path.clear();
809 path.appendFormat("%s/%s/cycle_count",
810 POWER_SUPPLY_SYSFS_PATH, name);
811 if (access(path, R_OK) == 0)
812 mHealthdConfig->batteryCycleCountPath = path;
813 }
814
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800815 if (mHealthdConfig->batteryCapacityLevelPath.isEmpty()) {
816 path.clear();
817 path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name);
818 if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityLevelPath = path;
819 }
820
821 if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) {
822 path.clear();
823 path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name);
824 if (access(path, R_OK) == 0)
825 mHealthdConfig->batteryChargeTimeToFullNowPath = path;
826 }
827
Stephane Lee1c108ed2020-02-10 18:23:57 -0800828 if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) {
829 path.clear();
830 path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name);
831 if (access(path, R_OK) == 0)
832 mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path;
833 }
834
Todd Poynorbc102112013-08-27 18:11:49 -0700835 if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
836 path.clear();
837 path.appendFormat("%s/%s/current_avg",
838 POWER_SUPPLY_SYSFS_PATH, name);
839 if (access(path, R_OK) == 0)
840 mHealthdConfig->batteryCurrentAvgPath = path;
841 }
842
Todd Poynorf5d30122013-08-12 17:03:35 -0700843 if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
844 path.clear();
845 path.appendFormat("%s/%s/charge_counter",
846 POWER_SUPPLY_SYSFS_PATH, name);
847 if (access(path, R_OK) == 0)
848 mHealthdConfig->batteryChargeCounterPath = path;
849 }
850
851 if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
852 path.clear();
853 path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
854 name);
855 if (access(path, R_OK) == 0) {
856 mHealthdConfig->batteryTemperaturePath = path;
Todd Poynorf5d30122013-08-12 17:03:35 -0700857 }
858 }
859
860 if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
861 path.clear();
862 path.appendFormat("%s/%s/technology",
863 POWER_SUPPLY_SYSFS_PATH, name);
864 if (access(path, R_OK) == 0)
865 mHealthdConfig->batteryTechnologyPath = path;
866 }
867
Jack Wue561d032022-11-24 12:19:41 +0800868 if (mHealthdConfig->batteryStateOfHealthPath.isEmpty()) {
869 path.clear();
870 path.appendFormat("%s/%s/state_of_health", POWER_SUPPLY_SYSFS_PATH, name);
871 if (access(path, R_OK) == 0) {
872 mHealthdConfig->batteryStateOfHealthPath = path;
873 } else {
874 path.clear();
875 path.appendFormat("%s/%s/health_index", POWER_SUPPLY_SYSFS_PATH, name);
876 if (access(path, R_OK) == 0)
877 mHealthdConfig->batteryStateOfHealthPath = path;
878 }
879 }
880
881 if (mHealthdConfig->batteryManufacturingDatePath.isEmpty()) {
882 path.clear();
883 path.appendFormat("%s/%s/manufacturing_date", POWER_SUPPLY_SYSFS_PATH, name);
884 if (access(path, R_OK) == 0)
885 mHealthdConfig->batteryManufacturingDatePath = path;
886 }
887
888 if (mHealthdConfig->batteryFirstUsageDatePath.isEmpty()) {
889 path.clear();
890 path.appendFormat("%s/%s/first_usage_date", POWER_SUPPLY_SYSFS_PATH, name);
891 if (access(path, R_OK) == 0) mHealthdConfig->batteryFirstUsageDatePath = path;
892 }
893
894 if (mHealthdConfig->chargingStatePath.isEmpty()) {
895 path.clear();
896 path.appendFormat("%s/%s/charging_state", POWER_SUPPLY_SYSFS_PATH, name);
897 if (access(path, R_OK) == 0) mHealthdConfig->chargingStatePath = path;
898 }
899
900 if (mHealthdConfig->chargingPolicyPath.isEmpty()) {
901 path.clear();
902 path.appendFormat("%s/%s/charging_policy", POWER_SUPPLY_SYSFS_PATH, name);
903 if (access(path, R_OK) == 0) mHealthdConfig->chargingPolicyPath = path;
904 }
905
Todd Poynor752faf22013-06-12 13:25:59 -0700906 break;
907
908 case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
909 break;
910 }
Jack Wu06b90412021-12-15 20:40:21 +0800911
912 // Look for "is_dock" file
913 path.clear();
914 path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name);
915 if (access(path.string(), R_OK) == 0) {
916 path.clear();
917 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
918 if (access(path.string(), R_OK) == 0)
919 mChargerNames.add(String8(name));
920
921 }
Todd Poynor752faf22013-06-12 13:25:59 -0700922 }
Todd Poynor752faf22013-06-12 13:25:59 -0700923 }
924
Ian Pedowitz585ab652015-10-12 19:01:00 -0700925 // Typically the case for devices which do not have a battery and
926 // and are always plugged into AC mains.
Todd Poynor6dcc45e2013-10-21 20:26:25 -0700927 if (!mBatteryDevicePresent) {
Todd Poynorebeb0c02014-09-23 14:54:24 -0700928 KLOG_WARNING(LOG_TAG, "No battery devices found\n");
Todd Poynor6dcc45e2013-10-21 20:26:25 -0700929 hc->periodic_chores_interval_fast = -1;
930 hc->periodic_chores_interval_slow = -1;
931 } else {
932 if (mHealthdConfig->batteryStatusPath.isEmpty())
933 KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
934 if (mHealthdConfig->batteryHealthPath.isEmpty())
935 KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
936 if (mHealthdConfig->batteryPresentPath.isEmpty())
937 KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
938 if (mHealthdConfig->batteryCapacityPath.isEmpty())
939 KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
940 if (mHealthdConfig->batteryVoltagePath.isEmpty())
941 KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
942 if (mHealthdConfig->batteryTemperaturePath.isEmpty())
943 KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
944 if (mHealthdConfig->batteryTechnologyPath.isEmpty())
945 KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
Ruchi Kandoif18ec9f2015-09-28 13:35:59 -0700946 if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
Ruchi Kandoicc338802015-08-24 13:01:16 -0700947 KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
948 if (mHealthdConfig->batteryFullChargePath.isEmpty())
949 KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
950 if (mHealthdConfig->batteryCycleCountPath.isEmpty())
951 KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
Stephane Lee86f9f6a2019-12-19 15:09:41 -0800952 if (mHealthdConfig->batteryCapacityLevelPath.isEmpty())
953 KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n");
954 if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
955 KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n");
Stephane Lee1c108ed2020-02-10 18:23:57 -0800956 if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
957 KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n");
Jack Wue561d032022-11-24 12:19:41 +0800958 if (mHealthdConfig->batteryStateOfHealthPath.isEmpty())
959 KLOG_WARNING(LOG_TAG, "batteryStateOfHealthPath not found\n");
960 if (mHealthdConfig->batteryManufacturingDatePath.isEmpty())
961 KLOG_WARNING(LOG_TAG, "batteryManufacturingDatePath not found\n");
962 if (mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
963 KLOG_WARNING(LOG_TAG, "batteryFirstUsageDatePath not found\n");
964 if (mHealthdConfig->chargingStatePath.isEmpty())
965 KLOG_WARNING(LOG_TAG, "chargingStatePath not found\n");
966 if (mHealthdConfig->chargingPolicyPath.isEmpty())
967 KLOG_WARNING(LOG_TAG, "chargingPolicyPath not found\n");
Todd Poynor6dcc45e2013-10-21 20:26:25 -0700968 }
Todd Poynor3db03a52014-05-21 16:28:13 -0700969
Ruchi Kandoia78fc232014-07-10 15:06:21 -0700970 if (property_get("ro.boot.fake_battery", pval, NULL) > 0
971 && strtol(pval, NULL, 10) != 0) {
972 mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
973 mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
974 }
Todd Poynor752faf22013-06-12 13:25:59 -0700975}
976
977}; // namespace android