文档章节

[日更-2019.5.19] Android 系统内的守护进程(二)--core类中的服务 : healthd

Captain_小馬佩德罗
 Captain_小馬佩德罗
发布于 06/13 11:20
字数 2061
阅读 22
收藏 0

声明

  • 其实很好奇Android系统中的一些关键守护进程服务的作用;
  • 暂且大概分析下它们的作用,这样有助于理解整个系统的工作过程;

0 写在前面的

  • 只要是操作系统,不用说的就是其中肯定会运行着一些很多守护进程(daemon)来完成很多杂乱的工作。通过系统中的init.rc文件也可以看出来,其中每个service中就包含着系统后台服务进程。
  • 而这些服务被分为:core类服务(adbd/servicemanager/healthd/lmkd/logd/vold)和main类服务;
  • main类服务又分为:网络类服务(netd/mdnsd/mtpd/rild)、图形及媒体类服务(surfaceflinger/bootanimation/mediaserver/dnnserver)、其他类服务(installd/keystore/debuggerd/sdcard/Zygote)

1 healthd

    “健康度守护进程”(health daemon)的意思是:该服务会周期性地执行检测综合性的“设备健康值” 的任务(当前只有一个与电池电量有关的任务)。该守护进程也会把自己注册为BatteryPropertiesRegistrar服务(在L版中,则是batterypropreg 或者batteryproperties)。完成了这个注册之后,healthd提供了几个框架服务(例如BatteryStatsService),用它从sysfs那里得到的数据,更新电池电量信息。

    healthd会先去完成初始化配置,然后进入执行代码的循环,如下图所示:

             

    healthd的主循环中使用epoll(2) APT对三个文件描述符进行轮询操作(读),并在每次读取到数据时,执行己注册的相关操作, 具体操作如下表所示。

描述符类型作用
wakealarm_fdTimerFD该定时器(Timer)被设为每隔periodic_chores_interval 秒就唤醒进程一次,被这个定时器唤醒时,healthd将会去执行periodic_chores 的代码
event_fdNETLink读取内核通知事件。healthd只会关心与其自身相关的power子系统(SUBSYSTEM=POWER)的事件。这些事件包括与电池电量及充电相关的通知。如果读取到了这些事件,healthd进程将会去执行battery_update()函数
binder_fd/dev/binder这种情况下,healthd将以batterypropregj服务的身份出现,让各个框架客户瑞中的Listener更新相关信息
  • 第一个要读取的文件描述符是 wakealarm_ fd: healthd用它执行周期性的日常工作。这里一共使用两种内部类型: fast (1分钟,用在使用电源充电时)和slow (10分钟,用在使用电池供电时)。当前定义的唯一一个日常工作是battery_update(),该函数会让healthd以Battery PropertiesRegistrar服务的身份,更新电池电量的当前状态。
  • 当从event_fd这个NETLink接收到来自POWER子系统的事件时,这个battery_update()函数也会被调用: healthd 并不会去解析这些事件中的具体信息,只是去刷新一下电池电量的当前状态。之所以需要此模式,是因为healthd需要能够对插上/拔下充电器之类的事件, 或是其他电视~管理警告做出响应。
  • binder_fd是供框架中的listener(首先是BattervStatsService)使用的接口。

2 利用strace追踪healthd的后台行为

    使用功能强大的strace,你可以观察到healthd在后台的行为:通过附加healthd进程的ID (需有root 权限)并调用ptrace(2) APl, strace可以在healthd调用各个系统调用的同时得到相关通知(如下图所示)。因为任何一个进程只要想做一点真正有意义的事,都必须要使用系统调用,这就向我们提供了一种能够详细地跟踪healthd行为的方法,并揭示出healthd是通过sysfs伪文件系统中的哪些伪文件来获取电池电量使用情况的。

