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

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

 int main(int argc, char **argv) {
int ch;
int ret;
/*代码中开始便是解析参数,healthd_mode_ops是一个关于充电状态结构体变量,
*结构体变量里的参数是函数指针,在初始化时指向各个不同的操作函数,
*当开机充电时变量赋值为&android_ops,关机充电时候变量赋值为&charger_ops。
*/
klog_set_level(KLOG_LEVEL);
healthd_mode_ops = &android_ops; //正常开机充电   //charger为该程序的可执行文件名,该行代码主要用于区分是命令操作还是正常代码启动
if (!strcmp(basename(argv[]), "charger")) { healthd_mode_ops = &charger_ops;   
} else {
while ((ch = getopt(argc, argv, "cr")) != -) {
switch (ch) { //根据不同的参数赋与不同的操作方法
case 'c':
healthd_mode_ops = &charger_ops;
break;
case 'r':
healthd_mode_ops = &recovery_ops;
break;
case '?':
default:
KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
optopt);
exit();
}
}
} //对需要数据上报的事件进行初始化,分别是healthd_mode_ops、wakealarm和uevent三个事件
ret = healthd_init(); if (ret) {
KLOG_ERROR("Initialization failed, exiting\n");
exit();
}
healthd_mainloop();
KLOG_ERROR("Main loop terminated, exiting\n");
return ;
}

1.1healthd_init( )函数分析

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

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

 void healthd_mode_android_init(struct healthd_config* /*config*/) {
ProcessState::self()->setThreadPoolMaxThreadCount();//线程池里最大线程数
IPCThreadState::self()->disableBackgroundScheduling(true);//禁用后台调度
IPCThreadState::self()->setupPolling(&gBinderFd);
if (gBinderFd >= ) {
//gBinderfd加入到epoll中
if (healthd_register_event(gBinderFd, binder_event)) /********healthd_register_event函数分析****************
int healthd_register_event(int fd, void (*handler)(uint32_t)) {
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLWAKEUP; //设置事件类型
ev.data.ptr = (void *)handler;       //加入事件处理函数
//将被监听的描述符添加到epoll
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {  
KLOG_ERROR(LOG_TAG,
"epoll_ctl failed; errno=%d\n", errno);
return -1;
}
eventct++;
return 0;
}
*/
KLOG_ERROR(LOG_TAG,
"Register for binder events failed\n");
}
gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
//将"batteryproperties"这个Service注册到ServiceManager中
gBatteryPropertiesRegistrar->publish();
}

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

再来看看wakealarm_init函数:

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

再看看uevent_init函数:

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

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

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

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

至此,healthd_init函数就分析完了,其主要工作就是:创建了三个文件节点用来监听相应的三种事件改变;创建BatteryMonitor对象,并通过读取/sys/class/power_supply将其初始化。

Healthd_init走完之后,接着就是调用healthd_mainloop函数,该函数维持了一个死循环,代码如下:

