POWER_SUPPLY_SYSFS_PATH定义为"/sys/class/power_supply",在init函数中打开系统该文件夹,然后一一读取该文件夹下的文件内容,在while循环中判断该文件夹下各个文件节点的内容,并将其初始化给相关的参数.
至此,healthd_init函数就分析完了,其主要工作就是:创建了三个文件节点用来监听相应的三种事件改变;创建BatteryMonitor对象,并通过读取/sys/class/power_supply将其初始化 。
Healthd_init走完之后,接着就是调用healthd_mainloop函数,该函数维持了一个死循环,代码如下:
static void healthd_mainloop(void) { while (1) {struct epoll_event events[eventct];int nevents;int timeout = awake_poll_interval;int mode_timeout;mode_timeout = healthd_mode_ops->preparetowait();if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))timeout = mode_timeout;nevents = epoll_wait(epollfd, events, eventct, timeout);if (nevents == -1) {if (errno == EINTR)continue;KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failedn");break;}for (int n = 0; n < nevents; ++n) {if (events[n].data.ptr)(*(void (*)(int))events[n].data.ptr)(events[n].events);}if (!nevents)periodic_chores();healthd_mode_ops->heartbeat();}return; }Healthd_mainloop中维持了一个死循环,死循环中变量nevents 表示从epollfd中轮循中监听得到的事件数目,这里介绍一下轮询机制中重要函数epoll_waite().
epoll_wait运行的道理是:等侍注册在epfd上的socket fd的事务的产生,若是产生则将产生的sokct fd和事务类型放入到events数组中 。且timeout如果为-1则为阻塞式,timeowout为0则表示非阻塞式 。可以看到代码中timeout为-1,故为阻塞式轮询,当epollfd上有事件发生,则会走到下面的处理逻辑 。事件处理主要在for循环中:
在periodic_chores()中调用到healthd_battery_update()更新电池状态 。
void healthd_battery_update(void) {int new_wake_interval = gBatteryMonitor->update() ?healthd_config.periodic_chores_interval_fast :healthd_config.periodic_chores_interval_slow;if (new_wake_interval != wakealarm_wake_interval)wakealarm_set_interval(new_wake_interval);if (healthd_config.periodic_chores_interval_fast == -1)awake_poll_interval = -1;Elseawake_poll_interval = new_wake_interval == healthd_config.periodic_chores_interval_fast ?-1 : healthd_config.periodic_chores_interval_fast * 1000; }可以看出该函数并不长,new_wake_interval表示新的wakealarm唤醒间隔,通过调用BatteryMonitor的update函数(后面详细分析如何更新),其返回值为是否处于充电状态,当处于充电状态,则唤醒间隔为healthd_config.periodic_chores_interval_fast(短间隔),当不再充电状态时唤醒间隔为healthd_config.periodic_chores_interval_slow(长间隔)
当新的间隔变量new_wake_interval与旧的变量wakealarm_wake_interval不一样,则将新的唤醒间隔设置成wakealarm的唤醒间隔;
awake_poll_internal作为下一次epoll_waite的timeout参数,在这里将其更新,在充电状态下awake_poll_internal为-1,没有充电的状态下awake_poll_internal为60000ms
healthd主流程都是在main函数中处理,至此main已经分析完成,其简要流程图如下

文章插图
Healthd处理逻辑初始化处理前面将healthd模块中main函数分析完了,其主要工作流程有个大概的了解,但是其详细处理逻辑并未做分析,在此之后,对Healthd的初始化,事件处理,状态更新将做一个详细的分析 。
前面已经说过在healthd_init中创建了三个文件节点gBinderfd,uevent_fd,wakealarm_fd,并用以注册监听三种事件,注册监听都是通过healthd_register_event函数实现的 。
healthd_register_event(gBinderFd, binder_event);
healthd_register_event(wakealarm_fd, wakealarm_event);
healthd_register_event(uevent_fd, uevent_event);
其healthd_register_event实现代码如下:
int healthd_register_event(int fd, void (*handler)(uint32_t)) { struct epoll_event ev;ev.events = EPOLLIN | EPOLLWAKEUP;ev.data.ptr = (void *)handler;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {KLOG_ERROR(LOG_TAG,"epoll_ctl failed; errno=%dn", errno);return -1;}eventct++;return 0; }函数将相应的文件节点事件赋值为函数的第二个形参,也就是说相应的gBinderfd的事件处理函数为binder_event函数,同理wakealarm_fd,ueven_fd的事件事件处理分别为wakealarm_event,uevent_event函数 。然后将其三个文件节点加入到epollfd中 。
事件获取与处理Healthd中维持了一个阻塞式的死循环healthd_mainloop,在该函数中提供阻塞式的监听已发送的事件函数epoll_wait(),healthd_mainloop中有如下代码
nevents = epoll_wait(epollfd, events, eventct, timeout);for (int n = 0; n < nevents; ++n) { if (events[n].data.ptr)(*(void (*)(int))events[n].data.ptr)(events[n].events); }
推荐阅读
- 安溪引进有身份证茶追溯系统确保茶叶安全
- 六大运动疗法有效调理消化系统改善肠胃
- 手把手教你用 KODI tMM 打造家庭影院系统
- 京东商城交易系统的演进
- 成为“黑客”前,必学的“系统命令”
- thinkphp常用系统配置大全
- win10系统无法进入安全模式解决方法
- 终于知道为什么黑客学习过程首选的系统是Linux系统而不是windows
- 为什么要有分布式系统?
- 霞浦标准园创建区建成首个茶叶自动喷灌系统
