healthd

healthd是安卓4.4之后提出来的,监听来自kernel的电池事件,并向上传递电池数据给framework层的BatteryService。BatteryService计算电池电量显示,剩余电量,电量级别以及绘制充电动画等信息,其代码位于/system/core/healthd。


android/system/core/healthd/
Android.mk BatteryMonitor.h BatteryPropertiesRegistrar.h healthd.cpp healthd_mode_android.cpp images
BatteryMonitor.cpp BatteryPropertiesRegistrar.cpp healthd_board_default.cpp healthd.h healthd_mode_charger.cpp

下面一张图清晰的表示了Android电池系统框架

healthd服务入口:android/system/core/healthd/healthd.cpp 中main函数。

int main(int argc, char **argv) {
int ch;
int ret; klog_set_level(KLOG_LEVEL); //healthd_mode_ops是一个关于充电状态的结构体变量,
healthd_mode_ops = &android_ops;//开机充电时,指向android_ops if (!strcmp(basename(argv[0]), "charger")) {
healthd_mode_ops = &charger_ops; //
} else {
while ((ch = getopt(argc, argv, "cr")) != -1) {
switch (ch) {
case 'c':
healthd_mode_ops = &charger_ops; //关机状态下的充电
break;
case 'r':
healthd_mode_ops = &recovery_ops;//recovery下的操作
break;
case '?':
default:
KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
optopt);
exit(1);
}
}
} ret = healthd_init(); //healthed初始化
if (ret) {
KLOG_ERROR("Initialization failed, exiting\n");
exit(2);
} healthd_mainloop(); //主循环
KLOG_ERROR("Main loop terminated, exiting\n");
return 3;
}

在main函数中,首先根据传入的参数不同区分:开机充电、recovery、关机充电。这三种情况,然后指定不同的healthd_mode_ops回调函数。因此有必要贴出来这三个重要的回调。

///////////////////////////////////////////////////////////////////////////三个相关的ops
static struct healthd_mode_ops android_ops = { 开机充电
.init = healthd_mode_android_init,
.preparetowait = healthd_mode_android_preparetowait,
.heartbeat = healthd_mode_nop_heartbeat,
.battery_update = healthd_mode_android_battery_update,
}; static struct healthd_mode_ops charger_ops = { 关机充电
.init = healthd_mode_charger_init,
.preparetowait = healthd_mode_charger_preparetowait,
.heartbeat = healthd_mode_charger_heartbeat,
.battery_update = healthd_mode_charger_battery_update,
}; static struct healthd_mode_ops recovery_ops = { recover相关的
.init = healthd_mode_nop_init,
.preparetowait = healthd_mode_nop_preparetowait,
.heartbeat = healthd_mode_nop_heartbeat,
.battery_update = healthd_mode_nop_battery_update,
};

接着往下看healthd_init()

static int healthd_init() {
epollfd = epoll_create(MAX_EPOLL_EVENTS);//创建一个epoll变量
if (epollfd == -1) {
KLOG_ERROR(LOG_TAG,
"epoll_create failed; errno=%d\n",
errno);
return -1;
}
//和板子级别的初始化,里面其实是一个空函数,什么也没做
healthd_board_init(&healthd_config);
//根据系统所处的模式,有三种情况的init,开机充电,关机充电,recovery
healthd_mode_ops->init(&healthd_config);
//wakealarm定时器初始化
wakealarm_init();
//uevent事件初始化,用以监听电池的uevent事件。
uevent_init();
//BatteryMonitor初始化。
gBatteryMonitor = new BatteryMonitor();//创建batteryMonitor对象
gBatteryMonitor->init(&healthd_config);//初始化batteryMonitor,打开/sys/class/power_supply,
//遍历该节点下的电池参数初始化healthd的config参数
return 0;
}

healthd_mode_ops->init(&healthd_config);根据main函数中传入的参数 有三种模式,Android,charger,recovery。

android模式

void healthd_mode_android_init(struct healthd_config* /*config*/) {
ProcessState::self()->setThreadPoolMaxThreadCount(0);//获取线程池最大线程数
IPCThreadState::self()->disableBackgroundScheduling(true);//禁止后台调用
IPCThreadState::self()->setupPolling(&gBinderFd);//将gBinderFd加入到epoll中 if (gBinderFd >= 0) {
//将binder_event事件注册到gBinderfd文件节点用以监听Binder事件。
if (healthd_register_event(gBinderFd, binder_event))
KLOG_ERROR(LOG_TAG,
"Register for binder events failed\n");
} gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
//将batteryProperties注册到ServiceManager中
gBatteryPropertiesRegistrar->publish();
}

