healthd log 解讀

healthd log

android kernel log中會打印出如下healthd log,這些log是什麼意思?來自哪裏?這篇文章爲你解讀。

<12>[  191.726280] .(4)[418:[email protected]]healthd: battery l=4 v=3575 t=30.0 h=2 st=3 c=-248 fc=2946000 cc=1 chg=
<12>[  191.753749] .(5)[418:[email protected]]healthd: battery l=4 v=3567 t=30.0 h=2 st=3 c=-258 fc=2946000 cc=1 chg=
<12>[  195.114317] .(5)[418:[email protected]]healthd: battery l=4 v=3667 t=30.0 h=2 st=2 c=446 fc=2946000 cc=1 chg=a
<12>[  195.122295] .(7)[418:[email protected]]healthd: battery l=4 v=3667 t=30.0 h=2 st=2 c=406 fc=2946000 cc=1 chg=a
<12>[  195.149265] .(4)[418:[email protected]]healthd: battery l=4 v=3667 t=30.0 h=2 st=2 c=407 fc=2946000 cc=1 chg=a
<12>[  195.151107] .(4)[418:[email protected]]healthd: battery l=4 v=3652 t=30.0 h=2 st=2 c=304 fc=2946000 cc=1 chg=a
<12>[  195.162849] .(4)[418:[email protected]]healthd: battery l=4 v=3647 t=30.0 h=2 st=2 c=299 fc=2946000 cc=1 chg=a
<12>[  200.414571] .(7)[418:[email protected]]healthd: battery l=4 v=3572 t=30.0 h=2 st=3 c=-258 fc=2946000 cc=1 chg=
<12>[  200.417265] .(7)[418:[email protected]]healthd: battery l=4 v=3572 t=30.0 h=2 st=3 c=-253 fc=2946000 cc=1 chg=
<12>[  200.420810] .(7)[418:[email protected]]healthd: battery l=4 v=3572 t=30.0 h=2 st=3 c=-274 fc=2946000 cc=1 chg=
<12>[  203.755133] .(6)[418:[email protected]]healthd: battery l=4 v=3806 t=30.0 h=2 st=3 c=1365 fc=2946000 cc=1 chg=
<12>[  203.994594] .(6)[418:[email protected]]healthd: battery l=4 v=3606 t=30.0 h=2 st=2 c=-29 fc=2946000 cc=1 chg=a
<12>[  203.997249] .(5)[418:[email protected]]healthd: battery l=4 v=3606 t=30.0 h=2 st=2 c=-32 fc=2946000 cc=1 chg=a
<12>[  203.999349] .(5)[418:[email protected]]healthd: battery l=4 v=3606 t=30.0 h=2 st=2 c=-28 fc=2946000 cc=1 chg=a

[ 6883.388565] (1)[486:[email protected]]healthd: battery l=25 v=3830 t=30.5 h=2 st=2 c=453400 fc=2946000 cc=0 chg=u
[ 6899.524245] (2)[486:[email protected]]healthd: battery l=25 v=3830 t=30.6 h=2 st=2 c=473600 fc=2946000 cc=0 chg=u
[ 6937.475240] (5)[486:[email protected]]healthd: battery l=25 v=3826 t=30.7 h=2 st=2 c=407700 fc=2946000 cc=0 chg=u
[ 6959.521355] (1)[486:[email protected]]healthd: battery l=25 v=3826 t=30.7 h=2 st=2 c=406400 fc=2946000 cc=0 chg=u
[ 7002.385107] (0)[486:[email protected]]healthd: battery l=26 v=3827 t=30.8 h=2 st=2 c=370400 fc=2946000 cc=0 chg=u
[ 7019.522528] (1)[486:[email protected]]healthd: battery l=26 v=3827 t=30.9 h=2 st=2 c=469300 fc=2946000 cc=0 chg=u

通過代碼跟蹤可以大概知道log含義:

  • l: 電量百分比
  • v: 電池電壓
  • t: 電池溫度
  • h: 電池健康狀態(如下)

/frameworks/native/services/batteryservice/include/batteryservice/BatteryServiceConstants.h

18  enum {
19      BATTERY_HEALTH_UNKNOWN = 1,
20      BATTERY_HEALTH_GOOD = 2,
21      BATTERY_HEALTH_OVERHEAT = 3,
22      BATTERY_HEALTH_DEAD = 4,
23      BATTERY_HEALTH_OVER_VOLTAGE = 5,
24      BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6,
25      BATTERY_HEALTH_COLD = 7,
26  };
  • c=%d", props.batteryCurrent);
  • fc=%d", props.batteryFullCharge);
  • cc=%d", props.batteryCycleCount);
  • chg: 當前使用充電器:
    • props.chargerAcOnline ? “a” : “”,
    • props.chargerUsbOnline ? “u” : “”,
    • props.chargerWirelessOnline ? “w” : “”

log打印來源

kernel log中的healthd log是從android 代碼 /system/core/healthd/BatteryMonitor.cpp 打印出來的:


201  bool BatteryMonitor::update(void) {
...
214      props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
215  
216      if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
217          props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath) / 1000;
218  
219      if (!mHealthdConfig->batteryFullChargePath.isEmpty())
220          props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath);
221  
222      if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
223          props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
224  
225      if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
226          props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
227  
...
234      if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
235          props.batteryStatus = getBatteryStatus(buf.c_str());
236  
237      if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
238          props.batteryHealth = getBatteryHealth(buf.c_str());
...
294      if (logthis) {
295          char dmesgline[256];
296          size_t len;
297          if (props.batteryPresent) {
298              snprintf(dmesgline, sizeof(dmesgline),
299                   "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
300                   props.batteryLevel, props.batteryVoltage,
301                   props.batteryTemperature < 0 ? "-" : "",
302                   abs(props.batteryTemperature / 10),
303                   abs(props.batteryTemperature % 10), props.batteryHealth,
304                   props.batteryStatus);
305  
306              len = strlen(dmesgline);
307              if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
308                  len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
309                                  " c=%d", props.batteryCurrent);
310              }
311  
312              if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
313                  len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
314                                  " fc=%d", props.batteryFullCharge);
315              }
316  
317              if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
318                  len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
319                                  " cc=%d", props.batteryCycleCount);
320              }
321          } else {
322              len = snprintf(dmesgline, sizeof(dmesgline),
323                   "battery none");
324          }
325  
326          snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
327                   props.chargerAcOnline ? "a" : "",
328                   props.chargerUsbOnline ? "u" : "",
329                   props.chargerWirelessOnline ? "w" : "");
330  
331          KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
332      }

log數據來源

android 上層打印的log是通過讀power_supply 相關的節點數據:

# ls sys/class/power_supply/
ac  battery  charger  usb
 # ls sys/class/power_supply/battery/
capacity  charge_counter  charge_full  current_avg  current_now  cycle_count  device  health  power  present  status  subsystem  technology  temp  type  uevent  voltage_now  wakeup13

power_supply實現

文件節點:
/kernel-4.9/drivers/power/supply/power_supply_sysfs.c

43  static ssize_t power_supply_show_property(struct device *dev,
44  					  struct device_attribute *attr,
45  					  char *buf) {
46  	static char *type_text[] = {
47  		"Unknown", "Battery", "UPS", "Mains", "USB",
48  		"USB_DCP", "USB_CDP", "USB_ACA", "Wireless", "USB_C",
49  		"USB_PD", "USB_PD_DRP"
50  	};
51  	static char *status_text[] = {
52  		"Unknown", "Charging", "Discharging", "Not charging", "Full",
53  		"Cmd discharging"
54  	};
55  	static char *charge_type[] = {
56  		"Unknown", "N/A", "Trickle", "Fast"
57  	};
58  	static char *health_text[] = {
59  		"Unknown", "Good", "Overheat", "Dead", "Over voltage",
60  		"Unspecified failure", "Cold", "Watchdog timer expire",
61  		"Safety timer expire"
62  	};
63  	static char *technology_text[] = {
64  		"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
65  		"LiMn"
66  	};
67  	static char *capacity_level_text[] = {
68  		"Unknown", "Critical", "Low", "Normal", "High", "Full"
69  	};
70  	static char *scope_text[] = {
71  		"Unknown", "System", "Device"
72  	};
73  	ssize_t ret = 0;
74  	struct power_supply *psy = dev_get_drvdata(dev);
75  	const ptrdiff_t off = attr - power_supply_attrs;
76  	union power_supply_propval value;
77  
78  	if (off == POWER_SUPPLY_PROP_TYPE) {
79  		value.intval = psy->desc->type;
80  	} else {
81  		ret = power_supply_get_property(psy, off, &value);
82  
83  		if (ret < 0) {
84  			if (ret == -ENODATA)
85  				dev_dbg(dev, "driver has no data for `%s' property\n",
86  					attr->attr.name);
87  			else if (ret != -ENODEV && ret != -EAGAIN)
88  				dev_err(dev, "driver failed to report `%s' property: %zd\n",
89  					attr->attr.name, ret);
90  			return ret;
91  		}
92  	}
93  
94  	if (off == POWER_SUPPLY_PROP_STATUS)
95  		return sprintf(buf, "%s\n", status_text[value.intval]);
96  	else if (off == POWER_SUPPLY_PROP_CHARGE_TYPE)
97  		return sprintf(buf, "%s\n", charge_type[value.intval]);
98  	else if (off == POWER_SUPPLY_PROP_HEALTH)
99  		return sprintf(buf, "%s\n", health_text[value.intval]);
100  	else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
101  		return sprintf(buf, "%s\n", technology_text[value.intval]);
102  	else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
103  		return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
104  	else if (off == POWER_SUPPLY_PROP_TYPE)
105  		return sprintf(buf, "%s\n", type_text[value.intval]);
106  	else if (off == POWER_SUPPLY_PROP_SCOPE)
107  		return sprintf(buf, "%s\n", scope_text[value.intval]);
108  	else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
109  		return sprintf(buf, "%s\n", value.strval);
110  
111  	if (off == POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT)
112  		return sprintf(buf, "%lld\n", value.int64val);
113  	else
114  		return sprintf(buf, "%d\n", value.intval);
115  }

註冊power_supply:
/kernel-4.9/drivers/power/supply/power_supply_core.c

833  struct power_supply *__must_check power_supply_register(struct device *parent,
834  		const struct power_supply_desc *desc,
835  		const struct power_supply_config *cfg)
836  {
837  	return __power_supply_register(parent, desc, cfg, true);
838  }
839  EXPORT_SYMBOL_GPL(power_supply_register);

每個平臺的芯片產的實現方法不一樣,如下的文件節點可知有ac battery charger usb 幾個地方調用power_supply_register 註冊這個power_supply。

# ls sys/class/power_supply/
ac  battery  charger  usb

而android 上層在kernel 打印的healthd 數據就是每個產商實現方法而來的。

參考

  1. Android Healthd電池服務分析》https://blog.csdn.net/u012830148/article/details/80226498
  2. Linux power supply class(1)_軟件架構及API彙整–wowo》http://www.wowotech.net/pm_subsystem/psy_class_overview.html ,https://wu-being.blog.csdn.net/article/details/106047670
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章