hammerhead:/ # ps | grep "healthd"
root      188   1     20424  17368 sys_epoll_ 00059334 S /sbin/healthd
hammerhead:/ # str
strace   strings
hammerhead:/ # strace -p 188
strace: Process 188 attached
epoll_pwait(3, [{EPOLLIN, {u32=36381, u64=4776546117586292253}}], 2, -1, NULL, 8) = 1
recvmsg(7, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000001}, msg_iov(1)=[{"online@/devices/system/cpu/cpu1\0"..., 2048}], msg_controllen=24, [{cmsg_len=24, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, {pid=0, uid=0, gid=0}}], msg_flags=0}, 0) = 105
epoll_pwait(3, [{EPOLLIN, {u32=36381, u64=4776546117586292253}}], 2, -1, NULL, 8) = 1
recvmsg(7, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000001}, msg_iov(1)=[{"online@/devices/system/cpu/cpu2\0"..., 2048}], msg_controllen=24, [{cmsg_len=24, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, {pid=0, uid=0, gid=0}}], msg_flags=0}, 0) = 105
epoll_pwait(3, [{EPOLLIN, {u32=36381, u64=4776546117586292253}}], 2, -1, NULL, 8) = 1
recvmsg(7, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000001}, msg_iov(1)=[{"online@/devices/system/cpu/cpu3\0"..., 2048}], msg_controllen=24, [{cmsg_len=24, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, {pid=0, uid=0, gid=0}}], msg_flags=0}, 0) = 105
epoll_pwait(3, [{EPOLLIN, {u32=36381, u64=4776546117586292253}}], 2, -1, NULL, 8) = 1
recvmsg(7, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000001}, msg_iov(1)=[{"offline@/devices/system/cpu/cpu3"..., 2048}], msg_controllen=24, [{cmsg_len=24, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, {pid=0, uid=0, gid=0}}], msg_flags=0}, 0) = 107
epoll_pwait(3, [{EPOLLIN, {u32=36381, u64=4776546117586292253}}], 2, -1, NULL, 8) = 1
recvmsg(7, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000001}, msg_iov(1)=[{"offline@/devices/system/cpu/cpu2"..., 2048}], msg_controllen=24, [{cmsg_len=24, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, {pid=0, uid=0, gid=0}}], msg_flags=0}, 0) = 107
epoll_pwait(3, [{EPOLLIN, {u32=36381, u64=4776546117586292253}}], 2, -1, NULL, 8) = 1
recvmsg(7, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000001}, msg_iov(1)=[{"offline@/devices/system/cpu/cpu1"..., 2048}], msg_controllen=24, [{cmsg_len=24, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, {pid=0, uid=0, gid=0}}], msg_flags=0}, 0) = 107
epoll_pwait(3, [{EPOLLIN, {u32=36381, u64=4776546117586292253}}], 2, -1, NULL, 8) = 1
recvmsg(7, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000001}, msg_iov(1)=[{"online@/devices/system/cpu/cpu1\0"..., 2048}], msg_controllen=24, [{cmsg_len=24, cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, {pid=0, uid=0, gid=0}}], msg_flags=0}, 0) = 105
epoll_pwait(3, [{EPOLLIN, {u32=36381, u64=4776546117586292253}}], 2, -1, NULL, 8) = 1

    sysfs中的伪文件(/sys/class/power_supply/*)的名称都是标准的一一事实上,它们都是指向特定的平台设备节点的符号文件,而这些设备节,点的名称,在不同的设备上可能是各不相同的。其中,保存有系统当前关于power_supply的各种状态。

hammerhead:/sys/class/power_supply # ls -al
total 0
drwxr-xr-x  2 root root 0 1970-04-22 10:55 .
drwxr-xr-x 60 root root 0 1970-04-22 10:55 ..
lrwxrwxrwx  1 root root 0 1970-04-22 10:55 ac -> ../../devices/f9923000.i2c/i2c-84/84-006b/power_supply/ac
lrwxrwxrwx  1 root root 0 1970-04-22 10:55 batt_therm -> ../../devices/battery_tm_ctrl.78/power_supply/batt_therm
lrwxrwxrwx  1 root root 0 1970-04-22 10:55 battery -> ../../devices/f9923000.i2c/i2c-84/84-0036/power_supply/battery
lrwxrwxrwx  1 root root 0 1970-04-22 10:55 touch -> ../../devices/virtual/power_supply/touch
lrwxrwxrwx  1 root root 0 1970-04-22 10:55 usb -> ../../devices/msm_dwc3/power_supply/usb
lrwxrwxrwx  1 root root 0 1970-04-22 10:55 wireless -> ../../devices/bq51013b_wlc.77/power_supply/wireless

3 被用作charger守护进程的healthd

    在Android 5之前的系统中,有一个特殊的守护进程charger,如果系统检测出自己正在充电模式下启动,那么init进程就会启动这个守护进程(通过class_start charger 指令,仅包含一个单独的服务)。

    在Android 5之后的系统中,charger己经被合并到healthd里去了,因为healthd的主要任务就是监视电池电量的相关状态,在以charger模式运行时,healthd会以一种类似init的“分身” (watchdog和ueventd)的形式运行。 在源码目录:~/LineageOS/system/core/rootdir/init.rc中:

# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
    class_stop charger
    trigger late-init

on charger
    class_start charger

    在源码目录:~/LineageOS/device/lge/hammerhead/init.hammerhead.rc中:

service charger /sbin/healthd -c
    class charger
    critical
    seclabel u:r:healthd:s0

    换而言之,/charger现在只不过是/sbin/healthd的一个符号链接,只不过是用一个-c参数启动。 可以查看系统根目录:

hammerhead:/ $ ls charger -al
lrwxrwxrwx 1 root root 13 1969-12-31 13:00 charger -> /sbin/healthd

    charger守护进程负责在设备充电时,把电池电量信息以图形的形式显示给用户看,如下图所示:

                                    

    healthd在Android中扮演一个更为重要的角色。它的重要性可以体现在它是为数不多的几个被放在root文件系统中的守护进程之一(healthd位于/sbin目录中,而不像其他大多数守护进程那样位于/system/bin目录中)。

4 后续的

    后续如果工作中涉及到它时再分析吧,就写这些... Enjoy it!

© 著作权归作者所有

Captain_小馬佩德罗
粉丝 3
博文 40
码字总数 83064
作品 0
南京
Android工程师
私信 提问
详解 Android 系统启动过程

Android的启动过程可以分为两个阶段,第一阶段是Linux的启动,第二阶段才是Android的启动,下面我们分别来了解一下具体的过程。 首先是Linux启动,这一部分我想就可以略过了,无非是Linux的B...

鉴客
2011/09/15
12.1K
0
2018年Android的保活方案效果统计

一、常见保活方案 1、监听广播:监听全局的静态广播,比如时间更新的广播、开机广播、解锁屏、网络状态、解锁加锁亮屏暗屏(3.1版本),高版本需要应用开机后运行一次才能监听这些系统广播,...

codeGoogle
2018/10/30
0
0
当我们按下电源键,Android 究竟做了些什么?

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由goo发表于云+社区专栏 相信我们对Android系统都不陌生,而Android系统博大精深,被各种各样的智能设备承载的同时,我们会否...

腾讯云加社区
2018/11/13
0
0
全面盘点当前Android后台保活方案的真实运行效果(截止2019年前)

本文原作者“minminaya”,作者网站:minminaya.cn,为了提升文章品质,即时通讯网对内容作了幅修订和改动,感谢原作者。 1、引言 对于IM应用和消息推送服务的开发者来说,在Android机型上的...

首席大胸器
2018/12/27
0
0
全面盘点当前Android后台保活方案的真实运行效果(截止2019年前)

本文原作者“minminaya”,作者网站:minminaya.cn,为了提升文章品质,即时通讯网对内容作了幅修订和改动,感谢原作者。 1、引言 对于IM应用和消息推送服务的开发者来说,在Android机型上的...

JackJiang2011
2018/12/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

局域网能互相ping通,ubuntu虚拟机不能上外网

【问题】 桥接模式老是无法上网,查看本机IP发现被分配了一个私网地址,猜测应该是虚拟DHCP服务器没有打开,于是查看Ubuntu的网络配置: /etc/network/interfaces 发现没有dhcp配置的信息,只...

tahiti_aa
42分钟前
1
0
以太坊助记词PHP开发包简介

以太坊助记词PHP开发包用来为PHP以太坊应用增加助记词和层级确定密钥支持能力。下载地址:以太坊助记词php开发包 。 1、开发包概述 以太坊助记词PHP开发包主要包括以下特性: 生成符合BIP39...

汇智网教程
昨天
2
0
系统监控-分布式调用链Skywalking

1. 为什么要使用分布式调用链技术? 随着公司业务的高速发展,公司服务之间的调用关系愈加复杂,如何理清并跟踪它们之间的调用关系就显的比较关键。线上每一个请求会经过多个业务系统,并产生...

秋日芒草
昨天
4
0
告诉自己的一些建议

摆脱学生心态 尽快发挥自己价值,让公司感知自己的存在,才是王道 选择比努力重要 自己附着的平台的经济体要是一个快速崛起的行业 转行趁早,年龄越大选择成本越高 趁早大量试错,学习新领域...

林怡丰
昨天
3
0
Windows下安装Redis

下载地址: 3.0老版已不维护更新:https://github.com/MicrosoftArchive/redis/releases 4.0版 https://github.com/tporadowski/redis/releases 中文官网:http://www.redis.net.cn/ https:......

Aeroever
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部