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.h和system/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电源驱动是如何管理系统中的不同电源类型的。