healthd log 解读
文章目录
- healthd log
- log打印来源
- log数据来源
- power_supply实现
- 参考
healthd log
android kernel log中会打印出如下healthd log,这些log是什么意思?来自哪里?这篇文章为你解读。
<12>[ 191.726280] .(4)[418:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.0-serv]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:health@2.1-serv]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:health@2.1-serv]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:health@2.1-serv]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:health@2.1-serv]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:health@2.1-serv]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:health@2.1-serv]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 数据就是每个产商实现方法而来的。
参考
- 《Android Healthd电池服务分析》https://blog.csdn.net/u012830148/article/details/80226498
- 《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
healthd log 解读相关推荐
- Oracle-Listener log解读
Listener log 概述 在ORACLE数据库中,如果不对监听日志文件(listener.log)进行截断,那么监听日志文件(listener.log)会变得越来越大. Listener log ...
- gc android,Android GC Log解读
写在前面 英文原版链接,若是觉得本文哪里不好还请指出,以便及时修改,以下是译文 安卓是为移动设备设计的,所以开发者应该时刻留意app占用的RAM(Random-Access Memory).尽管Dal ...
- Oracle-Alert log解读
Alert log概述 告警日志文件是一类特殊的跟踪文件(trace file). 告警日志文件命名一般为alert_<SID>.log,其中SID为ORACLE数据库实例名称. 数据库告 ...
- SeLinux 的avc log解读
avc log分析: SeLinux的AVC log的详细分析 eg: type=AVC msg=audit(1395177286.929:1638): avc: denied { read } fo ...
- 解读Android LOG机制的实现:(1)LOG的实现架构
解读Android LOG机制的实现:(1)LOG的实现架构 田海立@CSDN 2011/07/24 Android提供了用户级轻量的LOG机制,它的实现贯穿了Java,JNI,本地c/c++实现以及 ...
- 垃圾回收器机制(三):正确姿势解读GC日志
年轻代log解读 年轻代以ParNew收集器为例, 采用的是复制算法, log如下: 2019-02-01T21:18:15:00.382+0800: 718675.758: Application ...
- monkey 测试 ANR 问题 整理分析
1.ANR简介 ANR是Application Not Responding的简称,即应用无响应. anr trace log 一般在 /data/anr 目录. 2.ANR 分类 1. ...
- day55 linux 基础以及系统优化
Linux系统基础优化及常用命令 Linux基础系统优化 引言没有,只有一张图. Linux的网络功能相当强悍,一时之间我们无法了解所有的网络命令,在配置服务器基础环境时,先了解下网络参数设定命令 ...
- 高通SDX55平台:adb功能异常
展锐UDX710:LAN7800 PHY驱动调试 1. 问题描述 2. 问题分析 2.1 测试环境 2.2 初步分析 2.3 USB驱动初始化 2.3.1 USB驱动加载流程 2.3.1.1 USB_ ...
- linux基础—40个不得不学的linux基础命令,建议收藏
Linux终端提示符 [root@oldboy_python ~]# [root@oldboy_python ~]# [root@oldboy_python ~]# [root@oldboy_pyth ...
最新文章
- Java 调用存储过程 返回结果集
- 【免费分享】KotaLog Diary2022年计划电子手账本
- 数据库-优化-groupby的优化
- windows 2008 远程桌面如何设置允许多用户登录?
- 防止表单按钮多次提交
- pycharm+python3.7+pyqt配置_Python3+Pycharm+PyQt5环境搭建步骤图文详解
- SAP License:FI常用表
- JavaScript学习(八十)—请写一段JS程序提取URL中的各个get参数(参数名和参数个数不确定),将其按key-value形式返回到一个json结构中
- 用python写一个hello world程序
- Ansible详解(十二)——Ansible Roles详解
- iOS build 编译错误 Failed to emit precompiled header for bridging header
- Psping四大功能介绍:ICMP Ping/TCP Ping/延迟测试/带宽测试
- 前端开发人员MAC装机工具
- VRRP在城域网中的应用
- 布同:如何循序渐进学习Python语言
- 瑞吉外卖项目:移动端导入用户地址簿与菜品展示功能实现
- 第五届“强网”拟态防御国际精英挑战赛——特邀战队篇
- AIGC/ChatGPT这么火,相关的AI产品岗,真的有变多吗?_最新AI产品经理求职动态(28)...
- 聚类 轮廓 matlab,通过聚类点matlab着色的等高线图
- 骚年 你还太弱,请专心练剑
热门文章
- 个人用 Qt + ffmpeg + D3D9/D3D11 开发的播放器
- 队列练习之Example004-设计一个循环队列,用 front 和 rear 分别作为队头和队尾指针,另外用一个标志 tag 表示队列是空还是不空
- 浅谈数字后端工程师的工作
- 导入和导出requirement
- pip 生成 requirement.txt 文件
- Conflicting order. Following module has been added:
- 全力配合金融改革,尝试期货投资基金
- 关于阿里矢量图标的普通无色和彩色的使用方法
- 单独使用bable插件
- 【哈工大SCIR】多模态情感分析简述