码迷,mamicode.com
首页 > 移动开发 > 详细

android6.0系统Healthd分析及低电量自动关机流程

时间:2018-12-25 20:06:47      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:了解   服务   ||   boolean   事件处理   timer   eve   etop   rem   

 

系统平台:android6.0
概述
Healthd是android4.4之后提出来的一种中介模型,该模型向下监听来自底层的电池事件,向上传递电池数据信息给Framework层的BatteryService用以计算电池电量相关状态信息,BatteryServcie通过传递来的数据来计算电池电量显示,剩余电量,电量级别等信息,如果收到过温报警或者严重低电报警等信息,系统会直接关机,保护硬件。

1.主模块处理流程
Healthd模块代码是在system/core/healthd/,其模块入口在healthd的main函数,函数代码如下:

 1 int main(int argc, char **argv) {
 2     int ch;
 3     int ret;
 4 /*代码中开始便是解析参数,healthd_mode_ops是一个关于充电状态结构体变量,
 5  *结构体变量里的参数是函数指针,在初始化时指向各个不同的操作函数,
 6  *当开机充电时变量赋值为&android_ops,关机充电时候变量赋值为&charger_ops。
 7  */
 8     klog_set_level(KLOG_LEVEL);
 9     healthd_mode_ops = &android_ops;    //正常开机充电
10     
11   //charger为该程序的可执行文件名,该行代码主要用于区分是命令操作还是正常代码启动
12     if (!strcmp(basename(argv[0]), "charger")) {   
13         
14         healthd_mode_ops = &charger_ops;   
15     } else {
16         while ((ch = getopt(argc, argv, "cr")) != -1) {
17             switch (ch) {           //根据不同的参数赋与不同的操作方法
18             case c:
19                 healthd_mode_ops = &charger_ops;   
20                 break;
21             case r:
22                 healthd_mode_ops = &recovery_ops;
23                 break;
24             case ?:
25             default:
26                 KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
27                            optopt);
28                 exit(1);
29             }
30         }
31     }
32     
33     //对需要数据上报的事件进行初始化,分别是healthd_mode_ops、wakealarm和uevent三个事件
34     ret = healthd_init();   
35     
36     if (ret) {
37         KLOG_ERROR("Initialization failed, exiting\n");
38         exit(2);
39     }
40     healthd_mainloop();
41     KLOG_ERROR("Main loop terminated, exiting\n");
42     return 3;
43 }

 



1.1healthd_init( )函数分析

 1 static int healthd_init() {
 2     epollfd = epoll_create(MAX_EPOLL_EVENTS);  //创建epoll用于事件触发
 3     if (epollfd == -1) {
 4         KLOG_ERROR(LOG_TAG,
 5                    "epoll_create failed; errno=%d\n",
 6                    errno);
 7         return -1;
 8     }
 9     healthd_board_init(&healthd_config);     
10     //次处为调用android_ops->init进行初始化    
11     healthd_mode_ops->init(&healthd_config);  
12     //对wakealarm进行初始化,用于周期触发事件上报数据  
13     wakealarm_init();             
14     //对uevent进行初始化,用于域套节字进行数据传输    
15     uevent_init();                   
16     
17     /*在healthd_init中最后创建BatteryMonitor的对象,并将其初始化。
18     BatteryMonitor主要接受healthd传来的数据,做电池状态的计算并更新。*/
19     gBatteryMonitor = new BatteryMonitor();    
20     gBatteryMonitor->init(&healthd_config);     
21     return 0;
22 }

 