charger模式就是关机充电模式,Android层只跑一个healthd服务用来显示充电动画和电量百分比。

charger模式

void healthd_mode_charger_init(struct healthd_config* config) //做充电动画相关的设置
{
int ret;
struct charger *charger = &charger_state;
int i;
int epollfd; dump_last_kmsg(); LOGW("--------------- STARTING CHARGER MODE ---------------\n"); ret = ev_init(input_callback, charger);
if (!ret) {
epollfd = ev_get_epollfd();
healthd_register_event(epollfd, charger_event_handler);
} ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
if (ret < 0) {
LOGE("Cannot load battery_fail image\n");
charger->surf_unknown = NULL;
} charger->batt_anim = &battery_animation; //指定充电动画相关的属性 gr_surface* scale_frames;
int scale_count;
ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);//读取充电动画资源
if (ret < 0) {
LOGE("Cannot load battery_scale image\n");
charger->batt_anim->num_frames = 0;
charger->batt_anim->num_cycles = 1;
} else if (scale_count != charger->batt_anim->num_frames) {
LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
scale_count, charger->batt_anim->num_frames);
charger->batt_anim->num_frames = 0;
charger->batt_anim->num_cycles = 1;
} else {
for (i = 0; i < charger->batt_anim->num_frames; i++) { //读取资源成功,存放起来
charger->batt_anim->frames[i].surface = scale_frames[i];
}
} ev_sync_key_state(set_key_callback, charger); charger->next_screen_transition = -1;
charger->next_key_check = -1;
charger->next_pwr_check = -1;
healthd_config = config;
}
//接着到wakealarm_init
static void wakealarm_init(void) {
//创建一个月wakealarm对应的定时器描述符
wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
if (wakealarm_fd == -1) {
KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
return;
}
//将wakealarm事件注册到wakealarm_fd文件节点上以监听wakealarm事件。
if (healthd_register_event(wakealarm_fd, wakealarm_event))
KLOG_ERROR(LOG_TAG,
"Registration of wakealarm event failed\n");
//设置alarm唤醒间隔
wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
}

如果是关机充电模式,则healthd_mode_ops->heartbeat(); 执行的是healthd_mode_charger_heartbeat()函数

