Android电源管理-Healthd (1)

OS:Android 4.4.2

Android电源管理底层用的是Linux power supply框架。驱动部分不叙述。只看JAVA、JNI和CPP应用层。

从Android 4.4开始,Google专门提供了一个healthd来监控电源状态。它的路径在:system/core/healthd,编译出来的文件为/sbin/healthd

看一下healthd.cpp中的main函数:

1 int main(int argc, char **argv) {
2     int ch;
3  
4     klog_set_level(KLOG_LEVEL);
5  
6     while ((ch = getopt(argc, argv, "n")) != -1) {
7         switch (ch) {
8         case 'n':
9             nosvcmgr = true;
10             break;
11         case '?':
12         default:
13             KLOG_WARNING(LOG_TAG, "Unrecognized healthd option: %c\n", ch);
14         }
15     }
16  
17     healthd_board_init(&healthd_config);
18     wakealarm_init();
19     uevent_init();
20     binder_init();
21     gBatteryMonitor = new BatteryMonitor();
22     gBatteryMonitor->init(&healthd_config, nosvcmgr);
23  
24     healthd_mainloop();
25     return 0;
26 }

这里引人关注的是最后调用的healthd_mainloop(),仅凭函数名就能知道会进入一个无限循环,这样也就能达到监控电源状态的目的了。跟踪代码看一下这个函数的定义:

1 static void healthd_mainloop(void) {
2     struct epoll_event ev;
3     int epollfd;
4     int maxevents = 0;
5  
6     epollfd = epoll_create(MAX_EPOLL_EVENTS);
7     if (epollfd == -1) {
8         KLOG_ERROR(LOG_TAG,
9                    "healthd_mainloop: epoll_create failed; errno=%d\n",
10                    errno);
11         return;
12     }
13  
14     if (uevent_fd >= 0) {
15         ev.events = EPOLLIN | EPOLLWAKEUP;
16         ev.data.ptr = (void *)uevent_event;
17         if (epoll_ctl(epollfd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1)
18             KLOG_ERROR(LOG_TAG,
19                        "healthd_mainloop: epoll_ctl for uevent_fd failed; errno=%d\n",
20                        errno);
21         else
22             maxevents++;
23     }
24  
25     if (wakealarm_fd >= 0) {
26         ev.events = EPOLLIN | EPOLLWAKEUP;
27         ev.data.ptr = (void *)wakealarm_event;
28         if (epoll_ctl(epollfd, EPOLL_CTL_ADD, wakealarm_fd, &ev) == -1)
29             KLOG_ERROR(LOG_TAG,
30                        "healthd_mainloop: epoll_ctl for wakealarm_fd failed; errno=%d\n",
31                        errno);
32         else
33             maxevents++;
34    }
35  
36     if (binder_fd >= 0) {
37         ev.events = EPOLLIN | EPOLLWAKEUP;
38         ev.data.ptr= (void *)binder_event;
39         if (epoll_ctl(epollfd, EPOLL_CTL_ADD, binder_fd, &ev) == -1)
40             KLOG_ERROR(LOG_TAG,
41                        "healthd_mainloop: epoll_ctl for binder_fd failed; errno=%d\n",
42                        errno);
43         else
44             maxevents++;
45    }
46  
47     while (1) {
48         struct epoll_event events[maxevents];
49         int nevents;
50  
51         IPCThreadState::self()->flushCommands();
52         nevents = epoll_wait(epollfd, events, maxevents, awake_poll_interval);
53  
54         if (nevents == -1) {
55             if (errno == EINTR)
56                 continue;
57             KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
58             break;
59         }
60  
61         for (int n = 0; n < nevents; ++n) {
62             if (events[n].data.ptr)
63                 (*(void (*)())events[n].data.ptr)();
64         }
65  
66         if (!nevents)
67             periodic_chores();
68     }
69  
70     return;
71 }

果不其然,我们看到了while(1)。Android使用了linux epoll来侦听三个文件描述符的变化,分别是uevent_fd、wakealarm_fd和binder_fd。以uevent_fd为例,在这个描述符上关心的事件有EPOLLIN和EPOLLWAKEUP,当底层出现这两个事件的时候,会回调函数uevent_event(),看看这个函数会做些什么:

1 #define UEVENT_MSG_LEN 1024
2 static void uevent_event(void) {
3     char msg[UEVENT_MSG_LEN+2];
4     char *cp;
5     int n;
6  
7     n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
8     if (n <= 0)
9         return;
10     if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
11         return;
12  
13     msg[n] = '\0';
14     msg[n+1] = '\0';
15     cp = msg;
16  
17     while (*cp) {
18         if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
19             battery_update();
20             break;
21         }
22  
23         /* advance to after the next \0 */
24         while (*cp++)
25             ;
26     }
27 }

它会读取socket中的字符串,然后判断事件来源是否是由kernel的power_supply发出的,如果是,那就调用battery_update()更新电源状态。下面来看看battery_update()是如何更新电源状态的:

1 static void battery_update(void) {
2     // Fast wake interval when on charger (watch for overheat);
3     // slow wake interval when on battery (watch for drained battery).
4  
5    int new_wake_interval = gBatteryMonitor->update() ?
6        healthd_config.periodic_chores_interval_fast :
7            healthd_config.periodic_chores_interval_slow;
8  
9     if (new_wake_interval != wakealarm_wake_interval)
10             wakealarm_set_interval(new_wake_interval);
11  
12     // During awake periods poll at fast rate.  If wake alarm is set at fast
13     // rate then just use the alarm; if wake alarm is set at slow rate then
14     // poll at fast rate while awake and let alarm wake up at slow rate when
15     // asleep.
16  
17     if (healthd_config.periodic_chores_interval_fast == -1)
18         awake_poll_interval = -1;
19     else
20         awake_poll_interval =
21             new_wake_interval == healthd_config.periodic_chores_interval_fast ?
22                 -1 : healthd_config.periodic_chores_interval_fast * 1000;
23 }

这里的重点是gBatteryMonitor->update(),gBatteryMonitor的类型为BatteryMonitor。那接下来就把目光专注到system/core/healthd/BatteryMonitor.hsystem/core/healthd/BatteryMonitor.cpp

在BatteryMonitor.h中,我们看到了一个enum,它列出了Android所支持的电源类型:

1 enum PowerSupplyType {
2     ANDROID_POWER_SUPPLY_TYPE_UNKNOWN = 0,
3     ANDROID_POWER_SUPPLY_TYPE_AC,
4     ANDROID_POWER_SUPPLY_TYPE_USB,
5     ANDROID_POWER_SUPPLY_TYPE_WIRELESS,
6     ANDROID_POWER_SUPPLY_TYPE_BATTERY
7 };

可以看出Android当前支持的电源类型有4种:AC,USB,WIRELESS,BATTERY。在这里你可以增加你自己的电源类型,比如CAR(车载)… …
把目光聚焦到BatteryMonitor.cpp,这里有获取电源状态的核心代码。但是在继续看代码之前,我们先来看一下power_supply电源驱动是如何管理系统中的不同电源类型的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值