创建一个epoll的变量将其赋值给epollfd,在healthd_board_init中未作任何事便返回了。
healthd_mode_ops->init调用有两种情况:关机情况下调用charger_ops的init函数;开机情况下调用android_ops的init函数,这里就开机情况来分析。android_ops的init函数指针指向healthd_mode_android_init函数
代码如下:

 1 void healthd_mode_android_init(struct healthd_config* /*config*/) {
 2     ProcessState::self()->setThreadPoolMaxThreadCount(0);//线程池里最大线程数
 3     IPCThreadState::self()->disableBackgroundScheduling(true);//禁用后台调度
 4     IPCThreadState::self()->setupPolling(&gBinderFd);
 5     if (gBinderFd >= 0) {
 6         //gBinderfd加入到epoll中
 7         if (healthd_register_event(gBinderFd, binder_event))
 8                
 9             /********healthd_register_event函数分析****************
10             int healthd_register_event(int fd, void (*handler)(uint32_t)) {
11                 struct epoll_event ev;
12                 ev.events = EPOLLIN | EPOLLWAKEUP;        //设置事件类型
13                 ev.data.ptr = (void *)handler;       //加入事件处理函数
14                 //将被监听的描述符添加到epoll
15                 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {  
16                 KLOG_ERROR(LOG_TAG,
17                        "epoll_ctl failed; errno=%d\n", errno);
18                         return -1;
19                 }
20                 eventct++;
21                 return 0;
22             }
23             */
24             KLOG_ERROR(LOG_TAG,
25                        "Register for binder events failed\n");
26     }
27     gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
28     //将"batteryproperties"这个Service注册到ServiceManager中
29     gBatteryPropertiesRegistrar->publish();        
30 }



前面三条语句做初始化工作,设置线程池最大线程数,禁用后台调度,以及将gBinderfd加入到epoll中。healthd_register_event将binder_event事件注册到gBinderfd文件节点用以监听Binder事件。gBatteryPropertiesRegistrar->publish将"batteryproperties"这个Service注册到ServiceManager中

再来看看wakealarm_init函数:

 1 static void wakealarm_init(void) {
 2     //首先创建一个wakealarm_fd的定时器与之对应的文件描述符
 3     wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);   
 4     if (wakealarm_fd == -1) {
 5         KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
 6         return;
 7     }
 8 
 9     //healthd_register_event将wakealarm事件注册到wakealarm_fd文件节点用以监听wakealarm事件
10     if (healthd_register_event(wakealarm_fd, wakealarm_event))   
11         KLOG_ERROR(LOG_TAG,
12                    "Registration of wakealarm event failed\n");
13      //wakealarm_set_interval设置alarm唤醒的间隔
14     wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
15 }


再看看uevent_init函数:

 1 static void uevent_init(void) {
 2   //创建并打开一个64k的socket文件描述符uevent_fd
 3  uevent_fd = uevent_open_socket(64*1024, true);
 4  if (uevent_fd < 0) {
 5      KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
 6      return;
 7  }
 8  fcntl(uevent_fd, F_SETFL, O_NONBLOCK);        //设置文件状态标志为非阻塞模
 9    //将uevent事件注册到uevent_fd文件节点用以监听uevent事件
10  if (healthd_register_event(uevent_fd, uevent_event))  
11      KLOG_ERROR(LOG_TAG,
12                 "register for uevent events failed\n");
13 }



我们可以看到android利用epoll监听了三个文件节点的改变事件,分别是:通过gBinderfd监听线程Binder通信事件;通过wakealarm_fd监听wakealarm事件;
通过uevent_fd监听wakealarm事件。至于如何监听后面做详细分析
在healthd_init中最后创建BatteryMonitor的对象,并将其初始化。BatteryMonitor主要接受healthd传来的数据,做电池状态的计算并更新。

我们可以看到在BatterMonitor中的init函数中有以下语句:

 1 /*POWER_SUPPLY_SYSFS_PATH定义为"/sys/class/power_supply",
 2 在init函数中打开系统该文件夹,然后一一读取该文件夹下的文件内容*/
 3 DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);    
 4 struct dirent* entry;
 5 。。。。。。。
 6  //在while循环中判断该文件夹下各个文件节点的内容,并将其初始化给相关的参数
 7  while ((entry = readdir(dir))) {      
 8      const char* name = entry->d_name;
 9 。。。。。。
10 }