void healthd_mode_charger_heartbeat()
{
struct charger *charger = &charger_state;
int64_t now = curr_time_ms();
int ret; handle_input_state(charger, now); //处理按键相关的事情,长按开机
handle_power_supply_state(charger, now); /* do screen update last in case any of the above want to start
* screen transitions (animations, etc)
*/
update_screen_state(charger, now); //绘制充电动画
}
frameworks/base/services/core/java/com/android/server/BatteryService.java
//将电池监听注册到底层
public void onStart() {
IBinder b = ServiceManager.getService("batteryproperties");
final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
IBatteryPropertiesRegistrar.Stub.asInterface(b);
try {
//注册电池监听,当底层电池电量发生变化调用此监听,并调用update。
batteryPropertiesRegistrar.registerListener(new BatteryListener());
} catch (RemoteException e) {
// Should never happen.
} publishBinderService("battery", new BinderService());
publishLocalService(BatteryManagerInternal.class, new LocalService());
}
//当底层有信息时,会调用update更新BatteryService中相关值。
private void update(BatteryProperties props) {
synchronized (mLock) {
if (!mUpdatesStopped) {
mBatteryProps = props;
// Process the new values.
processValuesLocked(false);
} else {
mLastBatteryProps.set(props);
}
}
}
private void processValuesLocked(boolean force) {
boolean logOutlier = false;
long dischargeDuration = 0;
//获取电池电量是否低于critical界限。
mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
//获取电池充电状态,AC,USB,无线,以及什么都没接。
if (mBatteryProps.chargerAcOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
} else if (mBatteryProps.chargerUsbOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
} else if (mBatteryProps.chargerWirelessOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
} else {
mPlugType = BATTERY_PLUGGED_NONE;
} if (DEBUG) {
Slog.d(TAG, "Processing new values: "
+ "chargerAcOnline=" + mBatteryProps.chargerAcOnline
+ ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline
+ ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
+ ", batteryStatus=" + mBatteryProps.batteryStatus
+ ", batteryHealth=" + mBatteryProps.batteryHealth
+ ", batteryPresent=" + mBatteryProps.batteryPresent
+ ", batteryLevel=" + mBatteryProps.batteryLevel
+ ", batteryTechnology=" + mBatteryProps.batteryTechnology
+ ", batteryVoltage=" + mBatteryProps.batteryVoltage
+ ", batteryTemperature=" + mBatteryProps.batteryTemperature
+ ", mBatteryLevelCritical=" + mBatteryLevelCritical
+ ", mPlugType=" + mPlugType);
} // Let the battery stats keep track of the current level.
try {
mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
mBatteryProps.batteryVoltage);
} catch (RemoteException e) {
// Should never happen.
}
//低电关机
shutdownIfNoPowerLocked();
//电池温度过高关机
shutdownIfOverTempLocked(); if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
mBatteryProps.batteryHealth != mLastBatteryHealth ||
mBatteryProps.batteryPresent != mLastBatteryPresent ||
mBatteryProps.batteryLevel != mLastBatteryLevel ||
mPlugType != mLastPlugType ||
mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
mInvalidCharger != mLastInvalidCharger)) {
//适配器插入状态有更改
if (mPlugType != mLastPlugType) {
if (mLastPlugType == BATTERY_PLUGGED_NONE) {
// discharging -> charging // There's no value in this data unless we've discharged at least once and the
// battery level has changed; so don't log until it does.
if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {
dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
logOutlier = true;
EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
mDischargeStartLevel, mBatteryProps.batteryLevel);
// make sure we see a discharge event before logging again
mDischargeStartTime = 0;
}
} else if (mPlugType == BATTERY_PLUGGED_NONE) {
// charging -> discharging or we just powered up
mDischargeStartTime = SystemClock.elapsedRealtime();
mDischargeStartLevel = mBatteryProps.batteryLevel;
}
}
//电池状态更新
if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
mBatteryProps.batteryHealth != mLastBatteryHealth ||
mBatteryProps.batteryPresent != mLastBatteryPresent ||
mPlugType != mLastPlugType) {
EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,
mPlugType, mBatteryProps.batteryTechnology);
}
if (mBatteryProps.batteryLevel != mLastBatteryLevel) {
// Don't do this just from voltage or temperature changes, that is
// too noisy.
EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);
}
if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
mPlugType == BATTERY_PLUGGED_NONE) {
// We want to make sure we log discharge cycle outliers
// if the battery is about to die.
dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
logOutlier = true;
} if (!mBatteryLevelLow) {
// Should we now switch in to low battery mode?
if (mPlugType == BATTERY_PLUGGED_NONE
&& mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {
mBatteryLevelLow = true;
}
} else {
// Should we now switch out of low battery mode?
if (mPlugType != BATTERY_PLUGGED_NONE) {
mBatteryLevelLow = false;
} else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel) {
mBatteryLevelLow = false;
} else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {
// If being forced, the previous state doesn't matter, we will just
// absolutely check to see if we are now above the warning level.
mBatteryLevelLow = false;
}
}
//发送电池状态变换广播
sendIntentLocked(); // Separate broadcast is sent for power connected / not connected
// since the standard intent will not wake any applications and some
// applications may want to have smart behavior based on this.
if (mPlugType != 0 && mLastPlugType == 0) {
mHandler.post(new Runnable() {
@Override
public void run() {
Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
}
else if (mPlugType == 0 && mLastPlugType != 0) {
mHandler.post(new Runnable() {
@Override
public void run() {
Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
}
//低电量电池事件通知
if (shouldSendBatteryLowLocked()) {
mSentLowBatteryBroadcast = true;
mHandler.post(new Runnable() {
@Override
public void run() {
Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
} else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
mSentLowBatteryBroadcast = false;
mHandler.post(new Runnable() {
@Override
public void run() {
Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
} // Update the battery LED
mLed.updateLightsLocked(); // This needs to be done after sendIntent() so that we get the lastest battery stats.
if (logOutlier && dischargeDuration != 0) {
logOutlierLocked(dischargeDuration);
} mLastBatteryStatus = mBatteryProps.batteryStatus;
mLastBatteryHealth = mBatteryProps.batteryHealth;
mLastBatteryPresent = mBatteryProps.batteryPresent;
mLastBatteryLevel = mBatteryProps.batteryLevel;
mLastPlugType = mPlugType;
mLastBatteryVoltage = mBatteryProps.batteryVoltage;
mLastBatteryTemperature = mBatteryProps.batteryTemperature;
mLastBatteryLevelCritical = mBatteryLevelCritical;
mLastInvalidCharger = mInvalidCharger;
}
}

recovery模式不再分析。

Android Healthd电池服务分析的更多相关文章

  1. Android窗口管理服务WindowManagerService显示窗口动画的原理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8611754 在前一文中,我们分析了Activi ...

  2. Android窗口管理服务WindowManagerService对壁纸窗口(Wallpaper Window)的管理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8550820 Android系统中,壁纸窗口和输 ...

  3. Android窗口管理服务WindowManagerService对输入法窗口(Input Method Window)的管理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8526644 在Android系统中,输入法窗口 ...

  4. Android 媒体存储服务(二)

    Android 媒体存储服务 简介: 本文是<深入Android媒体存储服务>系列第二篇,简要介绍媒体存储服务扫描文件的流程.文中介绍的是 Android 4.2. Android 有一套 ...

  5. [置顶] Android开发之serviceManager分析

    Android 开发之serviceManager分析 在Android系统中用到最多的通信机制就是Binder,Binder主要由Client.Server.ServiceManager和Binde ...

  6. Android窗口管理服务WindowManagerService切换Activity窗口(App Transition)的过程分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8596449 在Android系统中,同一时刻只 ...

  7. Android窗口管理服务WindowManagerService显示Activity组件的启动窗口(Starting Window)的过程分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8577789 在Android系统中,Activ ...

  8. Android窗口管理服务WindowManagerService计算窗口Z轴位置的过程分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8570428 通过前面几篇文章的学习,我们知道了 ...

  9. 专题合集:深入Android媒体存储服务

    Android 有一套媒体存储服务,进程名是 android.process.media,主要负责把磁盘中的文件信息保存到数据库当中,供其他 APP 使用以及 MTP 模式使用.这里包含了数据库管理. ...

随机推荐

  1. nginx的使用,以及反向代理,负载均衡,从安装到使用,全部步骤。

    先总结nginx实现负载均衡的原理,在这之前先的知道反向代理,因为nginx的负载均衡是在反向代理的基础上实现的: 1.反向代理:通过在nginx的配置文件 (vim /opt/nginx196/co ...

  2. Java中代理和装饰者模式的区别

    装饰模式:以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案: 代理模式:给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用: 装饰模式为所装饰的对象增强功能:代理模式对代理的对 ...

  3. 简单聊一聊spring cloud stream和kafka的那点事

    Spring Cloud Stream is a framework for building highly scalable event-driven microservices connected ...

  4. c语言l博客作业09

    问题 答案 这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-2/homework/8655 我在 ...

  5. docker镜像、docker容器导入导出命令

    一.docker镜像导入导出命令 导出命令: docker save -o <保存路径> <镜像名称:标签> docker save -o ./test.tar test:la ...

  6. MongoDB第三天(正则,管道,聚合,字符串,算术,日期,java连接MongoDB)

    部分正则表达式: i:忽略大小写 m:多行查找 x:设置 x 选项后,正则表达式中的非转义的空白字符将被忽略.   s:允许点字符(即.)匹配包括换行符在内的所有字符. w:匹配包括下划线的任何单词字 ...

  7. Apache + WordPress 从 0 搭建

    引言 又到周末了,周末小编一般不更新系列文章,原因嘛是因为要攒稿子,年底工作比较忙,不攒点稿子是要断更的:( 所以周末一般聊点简单轻松加愉快的东西,小编现在的博客站是由 HEXO 进行搭建的,最近随着 ...

  8. [TimLinux] MySQL InnoDB的外键约束不支持set default引用选项

    1. 外键 MySQL的MyISAM是不支持外键的,InnoDB支持外键,外键是MySQL中的三大约束中的一类:主键约束(PRIMARY KEY),唯一性约束(UNIQUE),外键约束(FOREIGN ...

  9. A.Sweet Problem

    题目:甜蜜的问题 题意:你有三堆糖果:红色,绿色,蓝色 第一堆有r个糖果,第二堆有g个糖果,第三堆有b个糖果 每天都可以吃两个不同颜色的糖果,找出可以吃糖果的最大天数 分析:先排下序,如果最大堆大于等 ...

  10. 【CuteJavaScript】Angular6入门项目(3.编写服务和引入RxJS)

    本文目录 一.项目起步 二.编写路由组件 三.编写页面组件 1.编写单一组件 2.模拟数据 3.编写主从组件 四.编写服务 1.为什么需要服务 2.编写服务 五.引入RxJS 1.关于RxJS 2.引 ...