概述
Healthd是android4.4之后提出來的一種中介模型赶站,該模型向下監(jiān)聽來自底層的電池事件,向上傳遞電池數(shù)據(jù)信息給Framework層的BatteryService用以計算電池電量相關(guān)狀態(tài)信息均芽,BatteryServcie通過傳遞來的數(shù)據(jù)來計算電池電量顯示,剩余電量,電量級別等信息,如果收到過溫報警或者嚴重低電報警等信息佛玄,系統(tǒng)會直接關(guān)機,保護硬件咬最。
主模塊處理流程
Healthd模塊代碼是在system/core/healthd/翎嫡,其模塊入口在healthd的main函數(shù),函數(shù)代碼如下:
1 int main(int argc, char **argv) {
2
3 int ch;
4
5 int ret;
6
7 klog_set_level(KLOG_LEVEL);
8
9 healthd_mode_ops = &android_ops;
10
11
12
13 if (!strcmp(basename(argv[0]), "charger")) {
14
15 healthd_mode_ops = &charger_ops;
16
17 } else {
18
19 while ((ch = getopt(argc, argv, "cr")) != -1) {
20
21 switch (ch) {
22
23 case 'c':
24
25 healthd_mode_ops = &charger_ops;
26
27 break;
28
29 case 'r':
30
31 healthd_mode_ops = &recovery_ops;
32
33 break;
34
35 case '?':
36
37 default:
38
39 KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
40
41 optopt);
42
43 exit(1);
44
45 }
46
47 }
48
49 }
50
51 ret = healthd_init();
52
53 if (ret) {
54
55 KLOG_ERROR("Initialization failed, exiting\n");
56
57 exit(2);
58
59 }
60
61
62
63 healthd_mainloop();
64
65 KLOG_ERROR("Main loop terminated, exiting\n");
66
67 return 3;
68
69 }
可以看出Main函數(shù)并不長永乌,但是其作用確實巨大的惑申,main函數(shù)起著一個統(tǒng)籌兼顧的作用,其他各個模塊函數(shù)去做一些具體相應(yīng)的工作翅雏,最后匯總到main函數(shù)中被調(diào)用圈驼。
代碼中開始便是解析參數(shù),healthd_mode_ops是一個關(guān)于充電狀態(tài)結(jié)構(gòu)體變量,結(jié)構(gòu)體變量里的參數(shù)是函數(shù)指針,在初始化時指向各個不同的操作函數(shù)鼓蜒,當開機充電時變量賦值為&android_ops茁帽,關(guān)機充電時候變量賦值為&charger_ops耘分。
在ret = healthd_init();中進行一些初始化工作。
1 static int healthd_init() {
2
3 epollfd = epoll_create(MAX_EPOLL_EVENTS);
4
5 if (epollfd == -1) {
6
7 KLOG_ERROR(LOG_TAG,
8
9 "epoll_create failed; errno=%d\n",
10
11 errno);
12
13 return -1;
14
15 }
16
17
18
19 healthd_board_init(&healthd_config);
20
21 healthd_mode_ops->init(&healthd_config);
22
23 wakealarm_init();
24
25 uevent_init();
26
27 gBatteryMonitor = new BatteryMonitor();
28
29 gBatteryMonitor->init(&healthd_config);
30
31 return 0;
32
33 }
創(chuàng)建一個epoll的變量將其賦值給epollfd,在healthd_board_init中未作任何事便返回了。
healthd_mode_ops->init調(diào)用有兩種情況:關(guān)機情況下調(diào)用charger_ops的init函數(shù)玉锌;開機情況下調(diào)用android_ops的init函數(shù),這里就開機情況來分析疟羹。android_ops的init函數(shù)指針指向healthd_mode_android_init函數(shù)
代碼如下:
1 void healthd_mode_android_init(struct healthd_config* /*config*/) {
2 ProcessState::self()->setThreadPoolMaxThreadCount(0);//線程池里最大線程數(shù)
3 IPCThreadState::self()->disableBackgroundScheduling(true);//禁用后臺調(diào)度
4 IPCThreadState::self()->setupPolling(&gBinderFd);//
5
6 if (gBinderFd >= 0) {
7 if (healthd_register_event(gBinderFd, binder_event))
8 KLOG_ERROR(LOG_TAG,
9 "Register for binder events failed\n");
10 }
11
12 gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
13 gBatteryPropertiesRegistrar->publish();
14 }
前面三條語句做初始化工作主守,設(shè)置線程池最大線程數(shù),禁用后臺調(diào)度榄融,以及將gBinderfd加入到epoll中参淫。healthd_register_event將binder_event事件注冊到gBinderfd文件節(jié)點用以監(jiān)聽Binder事件。gBatteryPropertiesRegistrar->publish將"batteryproperties"這個Service注冊到ServiceManager中愧杯。
再來看看wakealarm_init函數(shù):
1 static void wakealarm_init(void) {
2 wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
3 if (wakealarm_fd == -1) {
4 KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
5 return;
6 }
7
8 if (healthd_register_event(wakealarm_fd, wakealarm_event))
9 KLOG_ERROR(LOG_TAG,
10 "Registration of wakealarm event failed\n");
11
12 wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
13 }
首先創(chuàng)建一個wakealarm_fd的定時器與之對應(yīng)的文件描述符涎才,healthd_register_event將wakealarm事件注冊到wakealarm_fd文件節(jié)點用以監(jiān)聽wakealarm事件,wakealarm_set_interval設(shè)置alarm喚醒的間隔
再看看uevent_init函數(shù):
1 static void uevent_init(void) {
2 uevent_fd = uevent_open_socket(64*1024, true);
3
4 if (uevent_fd < 0) {
5 KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
6 return;
7 }
8
9 fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
10 if (healthd_register_event(uevent_fd, uevent_event))
11 KLOG_ERROR(LOG_TAG,
12 "register for uevent events failed\n");
13 }
創(chuàng)建并打開一個64k的socket文件描述符uevent_fd力九,設(shè)置文件狀態(tài)標志為非阻塞模耍铜,將uevent事件注冊到uevent_fd文件節(jié)點用以監(jiān)聽uevent事件。
我們可以看到android利用epoll監(jiān)聽了三個文件節(jié)點的改變事件畏邢,分別是:通過gBinderfd監(jiān)聽線程Binder通信事件;通過wakealarm_fd監(jiān)聽wakealarm事件检吆;通過uevent_fd監(jiān)聽wakealarm事件舒萎。至于如何監(jiān)聽后面做詳細分析
在healthd_init中最后創(chuàng)建BatteryMonitor的對象,并將其初始化。BatteryMonitor主要接受healthd傳來的數(shù)據(jù)臂寝,做電池狀態(tài)的計算并更新章鲤。
我們可以看到在BatterMonitor中的init函數(shù)中有以下語句:
1 DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
2
3 struct dirent* entry;
4
5 ......
6
7 while ((entry = readdir(dir))) {
8
9 const char* name = entry->d_name;
10 ......
11
12 }
POWER_SUPPLY_SYSFS_PATH定義為"/sys/class/power_supply",在init函數(shù)中打開系統(tǒng)該文件夾,然后一一讀取該文件夾下的文件內(nèi)容咆贬,在while循環(huán)中判斷該文件夾下各個文件節(jié)點的內(nèi)容败徊,并將其初始化給相關(guān)的參數(shù).
至此,healthd_init函數(shù)就分析完了掏缎,其主要工作就是:創(chuàng)建了三個文件節(jié)點用來監(jiān)聽相應(yīng)的三種事件改變皱蹦;創(chuàng)建BatteryMonitor對象,并通過讀取/sys/class/power_supply將其初始化眷蜈。
Healthd_init走完之后沪哺,接著就是調(diào)用healthd_mainloop函數(shù),該函數(shù)維持了一個死循環(huán)酌儒,代碼如下:
1 static void healthd_mainloop(void) {
2
3 while (1) {
4
5 struct epoll_event events[eventct];
6
7 int nevents;
8
9 int timeout = awake_poll_interval;
10
11 int mode_timeout;
12
13 mode_timeout = healthd_mode_ops->preparetowait();
14
15 if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
16
17 timeout = mode_timeout;
18
19 nevents = epoll_wait(epollfd, events, eventct, timeout);
20
21 if (nevents == -1) {
22
23 if (errno == EINTR)
24
25 continue;
26
27 KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
28
29 break;
30
31 }
32
33 for (int n = 0; n < nevents; ++n) {
34
35 if (events[n].data.ptr)
36
37 (*(void (*)(int))events[n].data.ptr)(events[n].events);
38
39 }
40
41 if (!nevents)
42
43 periodic_chores();
44
45 healthd_mode_ops->heartbeat();
46
47 }
48
49 return;
50
51 }
Healthd_mainloop中維持了一個死循環(huán)辜妓,死循環(huán)中變量nevents 表示從epollfd中輪循中監(jiān)聽得到的事件數(shù)目,這里介紹一下輪詢機制中重要函數(shù)epoll_waite().
epoll_wait運行的道理是:等侍注冊在epfd上的socket fd的事務(wù)的產(chǎn)生忌怎,若是產(chǎn)生則將產(chǎn)生的sokct fd和事務(wù)類型放入到events數(shù)組中籍滴。且timeout如果為-1則為阻塞式,timeowout為0則表示非阻塞式榴啸∧醵瑁可以看到代碼中timeout為-1,故為阻塞式輪詢插掂,當epollfd上有事件發(fā)生灰瞻,則會走到下面的處理邏輯。事件處理主要在for循環(huán)中:
在periodic_chores()中調(diào)用到healthd_battery_update()更新電池狀態(tài)辅甥。
1 void healthd_battery_update(void) {
2
3 int new_wake_interval = gBatteryMonitor->update() ?
4
5 healthd_config.periodic_chores_interval_fast :
6
7 healthd_config.periodic_chores_interval_slow;
8
9
10
11 if (new_wake_interval != wakealarm_wake_interval)
12
13 wakealarm_set_interval(new_wake_interval);
14
15 if (healthd_config.periodic_chores_interval_fast == -1)
16
17 awake_poll_interval = -1;
18
19 Else
20
21 awake_poll_interval = new_wake_interval == healthd_config.periodic_chores_interval_fast ?
22
23 -1 : healthd_config.periodic_chores_interval_fast * 1000;
24
25 }
可以看出該函數(shù)并不長酝润,new_wake_interval表示新的wakealarm喚醒間隔,通過調(diào)用BatteryMonitor的update函數(shù)(后面詳細分析如何更新)璃弄,其返回值為是否處于充電狀態(tài)要销,當處于充電狀態(tài),則喚醒間隔為healthd_config.periodic_chores_interval_fast(短間隔)夏块,當不再充電狀態(tài)時喚醒間隔為healthd_config.periodic_chores_interval_slow(長間隔)
當新的間隔變量new_wake_interval與舊的變量wakealarm_wake_interval不一樣疏咐,則將新的喚醒間隔設(shè)置成wakealarm的喚醒間隔;
awake_poll_internal作為下一次epoll_waite的timeout參數(shù)脐供,在這里將其更新浑塞,在充電狀態(tài)下awake_poll_internal為-1,沒有充電的狀態(tài)下awake_poll_internal為60000ms
healthd主流程都是在main函數(shù)中處理政己,至此main已經(jīng)分析完成酌壕,其簡要流程圖如下
Healthd處理邏輯
初始化處理
前面將healthd模塊中main函數(shù)分析完了,其主要工作流程有個大概的了解,但是其詳細處理邏輯并未做分析卵牍,在此之后果港,對Healthd的初始化,事件處理糊昙,狀態(tài)更新將做一個詳細的分析辛掠。
前面已經(jīng)說過在healthd_init中創(chuàng)建了三個文件節(jié)點gBinderfd,uevent_fd释牺,wakealarm_fd萝衩,并用以注冊監(jiān)聽三種事件,注冊監(jiān)聽都是通過healthd_register_event函數(shù)實現(xiàn)的船侧。
healthd_register_event(gBinderFd, binder_event);
healthd_register_event(wakealarm_fd, wakealarm_event);
healthd_register_event(uevent_fd, uevent_event);
其healthd_register_event實現(xiàn)代碼如下:
1 int healthd_register_event(int fd, void (*handler)(uint32_t)) {
2
3 struct epoll_event ev;
4
5 ev.events = EPOLLIN | EPOLLWAKEUP;
6
7 ev.data.ptr = (void *)handler;
8
9 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
10
11 KLOG_ERROR(LOG_TAG,
12
13 "epoll_ctl failed; errno=%d\n", errno);
14
15 return -1;
16
17 }
18
19 eventct++;
20
21 return 0;
22
23 }
函數(shù)將相應(yīng)的文件節(jié)點事件賦值為函數(shù)的第二個形參欠气,也就是說相應(yīng)的gBinderfd的事件處理函數(shù)為binder_event函數(shù),同理wakealarm_fd,ueven_fd的事件事件處理分別為wakealarm_event镜撩,uevent_event函數(shù)预柒。然后將其三個文件節(jié)點加入到epollfd中。
事件獲取與處理
Healthd中維持了一個阻塞式的死循環(huán)healthd_mainloop袁梗,在該函數(shù)中提供阻塞式的監(jiān)聽已發(fā)送的事件函數(shù)epoll_wait()宜鸯,healthd_mainloop中有如下代碼
1 nevents = epoll_wait(epollfd, events, eventct, timeout);
2
3
4
5 for (int n = 0; n < nevents; ++n) {
6
7 if (events[n].data.ptr)
8
9 (*(void (*)(int))events[n].data.ptr)(events[n].events);
10
11 }
當epoll_waite接受到gBinderfd,wakealarm_fd遮怜,uevent_fd其中的事件淋袖,便會將監(jiān)聽到的事件加入到event數(shù)組中。在for循環(huán)中做處理锯梁,for循環(huán)中代碼看起來非常難懂即碗,其實if判斷的便是event有沒有相應(yīng)的處理函數(shù),在前面注冊事件時候已經(jīng)提到陌凳,三種句柄上的事件都有對應(yīng)的處理函數(shù)剥懒,也就是當收到gBinderfd上的事件,便用binder_event函數(shù)處理合敦,當收到uevent_fd上的事件便用uevent_event處理初橘,當收到wakealarm_fd上的事件便用wakealarm_event處理。
這里以較為重要的uevent_event事件處理為例:
1 #define UEVENT_MSG_LEN 2048
2
3 static void uevent_event(uint32_t /*epevents*/) {
4
5 char msg[UEVENT_MSG_LEN+2];
6
7 char *cp;
8
9 int n;
10
11
12
13 n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
14
15 if (n <= 0)
16
17 return;
18
19 if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
20
21 return;
22
23
24
25 msg[n] = '\0';
26
27 msg[n+1] = '\0';
28
29 cp = msg;
30
31
32
33 while (*cp) {
34
35 if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
36
37 healthd_battery_update();
38
39 break;
40
41 }
42
43
44
45 /* advance to after the next \0 */
46
47 while (*cp++)
48
49 ;
50
51 }
52
53 }
處理函數(shù)首先從uevent_fd 獲取事件數(shù)目充岛,然后循環(huán)判斷是否是來自與power_supply目錄下的事件保檐,如果是,則調(diào)用到healthd_battery_update中去更新電池狀態(tài)崔梗。
更新電池狀態(tài)
當收到事件夜只,做一些判斷工作便需要更新電池狀態(tài),其更新函數(shù)為healthd.cpp下的healthd_battery_update函數(shù)蒜魄,但是主要更新并不在heathd中完成的扔亥,而是在BatteryMonitor中的update函數(shù)爪膊,其代碼較多,分段分析:
1 props.chargerAcOnline = false;
2
3 props.chargerUsbOnline = false;
4
5 props.chargerWirelessOnline = false;
6
7 props.batteryStatus = BATTERY_STATUS_UNKNOWN;
8
9 props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
10
11
12
13 if (!mHealthdConfig->batteryPresentPath.isEmpty())
14
15 props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
16
17 else
18
19 props.batteryPresent = mBatteryDevicePresent;
20
21
22
23 props.batteryLevel = mBatteryFixedCapacity ?
24
25 mBatteryFixedCapacity :
26
27 getIntField(mHealthdConfig->batteryCapacityPath);
28
29 props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
30
31
32
33 props.batteryTemperature = mBatteryFixedTemperature ?
34
35 mBatteryFixedTemperature :
36
37 getIntField(mHealthdConfig->batteryTemperaturePath);
38
39 const int SIZE = 128;
40
41 char buf[SIZE];
42
43 String8 btech;
44
45
46
47 if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0)
48
49 props.batteryStatus = getBatteryStatus(buf);
50
51
52
53 if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0)
54
55 props.batteryHealth = getBatteryHealth(buf);
56
57
58
59 if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0)
60
61 props.batteryTechnology = String8(buf);
在init函數(shù)中將healthd_config 對象傳入砸王,并且將里面的成員的一些地址信息去初始化保存起來。主要是保存一些地址信息峦阁,以及充電方式谦铃。在BatteryMonitor初始化中,heathd_config傳入init函數(shù)中榔昔,賦值為mHealthdConfig驹闰,上面一段主要是讀取/sys/class/power_supply下的文件節(jié)點信息初更新電池數(shù)據(jù)屬性值,
1 path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
2
3 mChargerNames[i].string());
4
5
6
7 if (readFromFile(path, buf, SIZE) > 0) {
8
9 if (buf[0] != '0') {
10
11 path.clear();
12
13 path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
14
15 mChargerNames[i].string());
16
17 switch(readPowerSupplyType(path)) {
18
19 case ANDROID_POWER_SUPPLY_TYPE_AC:
20
21 props.chargerAcOnline = true;
22
23 break;
24
25 case ANDROID_POWER_SUPPLY_TYPE_USB:
26
27 props.chargerUsbOnline = true;
28
29 break;
30
31 case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
32
33 props.chargerWirelessOnline = true;
34
35 break;
36
37 default:
38
39 KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
40
41 mChargerNames[i].string());
42
43 }
44
45 }
46
47 }
這一段代碼其實實現(xiàn)的功能很簡單撒会,通過讀取/sys/class/power_supply/文件夾下不同類型的充電設(shè)備的online節(jié)點嘹朗,如果不為空則表示處于充電狀態(tài),判斷充電類型為AC充電器诵肛,usb充電還是無線充電并將其相應(yīng)的屬性置true屹培。
1 char dmesgline[256];
2
3
4
5 if (props.batteryPresent) {
6
7 snprintf(dmesgline, sizeof(dmesgline),
8
9 "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
10
11 props.batteryLevel, props.batteryVoltage,
12
13 props.batteryTemperature < 0 ? "-" : "",
14
15 abs(props.batteryTemperature / 10),
16
17 abs(props.batteryTemperature % 10), props.batteryHealth,
18
19 props.batteryStatus);
20
21
22
23 if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
24
25 int c = getIntField(mHealthdConfig->batteryCurrentNowPath);
26
27 char b[20];
28
29
30
31 snprintf(b, sizeof(b), " c=%d", c / 1000);
32
33 strlcat(dmesgline, b, sizeof(dmesgline));
34
35 }
將電池當前的電量級別,電壓怔檩,溫度褪秀,健康狀況,電池狀態(tài)以及充放電倍率存入dmesgline變量中薛训,在后面會將電池充電類型媒吗,電池使用時間都以字符串存入dmesgline變量中,然后:
1 KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);//向log記錄電池當前各種狀態(tài)信息
2 }
3
4 healthd_mode_ops->battery_update(&props);//更新電池
5 return props.chargerAcOnline | props.chargerUsbOnline |
6 props.chargerWirelessOnline;//返回是否在充電狀態(tài)
整個update函數(shù)做完更新數(shù)據(jù)乙埃,記錄數(shù)據(jù)到log之后闸英,然后調(diào)用到BatteryPropertiesRegistrar的update函數(shù)繼續(xù)更新電池狀態(tài),最后返回值為是否處于充電狀態(tài)介袜。
BatteryPropertiesRegistrar的update函數(shù)未作任何操作調(diào)用Healthd_mode_android.cpp中的healthd_mode_android_battery_update函數(shù)甫何,我們可以看看該函數(shù)
1 void healthd_mode_android_battery_update(
2
3 struct android::BatteryProperties *props) {
4
5 if (gBatteryPropertiesRegistrar != NULL)
6
7 gBatteryPropertiesRegistrar->notifyListeners(*props);
8
9
10
11 return;
12
13 }
這里這里直接調(diào)用到BatteryPropertiesRegistrar的notifyListeners去通知props改變了,props是什么呢米酬?props是定義的一個BatteryProperties屬性集沛豌,里面的成員變量包含了所有的電池狀態(tài)信息,在update開始便通過讀取各個文件節(jié)點的實時數(shù)據(jù)更新電池屬性props赃额,更新完成后通過BatteryPropertiesRegistrar通知其屬性監(jiān)聽者去更新狀態(tài)加派,但是誰是監(jiān)聽呢?
我們可以看到framework層中的BatteryService.java的onStart函數(shù)中有如下代碼:
1 public void onStart() {
2
3 IBinder b = ServiceManager.getService("batteryproperties");
4
5 final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
6
7 IBatteryPropertiesRegistrar.Stub.asInterface(b);
8
9 try {
10
11 batteryPropertiesRegistrar.registerListener(new BatteryListener());
12
13 } catch (RemoteException e) {
14
15 // Should never happen.
16
17 }
我們在初始化的時候已經(jīng)提到過跳芳,當healthd初始化時候會創(chuàng)建BatteryPropertiesRegistrar的對象并將其publish注冊到系統(tǒng)服務(wù)中芍锦,注冊服務(wù)的語句如下:
defaultServiceManager()->addService(String16("batteryproperties"), this);
所以BatteryService在這里獲取該服務(wù),并以此注冊其監(jiān)聽器為BatteryListener()飞盆,該監(jiān)聽器監(jiān)聽到BatteryProperties改變便會調(diào)用到BatteryService的update函數(shù)娄琉,去做電池電量相關(guān)計算以及顯示次乓。
至此更新操作基本分析完成,其簡要流程如下圖所示
總結(jié)
Healthd是framework層傳遞來自底層電池事件信息并調(diào)用相關(guān)模塊更新電池狀態(tài)的一個中間層孽水,其向下監(jiān)聽來自底層PMU驅(qū)動上報的uevent電池事件票腰,向上調(diào)用BatteryService去計算電池,電量女气,使用等相關(guān)信息杏慰,它通過一個阻塞式的死循環(huán)不斷監(jiān)聽底層三個文件節(jié)點上的事件信息,當監(jiān)聽到事件便調(diào)用到BatteryMonitor執(zhí)行更新操作炼鞠,通過BatteryService.java中注冊監(jiān)聽電池屬性改變的函數(shù)缘滥,當電池屬性信息發(fā)生改變,即回調(diào)到BatteryService中做更新操作谒主,更新完成一次電池事件的上報到更新整個流程就完成朝扼;總之Healthd是連接Battery模塊framework中java層與HAL層交互的主要通道。