至此,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;
     
     /*这里介绍一下轮询机制中重要函数epoll_waite().
       epoll_wait运行的道理是:等侍注册在epfd上的socket fd的事务的产生,
       若是产生则将产生的sokct fd和事务类型放入到events数组中。
       且timeout如果为-1则为阻塞式,timeowout为0则表示非阻塞式。
       可以看到代码中timeout为-1,故为阻塞式轮询,当epollfd上有事件发生,
       则会走到下面的处理逻辑。
      */
     nevents = epoll_wait(epollfd, events, eventct, timeout);
     if (nevents == -1) {
         if (errno == EINTR)
             continue;
         KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
         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()更新电池状态。

 1 void healthd_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 int new_wake_interval = gBatteryMonitor->update() ? //更新,调用BatteryMonitor的update函数,根据不同充电状态设置不同的定时器唤醒周期
 5     healthd_config.periodic_chores_interval_fast :
 6         healthd_config.periodic_chores_interval_slow;    
 7  if (new_wake_interval != wakealarm_wake_interval)     
 8          wakealarm_set_interval(new_wake_interval);     //new_wake_interval表示新的wakealarm唤醒间隔
 9  // During awake periods poll at fast rate.  If wake alarm is set at fast
10  // rate then just use the alarm; if wake alarm is set at slow rate then
11  // poll at fast rate while awake and let alarm wake up at slow rate when
12  // asleep.
13  if (healthd_config.periodic_chores_interval_fast == -1)
14      awake_poll_interval = -1;
15  else
16      awake_poll_interval =
17          new_wake_interval == healthd_config.periodic_chores_interval_fast ?
18              -1 : healthd_config.periodic_chores_interval_fast * 1000;
19 }


可以看出该函数并不长,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实现代码如下:

 1 int healthd_register_event(int fd, void (*handler)(uint32_t)) {
 2  struct epoll_event ev;
 3  ev.events = EPOLLIN | EPOLLWAKEUP;
 4  ev.data.ptr = (void *)handler;
 5  if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
 6      KLOG_ERROR(LOG_TAG,
 7                 "epoll_ctl failed; errno=%d\n", errno);
 8      return -1;
 9  }
10  eventct++;
11  return 0;
12 }


函数将相应的文件节点事件赋值为函数的第二个形参,也就是说相应的gBinderfd的事件处理函数为binder_event函数,同理wakealarm_fd,ueven_fd的事件事件处理分别为wakealarm_event,uevent_event函数。然后将其三个文件节点加入到epollfd中。

事件获取与处理
Healthd中维持了一个阻塞式的死循环healthd_mainloop,在该函数中提供阻塞式的监听已发送的事件函数epoll_wait(),healthd_mainloop中有如下代码

1      nevents = epoll_wait(epollfd, events, eventct, timeout);
2      if (nevents == -1) {
3          if (errno == EINTR)
4              continue;
5          KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
6          break;
7      }


当epoll_waite接受到gBinderfd,wakealarm_fd,uevent_fd其中的事件,便会将监听到的事件加入到event数组中。在for循环中做处理,for循环中代码看起来非常难懂,其实if判断的便是event有没有相应的处理函数,在前面注册事件时候已经提到,三种句柄上的事件都有对应的处理函数,也就是当收到gBinderfd上的事件,便用binder_event函数处理,当收到uevent_fd上的事件便用uevent_event处理,当收到wakealarm_fd上的事件便用wakealarm_event处理。
这里以较为重要的uevent_event事件处理为例:

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


处理函数首先从uevent_fd 获取事件数目,然后循环判断是否是来自与power_supply目录下的事件,如果是,则调用到healthd_battery_update中去更新电池状态。