static void healthd_mainloop(void) {
while () {
struct epoll_event events[eventct];
int nevents;
int timeout = awake_poll_interval;
int mode_timeout;
mode_timeout = healthd_mode_ops->preparetowait();
if (timeout < || (mode_timeout > && 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 == -) {
if (errno == EINTR)
continue;
KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
break;
}
for (int n = ; 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()更新电池状态。

 void healthd_battery_update(void) {
// Fast wake interval when on charger (watch for overheat);
// slow wake interval when on battery (watch for drained battery).
int new_wake_interval = gBatteryMonitor->update() ? //更新,调用BatteryMonitor的update函数,根据不同充电状态设置不同的定时器唤醒周期
healthd_config.periodic_chores_interval_fast :
healthd_config.periodic_chores_interval_slow;  
if (new_wake_interval != wakealarm_wake_interval) 
wakealarm_set_interval(new_wake_interval); //new_wake_interval表示新的wakealarm唤醒间隔
// During awake periods poll at fast rate. If wake alarm is set at fast
// rate then just use the alarm; if wake alarm is set at slow rate then
// poll at fast rate while awake and let alarm wake up at slow rate when
// asleep.
if (healthd_config.periodic_chores_interval_fast == -)
awake_poll_interval = -;
else
awake_poll_interval =
new_wake_interval == healthd_config.periodic_chores_interval_fast ?
- : healthd_config.periodic_chores_interval_fast * ;
}

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

 int healthd_register_event(int fd, void (*handler)(uint32_t)) {
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = (void *)handler;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -) {
KLOG_ERROR(LOG_TAG,
"epoll_ctl failed; errno=%d\n", errno);
return -;
}
eventct++;
return ;
}

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

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

      nevents = epoll_wait(epollfd, events, eventct, timeout);
if (nevents == -) {
if (errno == EINTR)
continue;
KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
break;
}

当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事件处理为例:

 #define UEVENT_MSG_LEN 2048
static void uevent_event(uint32_t /*epevents*/) {
char msg[UEVENT_MSG_LEN+];
char *cp;
int n;
n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
if (n <= )
return;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
return;
msg[n] = '\0';
msg[n+] = '\0';
cp = msg;
while (*cp) {
if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
healthd_battery_update();
break;
}
/* advance to after the next \0 */
while (*cp++)
;
}
}

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

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

 bool BatteryMonitor::update(void) {
bool logthis;
//清除原有属性值
props.chargerAcOnline = false;
props.chargerUsbOnline = false;
props.chargerWirelessOnline = false;
props.batteryStatus = BATTERY_STATUS_UNKNOWN;
props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
props.maxChargingCurrent = ;
if (!mHealthdConfig->batteryPresentPath.isEmpty())
props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
else
props.batteryPresent = mBatteryDevicePresent;
props.batteryLevel = mBatteryFixedCapacity ?
mBatteryFixedCapacity :
getIntField(mHealthdConfig->batteryCapacityPath);
props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / ;
props.batteryTemperature = mBatteryFixedTemperature ?
mBatteryFixedTemperature :
getIntField(mHealthdConfig->batteryTemperaturePath);
// For devices which do not have battery and are always plugged
// into power souce.
if (mAlwaysPluggedDevice) {
props.chargerAcOnline = true;
props.batteryPresent = true;
props.batteryStatus = BATTERY_STATUS_CHARGING;
props.batteryHealth = BATTERY_HEALTH_GOOD;
} const int SIZE = ;
char buf[SIZE];
String8 btech;
//读取/sys/class/power_supply下文件节点信息
if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > )
props.batteryStatus = getBatteryStatus(buf);
if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > )
props.batteryHealth = getBatteryHealth(buf);
if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > )
props.batteryTechnology = String8(buf); /*在init函数中将healthd_config 对象传入,并且将里面的成员的一些地址信息去初始化保存起来。
主要是保存一些地址信息,以及充电方式。在BatteryMonitor初始化中,heathd_config传入init函数中,
赋值为mHealthdConfig,上面一段主要是读取/sys/class/power_supply下的
文件节点信息初更新电池数据属性值
*/ unsigned int i;
//遍历/sys/class/power_supply下的文件节点获取信息
for (i = ; i < mChargerNames.size(); i++) {     
String8 path;
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
//读取子目录文件online的值,online值为1使用,0值没使用
if (readFromFile(path, buf, SIZE) > ) {
if (buf[] != '') {
path.clear();
path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
switch(readPowerSupplyType(path)) {     //根据读取的值将相应的属性值置true
case ANDROID_POWER_SUPPLY_TYPE_AC:
props.chargerAcOnline = true; //true,false在framework层用于充电状态判读
break;
case ANDROID_POWER_SUPPLY_TYPE_USB:
props.chargerUsbOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
props.chargerWirelessOnline = true;
break;
default:
KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
mChargerNames[i].string());
}
path.clear();
path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
if (access(path.string(), R_OK) == ) {
int maxChargingCurrent = getIntField(path);
if (props.maxChargingCurrent < maxChargingCurrent) {
props.maxChargingCurrent = maxChargingCurrent;
}
}
}
}
}
logthis = !healthd_board_battery_update(&props); //此处必返回0
if (logthis) {    //此处必执行
char dmesgline[];
//更新props的各个属性值,props将会被传到framework层进行数据传输
if (props.batteryPresent) {  
snprintf(dmesgline, sizeof(dmesgline),
"battery l=%d v=%d t=%s%d.%d h=%d st=%d",
props.batteryLevel, props.batteryVoltage,
props.batteryTemperature < ? "-" : "",
abs(props.batteryTemperature / ),
abs(props.batteryTemperature % ), props.batteryHealth,
props.batteryStatus);
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
int c = getIntField(mHealthdConfig->batteryCurrentNowPath);
char b[];
snprintf(b, sizeof(b), " c=%d", c / );
strlcat(dmesgline, b, sizeof(dmesgline));
}
} else {
snprintf(dmesgline, sizeof(dmesgline),
"battery none");
}
size_t len = strlen(dmesgline);
snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
props.chargerAcOnline ? "a" : "",
props.chargerUsbOnline ? "u" : "",
props.chargerWirelessOnline ? "w" : "");
log_time realtime(CLOCK_REALTIME);
time_t t = realtime.tv_sec;
struct tm *tmp = gmtime(&t);
if (tmp) {
static const char fmt[] = " %Y-%m-%d %H:%M:%S.XXXXXXXXX UTC";
//前的电量级别,电压,温度,健康状况,电池状态以及充放电倍率存入dmesgline变量中,
len = strlen(dmesgline);    
if ((len < (sizeof(dmesgline) - sizeof(fmt) - )) // margin
&& strftime(dmesgline + len, sizeof(dmesgline) - len,
fmt, tmp)) {
char *usec = strchr(dmesgline + len, 'X');
if (usec) {
len = usec - dmesgline;
snprintf(dmesgline + len, sizeof(dmesgline) - len,
"%09u", realtime.tv_nsec);
usec[] = ' ';
}
}
}
KLOG_WARNING(LOG_TAG, "%s\n", dmesgline); //向log记录电池当前各种状态信息
}
healthd_mode_ops->battery_update(&props);  //更新电池 /*回是否在充电状态个update函数做完更新数据,记录数据到log之后,
然后调用到BatteryPropertiesRegistrar的update函数继续更新电池状态,
最后返回值为是否处于充电状态。*/
return props.chargerAcOnline | props.chargerUsbOnline |  
props.chargerWirelessOnline;
}

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

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

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

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

  public void onStart() {
IBinder b = ServiceManager.getService("batteryproperties");
final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
IBatteryPropertiesRegistrar.Stub.asInterface(b);
try {
batteryPropertiesRegistrar.registerListener(new BatteryListener()); //监听事件
} catch (RemoteException e) {
// Should never happen.
}
publishBinderService("battery", new BinderService());
publishLocalService(BatteryManagerInternal.class, new LocalService());
}

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

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

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

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

  private final class BatteryListener extends IBatteryPropertiesListener.Stub {
@Override
public void batteryPropertiesChanged(BatteryProperties props) {
final long identity = Binder.clearCallingIdentity();
try {
BatteryService.this.update(props);   //监听到数据调用BatteryService的update函数
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}

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

shutdownIfNoPowerLocked函数代码如下:

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

isPoweredLocked函数代码如下:

  private boolean isPoweredLocked(int plugTypeSet) {
// assume we are powered if battery state is unknown so
// the "stay on while plugged in" option will work. //如果状态不确定,默认为在充电
if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
return true;
}
//为插入AC并且为AC充电状态则返回true不关机
if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != && mBatteryProps.chargerAcOnline) {
return true;
}
     //插入USB并且为USB充电状态则返回true不关机
if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != && mBatteryProps.chargerUsbOnline) {
return true;
}
//无线充电
if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != && mBatteryProps.chargerWirelessOnline) {
return true;
}
return false;
}

