android6.0系統(tǒng)Healthd深入分析[轉(zhuǎn)載]

概述
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層交互的主要通道。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末霎肯,一起剝皮案震驚了整個濱河市擎颖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌观游,老刑警劉巖肠仪,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異备典,居然都是意外死亡异旧,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門提佣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吮蛹,“玉大人,你說我怎么就攤上這事拌屏〕闭耄” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵倚喂,是天一觀的道長每篷。 經(jīng)常有香客問我,道長端圈,這世上最難降的妖魔是什么焦读? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮舱权,結(jié)果婚禮上矗晃,老公的妹妹穿的比我還像新娘。我一直安慰自己宴倍,他們只是感情好张症,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布仓技。 她就那樣靜靜地躺著,像睡著了一般俗他。 火紅的嫁衣襯著肌膚如雪脖捻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天兆衅,我揣著相機與錄音郭变,去河邊找鬼。 笑死涯保,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的周伦。 我是一名探鬼主播夕春,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼专挪!你這毒婦竟也來了及志?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤寨腔,失蹤者是張志新(化名)和其女友劉穎速侈,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迫卢,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡倚搬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了乾蛤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片每界。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖家卖,靈堂內(nèi)的尸體忽然破棺而出眨层,到底是詐尸還是另有隱情,我是刑警寧澤上荡,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布趴樱,位于F島的核電站,受9級特大地震影響酪捡,放射性物質(zhì)發(fā)生泄漏叁征。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一逛薇、第九天 我趴在偏房一處隱蔽的房頂上張望航揉。 院中可真熱鬧,春花似錦金刁、人聲如沸帅涂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽媳友。三九已至斯议,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間醇锚,已是汗流浹背哼御。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留焊唬,地道東北人恋昼。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像赶促,于是被迫代替她去往敵國和親液肌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容