更新电池状态
当收到事件,做一些判断工作便需要更新电池状态,其更新函数为healthd.cpp下的healthd_battery_update函数,但是主要更新并不在heathd中完成的,而是在BatteryMonitor中的update函数:

  1 bool BatteryMonitor::update(void) {
  2  bool logthis;
  3  //清除原有属性值
  4  props.chargerAcOnline = false;                        
  5  props.chargerUsbOnline = false;
  6  props.chargerWirelessOnline = false;
  7  props.batteryStatus = BATTERY_STATUS_UNKNOWN;
  8  props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
  9  props.maxChargingCurrent = 0;
 10  if (!mHealthdConfig->batteryPresentPath.isEmpty())
 11      props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
 12  else
 13      props.batteryPresent = mBatteryDevicePresent;
 14  props.batteryLevel = mBatteryFixedCapacity ?
 15      mBatteryFixedCapacity :
 16      getIntField(mHealthdConfig->batteryCapacityPath);
 17  props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
 18  props.batteryTemperature = mBatteryFixedTemperature ?
 19      mBatteryFixedTemperature :
 20      getIntField(mHealthdConfig->batteryTemperaturePath);
 21  // For devices which do not have battery and are always plugged
 22  // into power souce.
 23  if (mAlwaysPluggedDevice) {
 24      props.chargerAcOnline = true;
 25      props.batteryPresent = true;
 26      props.batteryStatus = BATTERY_STATUS_CHARGING;
 27      props.batteryHealth = BATTERY_HEALTH_GOOD;
 28  }
 29  
 30  const int SIZE = 128;
 31  char buf[SIZE];
 32  String8 btech;
 33  //读取/sys/class/power_supply下文件节点信息
 34  if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0)     
 35      props.batteryStatus = getBatteryStatus(buf);
 36  if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0)
 37      props.batteryHealth = getBatteryHealth(buf);
 38  if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0)
 39      props.batteryTechnology = String8(buf);
 40  
 41  /*在init函数中将healthd_config 对象传入,并且将里面的成员的一些地址信息去初始化保存起来。
 42  主要是保存一些地址信息,以及充电方式。在BatteryMonitor初始化中,heathd_config传入init函数中,
 43  赋值为mHealthdConfig,上面一段主要是读取/sys/class/power_supply下的
 44  文件节点信息初更新电池数据属性值
 45  */
 46  
 47  unsigned int i;
 48  //遍历/sys/class/power_supply下的文件节点获取信息
 49  for (i = 0; i < mChargerNames.size(); i++) {     
 50      String8 path;
 51      path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,    
 52                        mChargerNames[i].string());
 53        //读取子目录文件online的值,online值为1使用,0值没使用
 54      if (readFromFile(path, buf, SIZE) > 0) {  
 55          if (buf[0] != 0) {
 56              path.clear();
 57              path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
 58                                mChargerNames[i].string());
 59              switch(readPowerSupplyType(path)) {     //根据读取的值将相应的属性值置true
 60              case ANDROID_POWER_SUPPLY_TYPE_AC:
 61                  props.chargerAcOnline = true;     //true,false在framework层用于充电状态判读
 62                  break;
 63              case ANDROID_POWER_SUPPLY_TYPE_USB:
 64                  props.chargerUsbOnline = true;
 65                  break;
 66              case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
 67                  props.chargerWirelessOnline = true;
 68                  break;
 69              default:
 70                  KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
 71                               mChargerNames[i].string());
 72              }
 73              path.clear();
 74              path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
 75                                mChargerNames[i].string());
 76              if (access(path.string(), R_OK) == 0) {
 77                  int maxChargingCurrent = getIntField(path);
 78                  if (props.maxChargingCurrent < maxChargingCurrent) {
 79                      props.maxChargingCurrent = maxChargingCurrent;
 80                  }
 81              }
 82          }
 83      }
 84  }
 85  logthis = !healthd_board_battery_update(&props);    //此处必返回0
 86  if (logthis) {    //此处必执行
 87      char dmesgline[256];
 88      //更新props的各个属性值,props将会被传到framework层进行数据传输
 89      if (props.batteryPresent) {  
 90          snprintf(dmesgline, sizeof(dmesgline),
 91               "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
 92               props.batteryLevel, props.batteryVoltage,
 93               props.batteryTemperature < 0 ? "-" : "",
 94               abs(props.batteryTemperature / 10),
 95               abs(props.batteryTemperature % 10), props.batteryHealth,
 96               props.batteryStatus);
 97          if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
 98              int c = getIntField(mHealthdConfig->batteryCurrentNowPath);
 99              char b[20];
100              snprintf(b, sizeof(b), " c=%d", c / 1000);
101              strlcat(dmesgline, b, sizeof(dmesgline));
102          }
103      } else {
104          snprintf(dmesgline, sizeof(dmesgline),
105               "battery none");
106      }
107      size_t len = strlen(dmesgline);
108      snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
109               props.chargerAcOnline ? "a" : "",
110               props.chargerUsbOnline ? "u" : "",
111               props.chargerWirelessOnline ? "w" : "");
112      log_time realtime(CLOCK_REALTIME);
113      time_t t = realtime.tv_sec;
114      struct tm *tmp = gmtime(&t);
115      if (tmp) {
116          static const char fmt[] = " %Y-%m-%d %H:%M:%S.XXXXXXXXX UTC";
117          //前的电量级别,电压,温度,健康状况,电池状态以及充放电倍率存入dmesgline变量中,
118          len = strlen(dmesgline);    
119          if ((len < (sizeof(dmesgline) - sizeof(fmt) - 8)) // margin
120                  && strftime(dmesgline + len, sizeof(dmesgline) - len,
121                              fmt, tmp)) {
122              char *usec = strchr(dmesgline + len, X);
123              if (usec) {
124                  len = usec - dmesgline;
125                  snprintf(dmesgline + len, sizeof(dmesgline) - len,
126                           "%09u", realtime.tv_nsec);
127                  usec[9] =  ;
128              }
129          }
130      }
131      KLOG_WARNING(LOG_TAG, "%s\n", dmesgline); //向log记录电池当前各种状态信息
132  }
133  healthd_mode_ops->battery_update(&props);  //更新电池
134  
135  /*回是否在充电状态个update函数做完更新数据,记录数据到log之后,
136  然后调用到BatteryPropertiesRegistrar的update函数继续更新电池状态,
137  最后返回值为是否处于充电状态。*/
138  return props.chargerAcOnline | props.chargerUsbOnline |  
139          props.chargerWirelessOnline;
140 }