总结:
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分析及低电量自动关机流程的更多相关文章

  1. android6.0系统Healthd深入分析

    概述 Healthd是android4.4之后提出来的一种中介模型,该模型向下监听来自底层的电池事件,向上传递电池数据信息给Framework层的BatteryService用以计算电池电量相关状态信 ...

  2. [IMX6]Android6.0移植和分析

    0. 知识点 中断(设备树) [IMX6]设备树分析--dts 1. 编译 Android6.0内核移植(1):分析编译日志 Android6.0内核移植(2):kernel编译内核 单独烧录kern ...

  3. I.MX6 android 禁止低电量自动关机

    /************************************************************************ * I.MX6 android 禁止低电量自动关机 ...

  4. Android6.0系统添加那些新特性

        北京时间9月30日凌晨在美国旧金山举行2015年秋季新品公布会.在公布会上代号为"Marshmallow(棉花糖)"的安卓6.0系统正式推出.新系统的总体设计风格依旧保持扁 ...

  5. iTOP-i.MX6Q开发板支持安卓Android6.0系统

    迅为IMX6开发板: Android4.4/6.0系统  Linux + Qt5.7系统  Ubuntu12.04系统 部分案例:HMI:3D打印机:医疗设备:工控机:触控一体机:车载终端 核心板兼容 ...

  6. 华为7.0系统最简单激活xposed框架的流程

    对于喜欢搞机的哥们而言,很多时候会接触到Xposed框架及其种类繁多功能无敌的模块,对于5.0以下的系统版本,只要手机能获得root权限,安装和激活Xposed框架是异常简易的,但随着系统版本的不断更 ...

  7. [RK3288][Android6.0] 系统按键驱动流程分析【转】

    本文转载自:http://blog.csdn.net/kris_fei/article/details/77894406 Rockchip的按键驱动位于 kernel/drivers/input/ke ...

  8. Android6.0中PowerManagerService分析

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=30510400&id=5569393 概述 一直以来,电源管理是 ...

  9. (原创)android6.0系统 PowerManager深入分析(很具体)

    概述 一直以来,电源管理是电子产品设计中很重要的环节.也是不论什么电子设备中最为重要的系统模块之中的一个,优秀的电源管理方案.可以提供持久的续航能力,良好的用户体验.更能提升电子产品的竞争力. 移动设 ...

随机推荐

  1. the interconversion of String and StringBuilder

    package com.itheima_03; /* * StringBuilder和String的相互转换 * * StringBuilder -- String * public String t ...

  2. settimeout、setinterval区别和相互模拟

    前几天翻书,看到“避免双重求值”一节时有提到settimeout().setinterval() 建议传入函数而不是字符串以作为第一个参数,所以这里总结一下settimeout()和setinterv ...

  3. JS获取对象“属性和方法”的方法

    平时在写的代码过程中,经常会遇到对对象Object的数据处理.而在对对象的数据处理中,操作最频繁的是“数据引用”.“值的修改”.“获取关键字(属性)”.平时最烦的也是“获取关键字”,经常忘记怎么去获取 ...

  4. 带你从零学ReactNative开发跨平台App开发(十一)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  5. Ubuntu添加源列表

    1.首先备份源列表:sudo cp /etc/apt/sources.list /etc/apt/sources.list_backup 2.清空原来的/etc/apt/sources.list,添加 ...

  6. git常用命令简集

    基础操作: 初始化git仓库: git init 提交到暂存区: git add “filename” 提交到分支: git commit -m "注释" 工作区状态: git s ...

  7. 转 Js窗体window大小设置

    网页可见区域宽:document.body.clientWidth  网页可见区域高:document.body.clientHeight  网页可见区域宽:document.body.offsetW ...

  8. 关于 未在本地计算机上注册“VFPOLEDB.1” 的解决方案

    在很古老的时候猿们会使用 Microsoft Visual FoxPro(即Dbf)的数据库,用于对数据的存储,和Access类似,而且两者可以互转,可以把它当成数据文件,如Access数据(MDB) ...

  9. 查找数据库表中重复的 Image 类型值

    直接上代码: SELECT * FROM [dbo].[V_Courseware] ))) IN ())) FROM [dbo].[V_Courseware] ))) ); 替换以上代码中相应对象即可 ...

  10. Scala编程之访问修饰符

    private ,protected,public,在不加前两者声明时为public为公共式访问: private为私有式访问:protected为家族式访问,与Java一致. object Oute ...