文章目录

  • 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 数据就是每个产商实现方法而来的。

参考

  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

healthd log 解读相关推荐

  1. Oracle-Listener log解读

    Listener log 概述 在ORACLE数据库中,如果不对监听日志文件(listener.log)进行截断,那么监听日志文件(listener.log)会变得越来越大. Listener log ...

  2. gc android,Android GC Log解读

    写在前面 英文原版链接,若是觉得本文哪里不好还请指出,以便及时修改,以下是译文 安卓是为移动设备设计的,所以开发者应该时刻留意app占用的RAM(Random-Access Memory).尽管Dal ...

  3. Oracle-Alert log解读

    Alert log概述 告警日志文件是一类特殊的跟踪文件(trace file). 告警日志文件命名一般为alert_<SID>.log,其中SID为ORACLE数据库实例名称. 数据库告 ...

  4. SeLinux 的avc log解读

    avc log分析: SeLinux的AVC log的详细分析 eg: type=AVC msg=audit(1395177286.929:1638): avc: denied { read } fo ...

  5. 解读Android LOG机制的实现:(1)LOG的实现架构

    解读Android LOG机制的实现:(1)LOG的实现架构 田海立@CSDN 2011/07/24 Android提供了用户级轻量的LOG机制,它的实现贯穿了Java,JNI,本地c/c++实现以及 ...

  6. 垃圾回收器机制(三):正确姿势解读GC日志

    年轻代log解读 年轻代以ParNew收集器为例, 采用的是复制算法, log如下: 2019-02-01T21:18:15:00.382+0800: 718675.758: Application ...

  7. monkey 测试 ANR 问题 整理分析

    ​​​​​ 1.ANR简介 ANR是Application Not Responding的简称,即应用无响应. anr trace log 一般在 /data/anr 目录. 2.ANR 分类 1. ...

  8. day55 linux 基础以及系统优化

    Linux系统基础优化及常用命令   Linux基础系统优化 引言没有,只有一张图. Linux的网络功能相当强悍,一时之间我们无法了解所有的网络命令,在配置服务器基础环境时,先了解下网络参数设定命令 ...

  9. 高通SDX55平台:adb功能异常

    展锐UDX710:LAN7800 PHY驱动调试 1. 问题描述 2. 问题分析 2.1 测试环境 2.2 初步分析 2.3 USB驱动初始化 2.3.1 USB驱动加载流程 2.3.1.1 USB_ ...

  10. linux基础—40个不得不学的linux基础命令,建议收藏

    Linux终端提示符 [root@oldboy_python ~]# [root@oldboy_python ~]# [root@oldboy_python ~]# [root@oldboy_pyth ...

最新文章

  1. Java 调用存储过程 返回结果集
  2. 【免费分享】KotaLog Diary2022年计划电子手账本
  3. 数据库-优化-groupby的优化
  4. windows 2008 远程桌面如何设置允许多用户登录?
  5. 防止表单按钮多次提交
  6. pycharm+python3.7+pyqt配置_Python3+Pycharm+PyQt5环境搭建步骤图文详解
  7. SAP License:FI常用表
  8. JavaScript学习(八十)—请写一段JS程序提取URL中的各个get参数(参数名和参数个数不确定),将其按key-value形式返回到一个json结构中
  9. 用python写一个hello world程序
  10. Ansible详解(十二)——Ansible Roles详解
  11. iOS build 编译错误 Failed to emit precompiled header for bridging header
  12. Psping四大功能介绍:ICMP Ping/TCP Ping/延迟测试/带宽测试
  13. 前端开发人员MAC装机工具
  14. VRRP在城域网中的应用
  15. 布同:如何循序渐进学习Python语言
  16. 瑞吉外卖项目:移动端导入用户地址簿与菜品展示功能实现
  17. 第五届“强网”拟态防御国际精英挑战赛——特邀战队篇
  18. AIGC/ChatGPT这么火,相关的AI产品岗,真的有变多吗?_最新AI产品经理求职动态(28)...
  19. 聚类 轮廓 matlab,通过聚类点matlab着色的等高线图
  20. 骚年 你还太弱,请专心练剑

热门文章

  1. 个人用 Qt + ffmpeg + D3D9/D3D11 开发的播放器
  2. 队列练习之Example004-设计一个循环队列,用 front 和 rear 分别作为队头和队尾指针,另外用一个标志 tag 表示队列是空还是不空
  3. 浅谈数字后端工程师的工作
  4. 导入和导出requirement
  5. pip 生成 requirement.txt 文件
  6. Conflicting order. Following module has been added:
  7. 全力配合金融改革,尝试期货投资基金
  8. 关于阿里矢量图标的普通无色和彩色的使用方法
  9. 单独使用bable插件
  10. 【哈工大SCIR】多模态情感分析简述