BatteryPropertiesRegistrar的update函数未作任何操作调用Healthd_mode_android.cpp中的healthd_mode_android_battery_update函数,我们可以看看该函数

1 void healthd_mode_android_battery_update(
2  struct android::BatteryProperties *props) {    //props携带各种需要传输的数据
3  if (gBatteryPropertiesRegistrar != NULL)
4    //调用BatteryPropertiesRegistrar的notifyListeners去通知props改变了
5      gBatteryPropertiesRegistrar->notifyListeners(*props);
6  return;
7 }


这里这里直接调用到BatteryPropertiesRegistrar的notifyListeners去通知props改变了,props是什么呢?props是定义的一个BatteryProperties属性集,里面的成员变量包含了所有的电池状态信息,在update开始便通过读取各个文件节点的实时数据更新电池属性props,更新完成后通过BatteryPropertiesRegistrar通知其属性监听者去更新状态,但是谁是监听呢?

我们可以看到framework层中的BatteryService.java的onStart函数中有如下代码:

 1  public void onStart() {
 2      IBinder b = ServiceManager.getService("batteryproperties");
 3      final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
 4              IBatteryPropertiesRegistrar.Stub.asInterface(b);
 5      try {
 6          batteryPropertiesRegistrar.registerListener(new BatteryListener());  //监听事件
 7      } catch (RemoteException e) {
 8          // Should never happen.
 9      }
10      publishBinderService("battery", new BinderService());
11      publishLocalService(BatteryManagerInternal.class, new LocalService());
12  }


