blob: cdc2e5d284086f2b2c963be0cf8b3901925445b6 [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
Michael Scott3217c5c2016-06-05 11:20:13 -070034#include <android-base/file.h>
Elliott Hughesda46b392016-10-11 17:09:00 -070035#include <android-base/parseint.h>
Michael Scott3217c5c2016-06-05 11:20:13 -070036#include <android-base/strings.h>
Yifan Hong1d4368b2019-10-07 11:18:04 -070037#include <android/hardware/health/2.1/types.h>
Todd Poynor752faf22013-06-12 13:25:59 -070038#include <batteryservice/BatteryService.h>
39#include <cutils/klog.h>
Todd Poynor3db03a52014-05-21 16:28:13 -070040#include <cutils/properties.h>
Todd Poynorc133b712013-08-14 17:39:13 -070041#include <utils/Errors.h>
Todd Poynor752faf22013-06-12 13:25:59 -070042#include <utils/String8.h>
43#include <utils/Vector.h>
44
45#define POWER_SUPPLY_SUBSYSTEM "power_supply"
46#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
Ruchi Kandoia78fc232014-07-10 15:06:21 -070047#define FAKE_BATTERY_CAPACITY 42
48#define FAKE_BATTERY_TEMPERATURE 424
Ruchi Kandoi5c09ec12016-02-25 16:19:30 -080049#define MILLION 1.0e6
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -070050#define DEFAULT_VBUS_VOLTAGE 5000000
Todd Poynor752faf22013-06-12 13:25:59 -070051
Yifan Hong1d4368b2019-10-07 11:18:04 -070052using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
53using HealthInfo_2_0 = android::hardware::health::V2_0::HealthInfo;
54using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
55using android::hardware::health::V1_0::BatteryHealth;
56using android::hardware::health::V1_0::BatteryStatus;
57
Todd Poynor752faf22013-06-12 13:25:59 -070058namespace android {
59
Yifan Hong1d4368b2019-10-07 11:18:04 -070060template <typename T>
61struct SysfsStringEnumMap {
Mark Salyzyn6f5b47f2014-05-15 15:00:59 -070062 const char* s;
Yifan Hong1d4368b2019-10-07 11:18:04 -070063 T val;
Todd Poynor752faf22013-06-12 13:25:59 -070064};
65
Yifan Hong1d4368b2019-10-07 11:18:04 -070066template <typename T>
67static std::optional<T> mapSysfsString(const char* str, SysfsStringEnumMap<T> map[]) {
Todd Poynor752faf22013-06-12 13:25:59 -070068 for (int i = 0; map[i].s; i++)
69 if (!strcmp(str, map[i].s))
70 return map[i].val;
71
Yifan Hong1d4368b2019-10-07 11:18:04 -070072 return std::nullopt;
Yabin Cuidb04a492016-02-16 17:19:23 -080073}
74
Todd Poynore030a102018-01-19 14:03:59 -080075BatteryMonitor::BatteryMonitor()
76 : mHealthdConfig(nullptr),
77 mBatteryDevicePresent(false),
78 mBatteryFixedCapacity(0),
Yifan Hong1d4368b2019-10-07 11:18:04 -070079 mBatteryFixedTemperature(0),
80 mHealthInfo(std::make_unique<HealthInfo_2_1>()) {}
81
82BatteryMonitor::~BatteryMonitor() {}
83
84const HealthInfo_1_0& BatteryMonitor::getHealthInfo_1_0() const {
85 return getHealthInfo_2_0().legacy;
Yabin Cuidb04a492016-02-16 17:19:23 -080086}
87
Yifan Hong1d4368b2019-10-07 11:18:04 -070088const HealthInfo_2_0& BatteryMonitor::getHealthInfo_2_0() const {
89 return getHealthInfo_2_1().legacy;
Hridya Valsaraju7fa72252018-01-12 17:44:33 -080090}
91
Yifan Hong1d4368b2019-10-07 11:18:04 -070092const HealthInfo_2_1& BatteryMonitor::getHealthInfo_2_1() const {
93 return *mHealthInfo;
94}
95
96BatteryStatus getBatteryStatus(const char* status) {
97 static SysfsStringEnumMap<BatteryStatus> batteryStatusMap[] = {
98 {"Unknown", BatteryStatus::UNKNOWN},
99 {"Charging", BatteryStatus::CHARGING},
100 {"Discharging", BatteryStatus::DISCHARGING},
101 {"Not charging", BatteryStatus::NOT_CHARGING},
102 {"Full", BatteryStatus::FULL},
103 {NULL, BatteryStatus::UNKNOWN},
Todd Poynor752faf22013-06-12 13:25:59 -0700104 };
105
Yifan Hong1d4368b2019-10-07 11:18:04 -0700106 auto ret = mapSysfsString(status, batteryStatusMap);
107 if (!ret) {
Todd Poynor752faf22013-06-12 13:25:59 -0700108 KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status);
Yifan Hong1d4368b2019-10-07 11:18:04 -0700109 *ret = BatteryStatus::UNKNOWN;
Todd Poynor752faf22013-06-12 13:25:59 -0700110 }
111
Yifan Hong1d4368b2019-10-07 11:18:04 -0700112 return *ret;
Todd Poynor752faf22013-06-12 13:25:59 -0700113}
114
Yifan Hong1d4368b2019-10-07 11:18:04 -0700115BatteryHealth getBatteryHealth(const char* status) {
116 static SysfsStringEnumMap<BatteryHealth> batteryHealthMap[] = {
117 {"Unknown", BatteryHealth::UNKNOWN},
118 {"Good", BatteryHealth::GOOD},
119 {"Overheat", BatteryHealth::OVERHEAT},
120 {"Dead", BatteryHealth::DEAD},
121 {"Over voltage", BatteryHealth::OVER_VOLTAGE},
122 {"Unspecified failure", BatteryHealth::UNSPECIFIED_FAILURE},
123 {"Cold", BatteryHealth::COLD},
124 // battery health values from JEITA spec
125 {"Warm", BatteryHealth::GOOD},
126 {"Cool", BatteryHealth::GOOD},
127 {"Hot", BatteryHealth::OVERHEAT},
128 {NULL, BatteryHealth::UNKNOWN},
Todd Poynor752faf22013-06-12 13:25:59 -0700129 };
130
Yifan Hong1d4368b2019-10-07 11:18:04 -0700131 auto ret = mapSysfsString(status, batteryHealthMap);
132 if (!ret) {
Todd Poynor752faf22013-06-12 13:25:59 -0700133 KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status);
Yifan Hong1d4368b2019-10-07 11:18:04 -0700134 *ret = BatteryHealth::UNKNOWN;
Todd Poynor752faf22013-06-12 13:25:59 -0700135 }
136
Yifan Hong1d4368b2019-10-07 11:18:04 -0700137 return *ret;
Todd Poynor752faf22013-06-12 13:25:59 -0700138}
139
Michael Scott3217c5c2016-06-05 11:20:13 -0700140int BatteryMonitor::readFromFile(const String8& path, std::string* buf) {
Steven Moreland2aac3352017-03-10 22:31:08 -0800141 if (android::base::ReadFileToString(path.c_str(), buf)) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700142 *buf = android::base::Trim(*buf);
Todd Poynor752faf22013-06-12 13:25:59 -0700143 }
Michael Scott3217c5c2016-06-05 11:20:13 -0700144 return buf->length();
Todd Poynor752faf22013-06-12 13:25:59 -0700145}
146
147BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
Yifan Hong1d4368b2019-10-07 11:18:04 -0700148 static SysfsStringEnumMap<int> supplyTypeMap[] = {
149 {"Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN},
150 {"Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY},
151 {"UPS", ANDROID_POWER_SUPPLY_TYPE_AC},
152 {"Mains", ANDROID_POWER_SUPPLY_TYPE_AC},
153 {"USB", ANDROID_POWER_SUPPLY_TYPE_USB},
154 {"USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC},
155 {"USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC},
156 {"USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC},
157 {"USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC},
158 {"USB_C", ANDROID_POWER_SUPPLY_TYPE_AC},
159 {"USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC},
160 {"USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB},
161 {"Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS},
162 {NULL, 0},
Todd Poynor752faf22013-06-12 13:25:59 -0700163 };
Yifan Hong1d4368b2019-10-07 11:18:04 -0700164 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700165
Michael Scott3217c5c2016-06-05 11:20:13 -0700166 if (readFromFile(path, &buf) <= 0)
Todd Poynor752faf22013-06-12 13:25:59 -0700167 return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
168
Yifan Hong1d4368b2019-10-07 11:18:04 -0700169 auto ret = mapSysfsString(buf.c_str(), supplyTypeMap);
Johan Redestig32828612016-02-03 13:45:54 +0100170 if (ret < 0) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700171 KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
Yifan Hong1d4368b2019-10-07 11:18:04 -0700172 *ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
Johan Redestig32828612016-02-03 13:45:54 +0100173 }
Todd Poynor752faf22013-06-12 13:25:59 -0700174
Yifan Hong1d4368b2019-10-07 11:18:04 -0700175 return static_cast<BatteryMonitor::PowerSupplyType>(*ret);
Todd Poynor752faf22013-06-12 13:25:59 -0700176}
177
178bool BatteryMonitor::getBooleanField(const String8& path) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700179 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700180 bool value = false;
Michael Scott3217c5c2016-06-05 11:20:13 -0700181
182 if (readFromFile(path, &buf) > 0)
183 if (buf[0] != '0')
Todd Poynor752faf22013-06-12 13:25:59 -0700184 value = true;
Todd Poynor752faf22013-06-12 13:25:59 -0700185
186 return value;
187}
188
189int BatteryMonitor::getIntField(const String8& path) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700190 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700191 int value = 0;
Michael Scott3217c5c2016-06-05 11:20:13 -0700192
193 if (readFromFile(path, &buf) > 0)
Elliott Hughesda46b392016-10-11 17:09:00 -0700194 android::base::ParseInt(buf, &value);
Michael Scott3217c5c2016-06-05 11:20:13 -0700195
Todd Poynor752faf22013-06-12 13:25:59 -0700196 return value;
197}
198
Yifan Hong1353e702019-10-07 10:41:30 -0700199void BatteryMonitor::updateValues(void) {
Yifan Hong1d4368b2019-10-07 11:18:04 -0700200 *mHealthInfo = HealthInfo_2_1{};
201
202 HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
Todd Poynor752faf22013-06-12 13:25:59 -0700203
Todd Poynorf5d30122013-08-12 17:03:35 -0700204 if (!mHealthdConfig->batteryPresentPath.isEmpty())
205 props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
Todd Poynor752faf22013-06-12 13:25:59 -0700206 else
Todd Poynor6dcc45e2013-10-21 20:26:25 -0700207 props.batteryPresent = mBatteryDevicePresent;
Todd Poynor752faf22013-06-12 13:25:59 -0700208
Todd Poynor3db03a52014-05-21 16:28:13 -0700209 props.batteryLevel = mBatteryFixedCapacity ?
210 mBatteryFixedCapacity :
211 getIntField(mHealthdConfig->batteryCapacityPath);
Todd Poynorf5d30122013-08-12 17:03:35 -0700212 props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
Todd Poynorb45f1f52013-07-30 18:57:16 -0700213
Ruchi Kandoicc338802015-08-24 13:01:16 -0700214 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
215 props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath) / 1000;
216
217 if (!mHealthdConfig->batteryFullChargePath.isEmpty())
218 props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath);
219
220 if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
221 props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
222
Ruchi Kandoi3f9886b2016-04-07 12:34:40 -0700223 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
224 props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
225
Todd Poynor3db03a52014-05-21 16:28:13 -0700226 props.batteryTemperature = mBatteryFixedTemperature ?
227 mBatteryFixedTemperature :
228 getIntField(mHealthdConfig->batteryTemperaturePath);
Todd Poynor752faf22013-06-12 13:25:59 -0700229
Michael Scott3217c5c2016-06-05 11:20:13 -0700230 std::string buf;
Todd Poynor752faf22013-06-12 13:25:59 -0700231
Michael Scott3217c5c2016-06-05 11:20:13 -0700232 if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
233 props.batteryStatus = getBatteryStatus(buf.c_str());
Todd Poynor752faf22013-06-12 13:25:59 -0700234
Michael Scott3217c5c2016-06-05 11:20:13 -0700235 if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
236 props.batteryHealth = getBatteryHealth(buf.c_str());
Todd Poynor752faf22013-06-12 13:25:59 -0700237
Michael Scott3217c5c2016-06-05 11:20:13 -0700238 if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
239 props.batteryTechnology = String8(buf.c_str());
Todd Poynor752faf22013-06-12 13:25:59 -0700240
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700241 double MaxPower = 0;
Todd Poynor752faf22013-06-12 13:25:59 -0700242
ShevT9d98a6a2018-07-26 11:47:47 +0300243 for (size_t i = 0; i < mChargerNames.size(); i++) {
Todd Poynor752faf22013-06-12 13:25:59 -0700244 String8 path;
245 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
246 mChargerNames[i].string());
Michael Scott3217c5c2016-06-05 11:20:13 -0700247 if (getIntField(path)) {
248 path.clear();
249 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
250 mChargerNames[i].string());
251 switch(readPowerSupplyType(path)) {
252 case ANDROID_POWER_SUPPLY_TYPE_AC:
253 props.chargerAcOnline = true;
254 break;
255 case ANDROID_POWER_SUPPLY_TYPE_USB:
256 props.chargerUsbOnline = true;
257 break;
258 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
259 props.chargerWirelessOnline = true;
260 break;
261 default:
262 KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
263 mChargerNames[i].string());
264 }
265 path.clear();
266 path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
267 mChargerNames[i].string());
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700268 int ChargingCurrent =
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700269 (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
270
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700271 path.clear();
272 path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
273 mChargerNames[i].string());
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700274
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700275 int ChargingVoltage =
276 (access(path.string(), R_OK) == 0) ? getIntField(path) :
277 DEFAULT_VBUS_VOLTAGE;
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700278
Dmitry Shmidt9f6b80c2016-06-20 12:58:37 -0700279 double power = ((double)ChargingCurrent / MILLION) *
280 ((double)ChargingVoltage / MILLION);
281 if (MaxPower < power) {
282 props.maxChargingCurrent = ChargingCurrent;
283 props.maxChargingVoltage = ChargingVoltage;
284 MaxPower = power;
Todd Poynor752faf22013-06-12 13:25:59 -0700285 }
286 }
287 }
Yifan Hong1353e702019-10-07 10:41:30 -0700288}
Todd Poynor752faf22013-06-12 13:25:59 -0700289
Yifan Hong1353e702019-10-07 10:41:30 -0700290void BatteryMonitor::logValues(void) {
291 char dmesgline[256];
292 size_t len;
Yifan Hong1d4368b2019-10-07 11:18:04 -0700293 const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
Yifan Hong1353e702019-10-07 10:41:30 -0700294 if (props.batteryPresent) {
295 snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
296 props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "",
297 abs(props.batteryTemperature / 10), abs(props.batteryTemperature % 10),
298 props.batteryHealth, props.batteryStatus);
Todd Poynorb45f1f52013-07-30 18:57:16 -0700299
Yifan Hong1353e702019-10-07 10:41:30 -0700300 len = strlen(dmesgline);
301 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
302 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
303 props.batteryCurrent);
Todd Poynor10b235e2013-08-07 15:25:14 -0700304 }
305
Yifan Hong1353e702019-10-07 10:41:30 -0700306 if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
307 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
308 props.batteryFullCharge);
309 }
Mark Salyzynacb1ddf2015-07-23 09:22:50 -0700310
Yifan Hong1353e702019-10-07 10:41:30 -0700311 if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
312 len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
313 props.batteryCycleCount);
314 }
315 } else {
316 len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
Todd Poynorb45f1f52013-07-30 18:57:16 -0700317 }
318
Yifan Hong1353e702019-10-07 10:41:30 -0700319 snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
320 props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
321 props.chargerWirelessOnline ? "w" : "");
322
323 KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
324}
325
326bool BatteryMonitor::isChargerOnline() {
Yifan Hong1d4368b2019-10-07 11:18:04 -0700327 const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
Todd Poynor752faf22013-06-12 13:25:59 -0700328 return props.chargerAcOnline | props.chargerUsbOnline |
329 props.chargerWirelessOnline;
330}
331
Yabin Cuiaedf6032016-02-19 18:03:23 -0800332int BatteryMonitor::getChargeStatus() {
Yifan Hong1d4368b2019-10-07 11:18:04 -0700333 BatteryStatus result = BatteryStatus::UNKNOWN;
Yabin Cuiaedf6032016-02-19 18:03:23 -0800334 if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
Michael Scott3217c5c2016-06-05 11:20:13 -0700335 std::string buf;
336 if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
337 result = getBatteryStatus(buf.c_str());
Yabin Cuiaedf6032016-02-19 18:03:23 -0800338 }
Yifan Hong1d4368b2019-10-07 11:18:04 -0700339 return static_cast<int>(result);
Yabin Cuiaedf6032016-02-19 18:03:23 -0800340}
341
Todd Poynorc133b712013-08-14 17:39:13 -0700342status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
343 status_t ret = BAD_VALUE;
Jin Qian72adf112017-02-02 17:31:13 -0800344 std::string buf;
Todd Poynorc133b712013-08-14 17:39:13 -0700345
Todd Poynor8f132af2014-05-08 17:15:45 -0700346 val->valueInt64 = LONG_MIN;
347
Todd Poynorc133b712013-08-14 17:39:13 -0700348 switch(id) {
349 case BATTERY_PROP_CHARGE_COUNTER:
350 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700351 val->valueInt64 =
Todd Poynorc133b712013-08-14 17:39:13 -0700352 getIntField(mHealthdConfig->batteryChargeCounterPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700353 ret = OK;
Todd Poynorc133b712013-08-14 17:39:13 -0700354 } else {
355 ret = NAME_NOT_FOUND;
356 }
357 break;
358
359 case BATTERY_PROP_CURRENT_NOW:
360 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700361 val->valueInt64 =
Todd Poynorc133b712013-08-14 17:39:13 -0700362 getIntField(mHealthdConfig->batteryCurrentNowPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700363 ret = OK;
Todd Poynorc133b712013-08-14 17:39:13 -0700364 } else {
365 ret = NAME_NOT_FOUND;
366 }
367 break;
368
Todd Poynorbc102112013-08-27 18:11:49 -0700369 case BATTERY_PROP_CURRENT_AVG:
370 if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700371 val->valueInt64 =
Todd Poynorbc102112013-08-27 18:11:49 -0700372 getIntField(mHealthdConfig->batteryCurrentAvgPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700373 ret = OK;
Todd Poynorbc102112013-08-27 18:11:49 -0700374 } else {
375 ret = NAME_NOT_FOUND;
376 }
377 break;
378
Paul Lawrence347c8de2014-03-19 15:04:40 -0700379 case BATTERY_PROP_CAPACITY:
380 if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
Todd Poynor8f132af2014-05-08 17:15:45 -0700381 val->valueInt64 =
Paul Lawrence347c8de2014-03-19 15:04:40 -0700382 getIntField(mHealthdConfig->batteryCapacityPath);
Elliott Hughes643268f2018-10-08 11:10:11 -0700383 ret = OK;
Paul Lawrence347c8de2014-03-19 15:04:40 -0700384 } else {
385 ret = NAME_NOT_FOUND;
386 }
387 break;
388
Todd Poynor8f132af2014-05-08 17:15:45 -0700389 case BATTERY_PROP_ENERGY_COUNTER:
Todd Poynore14b37e2014-05-20 13:54:40 -0700390 if (mHealthdConfig->energyCounter) {
391 ret = mHealthdConfig->energyCounter(&val->valueInt64);
392 } else {
393 ret = NAME_NOT_FOUND;
394 }
Todd Poynor8f132af2014-05-08 17:15:45 -0700395 break;
396
Jin Qian72adf112017-02-02 17:31:13 -0800397 case BATTERY_PROP_BATTERY_STATUS:
Todd Poynore030a102018-01-19 14:03:59 -0800398 val->valueInt64 = getChargeStatus();
Elliott Hughes643268f2018-10-08 11:10:11 -0700399 ret = OK;
Jin Qian72adf112017-02-02 17:31:13 -0800400 break;
401
Todd Poynorc133b712013-08-14 17:39:13 -0700402 default:
403 break;
404 }
405
Todd Poynorc133b712013-08-14 17:39:13 -0700406 return ret;
407}
408
Todd Poynor020369d2013-09-18 20:09:33 -0700409void BatteryMonitor::dumpState(int fd) {
410 int v;
411 char vs[128];
Yifan Hong1d4368b2019-10-07 11:18:04 -0700412 const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
Todd Poynor020369d2013-09-18 20:09:33 -0700413
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700414 snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d voltage_max: %d\n",
Todd Poynor020369d2013-09-18 20:09:33 -0700415 props.chargerAcOnline, props.chargerUsbOnline,
Badhri Jagan Sridharan40e1df42015-10-27 10:43:53 -0700416 props.chargerWirelessOnline, props.maxChargingCurrent,
417 props.maxChargingVoltage);
Todd Poynor020369d2013-09-18 20:09:33 -0700418 write(fd, vs, strlen(vs));
419 snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
420 props.batteryStatus, props.batteryHealth, props.batteryPresent);
421 write(fd, vs, strlen(vs));
422 snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n",
423 props.batteryLevel, props.batteryVoltage,
424 props.batteryTemperature);
425 write(fd, vs, strlen(vs));
426
427 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
428 v = getIntField(mHealthdConfig->batteryCurrentNowPath);
429 snprintf(vs, sizeof(vs), "current now: %d\n", v);
430 write(fd, vs, strlen(vs));
431 }
432
433 if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
434 v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
435 snprintf(vs, sizeof(vs), "current avg: %d\n", v);
436 write(fd, vs, strlen(vs));
437 }
438
439 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
440 v = getIntField(mHealthdConfig->batteryChargeCounterPath);
441 snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
442 write(fd, vs, strlen(vs));
443 }
Ruchi Kandoicc338802015-08-24 13:01:16 -0700444
445 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
446 snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrent);
447 write(fd, vs, strlen(vs));
448 }
449
450 if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
451 snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
452 write(fd, vs, strlen(vs));
453 }
454
455 if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
456 snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullCharge);
457 write(fd, vs, strlen(vs));
458 }
Todd Poynor020369d2013-09-18 20:09:33 -0700459}
460
Todd Poynorc7464c92013-09-10 12:40:00 -0700461void BatteryMonitor::init(struct healthd_config *hc) {
Todd Poynor752faf22013-06-12 13:25:59 -0700462 String8 path;
Todd Poynor3db03a52014-05-21 16:28:13 -0700463 char pval[PROPERTY_VALUE_MAX];
Todd Poynor752faf22013-06-12 13:25:59 -0700464
Todd Poynorf5d30122013-08-12 17:03:35 -0700465 mHealthdConfig = hc;
James Hawkins588a2ca2016-02-18 14:52:46 -0800466 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
Todd Poynor752faf22013-06-12 13:25:59 -0700467 if (dir == NULL) {
468 KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
469 } else {
470 struct dirent* entry;
471
James Hawkins588a2ca2016-02-18 14:52:46 -0800472 while ((entry = readdir(dir.get()))) {
Todd Poynor752faf22013-06-12 13:25:59 -0700473 const char* name = entry->d_name;
Thierry Strudelf73de6f2019-01-11 17:09:20 -0800474 std::vector<String8>::iterator itIgnoreName;
Todd Poynor752faf22013-06-12 13:25:59 -0700475
476 if (!strcmp(name, ".") || !strcmp(name, ".."))
477 continue;
478
Thierry Strudelf73de6f2019-01-11 17:09:20 -0800479 itIgnoreName = find(hc->ignorePowerSupplyNames.begin(),
480 hc->ignorePowerSupplyNames.end(), String8(name));
481 if (itIgnoreName != hc->ignorePowerSupplyNames.end())
482 continue;
483
Todd Poynor752faf22013-06-12 13:25:59 -0700484 // Look for "type" file in each subdirectory
485 path.clear();
486 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
487 switch(readPowerSupplyType(path)) {
488 case ANDROID_POWER_SUPPLY_TYPE_AC:
489 case ANDROID_POWER_SUPPLY_TYPE_USB:
490 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
491 path.clear();
492 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
493 if (access(path.string(), R_OK) == 0)
494 mChargerNames.add(String8(name));
495 break;
496
497 case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
Todd Poynor6dcc45e2013-10-21 20:26:25 -0700498 mBatteryDevicePresent = true;
499
Todd Poynorf5d30122013-08-12 17:03:35 -0700500 if (mHealthdConfig->batteryStatusPath.isEmpty()) {
Todd Poynor752faf22013-06-12 13:25:59 -0700501 path.clear();
Todd Poynorf5d30122013-08-12 17:03:35 -0700502 path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
503 name);
Todd Poynor752faf22013-06-12 13:25:59 -0700504 if (access(path, R_OK) == 0)
Todd Poynorf5d30122013-08-12 17:03:35 -0700505 mHealthdConfig->batteryStatusPath = path;
Todd Poynor752faf22013-06-12 13:25:59 -0700506 }
507
Todd Poynorf5d30122013-08-12 17:03:35 -0700508 if (mHealthdConfig->batteryHealthPath.isEmpty()) {
Todd Poynor752faf22013-06-12 13:25:59 -0700509 path.clear();
Todd Poynorf5d30122013-08-12 17:03:35 -0700510 path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
511 name);
Todd Poynor752faf22013-06-12 13:25:59 -0700512 if (access(path, R_OK) == 0)
Todd Poynorf5d30122013-08-12 17:03:35 -0700513 mHealthdConfig->batteryHealthPath = path;
Todd Poynor752faf22013-06-12 13:25:59 -0700514 }
515
Todd Poynorf5d30122013-08-12 17:03:35 -0700516 if (mHealthdConfig->batteryPresentPath.isEmpty()) {
517 path.clear();
518 path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
519 name);
520 if (access(path, R_OK) == 0)
521 mHealthdConfig->batteryPresentPath = path;
522 }
523
524 if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
525 path.clear();
526 path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
527 name);
528 if (access(path, R_OK) == 0)
529 mHealthdConfig->batteryCapacityPath = path;
530 }
531
532 if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
533 path.clear();
534 path.appendFormat("%s/%s/voltage_now",
535 POWER_SUPPLY_SYSFS_PATH, name);
536 if (access(path, R_OK) == 0) {
537 mHealthdConfig->batteryVoltagePath = path;
Todd Poynorf5d30122013-08-12 17:03:35 -0700538 }
539 }
540
Ruchi Kandoicc338802015-08-24 13:01:16 -0700541 if (mHealthdConfig->batteryFullChargePath.isEmpty()) {
542 path.clear();
543 path.appendFormat("%s/%s/charge_full",
544 POWER_SUPPLY_SYSFS_PATH, name);
545 if (access(path, R_OK) == 0)
546 mHealthdConfig->batteryFullChargePath = path;
547 }
548
Todd Poynorf5d30122013-08-12 17:03:35 -0700549 if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
550 path.clear();
551 path.appendFormat("%s/%s/current_now",
552 POWER_SUPPLY_SYSFS_PATH, name);
553 if (access(path, R_OK) == 0)
554 mHealthdConfig->batteryCurrentNowPath = path;
555 }
556
Ruchi Kandoicc338802015-08-24 13:01:16 -0700557 if (mHealthdConfig->batteryCycleCountPath.isEmpty()) {
558 path.clear();
559 path.appendFormat("%s/%s/cycle_count",
560 POWER_SUPPLY_SYSFS_PATH, name);
561 if (access(path, R_OK) == 0)
562 mHealthdConfig->batteryCycleCountPath = path;
563 }
564
Todd Poynorbc102112013-08-27 18:11:49 -0700565 if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
566 path.clear();
567 path.appendFormat("%s/%s/current_avg",
568 POWER_SUPPLY_SYSFS_PATH, name);
569 if (access(path, R_OK) == 0)
570 mHealthdConfig->batteryCurrentAvgPath = path;
571 }
572
Todd Poynorf5d30122013-08-12 17:03:35 -0700573 if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
574 path.clear();
575 path.appendFormat("%s/%s/charge_counter",
576 POWER_SUPPLY_SYSFS_PATH, name);
577 if (access(path, R_OK) == 0)
578 mHealthdConfig->batteryChargeCounterPath = path;
579 }
580
581 if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
582 path.clear();
583 path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
584 name);
585 if (access(path, R_OK) == 0) {
586 mHealthdConfig->batteryTemperaturePath = path;
Todd Poynorf5d30122013-08-12 17:03:35 -0700587 }
588 }
589
590 if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
591 path.clear();
592 path.appendFormat("%s/%s/technology",
593 POWER_SUPPLY_SYSFS_PATH, name);
594 if (access(path, R_OK) == 0)
595 mHealthdConfig->batteryTechnologyPath = path;
596 }
597
Todd Poynor752faf22013-06-12 13:25:59 -0700598 break;
599
600 case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
601 break;
602 }
603 }
Todd Poynor752faf22013-06-12 13:25:59 -0700604 }
605
Ian Pedowitz585ab652015-10-12 19:01:00 -0700606 // Typically the case for devices which do not have a battery and
607 // and are always plugged into AC mains.
Todd Poynor6dcc45e2013-10-21 20:26:25 -0700608 if (!mBatteryDevicePresent) {
Todd Poynorebeb0c02014-09-23 14:54:24 -0700609 KLOG_WARNING(LOG_TAG, "No battery devices found\n");
Todd Poynor6dcc45e2013-10-21 20:26:25 -0700610 hc->periodic_chores_interval_fast = -1;
611 hc->periodic_chores_interval_slow = -1;
612 } else {
613 if (mHealthdConfig->batteryStatusPath.isEmpty())
614 KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
615 if (mHealthdConfig->batteryHealthPath.isEmpty())
616 KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
617 if (mHealthdConfig->batteryPresentPath.isEmpty())
618 KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
619 if (mHealthdConfig->batteryCapacityPath.isEmpty())
620 KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
621 if (mHealthdConfig->batteryVoltagePath.isEmpty())
622 KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
623 if (mHealthdConfig->batteryTemperaturePath.isEmpty())
624 KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
625 if (mHealthdConfig->batteryTechnologyPath.isEmpty())
626 KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
Ruchi Kandoif18ec9f2015-09-28 13:35:59 -0700627 if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
Ruchi Kandoicc338802015-08-24 13:01:16 -0700628 KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
629 if (mHealthdConfig->batteryFullChargePath.isEmpty())
630 KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
631 if (mHealthdConfig->batteryCycleCountPath.isEmpty())
632 KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
Todd Poynor6dcc45e2013-10-21 20:26:25 -0700633 }
Todd Poynor3db03a52014-05-21 16:28:13 -0700634
Ruchi Kandoia78fc232014-07-10 15:06:21 -0700635 if (property_get("ro.boot.fake_battery", pval, NULL) > 0
636 && strtol(pval, NULL, 10) != 0) {
637 mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
638 mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
639 }
Todd Poynor752faf22013-06-12 13:25:59 -0700640}
641
642}; // namespace android