我们在初始化的时候已经提到过,当healthd初始化时候会创建BatteryPropertiesRegistrar的对象并将其publish注册到系统服务中,注册服务的语句如下:
defaultServiceManager()->addService(String16(“batteryproperties”), this);

所以BatteryService在这里获取该服务,并以此注册其监听器为BatteryListener(),该监听器监听到BatteryProperties改变便会调用到BatteryService的update函数,去做电池电量相关计算以及显示。

至此更新操作基本分析完成,其简要流程如下图所
技术分享图片

============================================================================================================
下面以低电量关机为例分析BatteryService监听到数据后的处理流程
电池监听函数如下:

 1  private final class BatteryListener extends IBatteryPropertiesListener.Stub {
 2      @Override
 3      public void batteryPropertiesChanged(BatteryProperties props) {
 4          final long identity = Binder.clearCallingIdentity();
 5          try {
 6              BatteryService.this.update(props);   //监听到数据调用BatteryService的update函数
 7          } finally {
 8              Binder.restoreCallingIdentity(identity);
 9          }
10     }
11  }


函数调用流程:
BatteryListener
==>BatteryService.this.update(props)
   ==>processValuesLocked(false);
     ==>shutdownIfNoPowerLocked(); //在此函数中对充电数据进行处理,根据不同的充电条件判断是否关机

shutdownIfNoPowerLocked函数代码如下:

 1  private void shutdownIfNoPowerLocked() {
 2      // shut down gracefully if our battery is critically low and we are not powered.
 3      // wait until the system has booted before attempting to display the shutdown dialog.
 4      //isPoweredLocked判断充电的状态,如果电量为零但又没有接充电器的情况下关机
 5      if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
 6          mHandler.post(new Runnable() {
 7              @Override
 8              public void run() {   //执行关机的代码
 9                  if (ActivityManagerNative.isSystemReady()) {
10                      Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
11                      intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
12                      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
13                      mContext.startActivityAsUser(intent, UserHandle.CURRENT);
14                  }
15              }
16          });
17      }
18  }


isPoweredLocked函数代码如下:

 1  private boolean isPoweredLocked(int plugTypeSet) {
 2      // assume we are powered if battery state is unknown so
 3      // the "stay on while plugged in" option will work.
 4      
 5      //如果状态不确定,默认为在充电
 6      if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {   
 7          return true;
 8      }
 9      //为插入AC并且为AC充电状态则返回true不关机
10      if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mBatteryProps.chargerAcOnline) {
11          return true;
12      }
13      //插入USB并且为USB充电状态则返回true不关机
14      if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mBatteryProps.chargerUsbOnline) {
15          return true;
16      }
17      //无线充电
18      if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mBatteryProps.chargerWirelessOnline) {
19          return true;
20      }
21      return false;
22  }


总结:
Healthd是framework层传递来自底层电池事件信息并调用相关模块更新电池状态的一个中间层,其向下监听来自底层PMU驱动上报的uevent电池事件,向上调用BatteryService去计算电池,电量,使用等相关信息,它通过一个阻塞式的死循环不断监听底层三个文件节点上的事件信息,当监听到事件便调用到BatteryMonitor执行更新操作,通过BatteryService.java中注册监听电池属性改变的函数,当电池属性信息发生改变,即回调到BatteryService中做更新操作,更新完成一次电池事件的上报到更新整个流程就完成;总之Healthd是连接Battery模块framework中java层与HAL层交互的主要通道。

附:在此博客上整理添加而来
  https://blog.csdn.net/u011311586/article/details/51082685

android6.0系统Healthd分析及低电量自动关机流程

标签:了解   服务   ||   boolean   事件处理   timer   eve   etop   rem   

原文地址:https://www.cnblogs.com/ljin/p/10175603.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!