Android Battery 架构
Android电源
android中和电源相关的服务有两个他们在/frameworks/base/services/core/java/com/android/server/
一个是BatteryService.java
,另一个是在目录powe下的PowerManagerService.java
。
电源管理架构
Android电源管理主要通过Wakelock机制来管理系统的状态,整个android电源管理,可以分为四个层次:应用接口层(PowerManager.java),Framework层(PowerManagerService.java), HAL(power.c)和linux内核层(kernel/power)。
应用接口层:PowerManager中开放的接口,应用可以调用PM的接口申请wakelock,唤醒系统,使系统进入休眠等操作。
Framework层:应用程序调用PowerManager开放的接口,对系统操作在PowerManagerService中完成,PowerManagerService计算系统中和power相关的计算,是整个电源管理的决策系统。同时协调power如何与系统其它模块的交互,如亮屏,暗屏,系统睡眠,唤醒等。
HAL层:该层只有一个power.c文件,该文件通过上层传下来的参数,向/sys/power/wake_lock或/sys/power/wake_unlock文件节点写入数据来与kernel进行通信,主要功能是申请/释放锁,维持屏幕亮灭。
kernel层:kernel/power实现电源管理框架。 drivers/power,设备特定的电源管理框架。
电池管理架构
Android系统对电池的管理驱动继承了linux的power supply class。在用户层在BatteryService.java中通过广播的方式将电池相关的属性报给app使用,并且注册了uevent监听电池状态变化,以实时获取电池状态。
代码语言:javascript复制frameworks/base/services/core/java/com/android/server/BatteryService.java
当检测到电池状态变化时,给 {@link android.content.Intent#ACTION_BATTERY_CHANGED BATTERY_CHANGED action}广播给{@link android.content.BroadcastReceiver IntentReceivers}这类的服务。
电池状态新的值存放在{@link android.content.Intent#getExtra Intent.getExtra} ,存放的内容如下:
代码语言:javascript复制scale:最大电池电量值,通常100
level:当前电量值,从0到scale
status;当前充电状态
health:电池状态
present:bool值,如果有电池则值为true
icon-small:整型,该状态建议使用的icon。
plugged:0,设备未插入,1:AC适配器插入, 2, USB插入
voltage:当前电池电压mv
temperature:当前电池温度。
technology:电池类型,如:Li-ion
onStart将电池监听注册到底层
代码语言:javascript复制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.
}
//将POWER_SERVICE作为Binder的服务端,注册到SystemService中
publishBinderService("battery", new BinderService());
//将BatteryManagerInternal注册到本地服务
publishLocalService(BatteryManagerInternal.class, new LocalService());
}
当底层有信息,会调用update更新BatteryService中相关值。
代码语言:javascript复制 private void update(BatteryProperties props) {
synchronized (mLock) {
if (!mUpdatesStopped) {
mBatteryProps = props;
// Process the new values.
processValuesLocked(false);
} else {
mLastBatteryProps.set(props);
}
}
}
processValuesLocked函数如下:
代码语言:javascript复制 private void processValuesLocked(boolean force) {
313 boolean logOutlier = false;
314 long dischargeDuration = 0;
315 //获取电池电量是否低于critical界限
316 mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
//获取充电状态,AC,USB,无线以及什么都没有接
317 if (mBatteryProps.chargerAcOnline) {
318 mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
319 } else if (mBatteryProps.chargerUsbOnline) {
320 mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
321 } else if (mBatteryProps.chargerWirelessOnline) {
322 mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
323 } else {
324 mPlugType = BATTERY_PLUGGED_NONE;
325 }
344 // Let the battery stats keep track of the current level.电池统计信息和当前状态保持一致
345 try {
346 mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
347 mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
348 mBatteryProps.batteryVoltage);
349 } catch (RemoteException e) {
350 // Should never happen.
351 }
//低电量关机
353 shutdownIfNoPowerLocked();
//电池温度过高关机
354 shutdownIfOverTempLocked();
//force是第一次调用时标志,如果状态有更改依然会调用下面的代码
356 if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
357 mBatteryProps.batteryHealth != mLastBatteryHealth ||
358 mBatteryProps.batteryPresent != mLastBatteryPresent ||
359 mBatteryProps.batteryLevel != mLastBatteryLevel ||
360 mPlugType != mLastPlugType ||
361 mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
362 mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
363 mBatteryProps.maxChargingCurrent != mLastMaxChargingCurrent ||
364 mInvalidCharger != mLastInvalidCharger))
//插入状态有更改
366 if (mPlugType != mLastPlugType) {
367 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
368 // 不充电-->充电
369
370 // There's no value in this data unless we've discharged at least once and the
371 // battery level has changed; so don't log until it does.
372 if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {
373 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
374 logOutlier = true;
375 EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
376 mDischargeStartLevel, mBatteryProps.batteryLevel);
377 // make sure we see a discharge event before logging again
378 mDischargeStartTime = 0;
379 }
380 } else if (mPlugType == BATTERY_PLUGGED_NONE) {
381 // 充电-->不充电 或者开机上电
382 mDischargeStartTime = SystemClock.elapsedRealtime();
383 mDischargeStartLevel = mBatteryProps.batteryLevel;
384 }
385 }
//电池状态更新
386 if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
387 mBatteryProps.batteryHealth != mLastBatteryHealth ||
388 mBatteryProps.batteryPresent != mLastBatteryPresent ||
389 mPlugType != mLastPlugType) {
390 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
391 mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,
392 mPlugType, mBatteryProps.batteryTechnology);
393 }
//电池电量更新
394 if (mBatteryProps.batteryLevel != mLastBatteryLevel) {
395 // Don't do this just from voltage or temperature changes, that is
396 // too noisy.
397 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
398 mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);
399 }
...
//发送电池状态变化广播
427 sendIntentLocked();
//对电源连接/断开进行单独的广播,因为标准的intent将不会唤醒任何应用程序并且一些应用程序基于这个信息可以做一些单独的“智能”行为
432 if (mPlugType != 0 && mLastPlugType == 0) {
433 mHandler.post(new Runnable() {
434 @Override
435 public void run() {
436 Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
437 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
438 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
439 }
440 });
441 }
442 else if (mPlugType == 0 && mLastPlugType != 0) {
443 mHandler.post(new Runnable() {
444 @Override
445 public void run() {
446 Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
447 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
448 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
449 }
450 });
451 }
//低电量电池事件通知
453 if (shouldSendBatteryLowLocked()) {
454 mSentLowBatteryBroadcast = true;
455 mHandler.post(new Runnable() {
456 @Override
457 public void run() {
458 Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
459 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
460 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
461 }
462 });
463 } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
464 mSentLowBatteryBroadcast = false;
465 mHandler.post(new Runnable() {
466 @Override
467 public void run() {
468 Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
469 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
470 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
471 }
472 });
473 }
475 // Update the battery LED
476 mLed.updateLightsLocked();
478 // This needs to be done after sendIntent() so that we get the lastest battery stats.
479 if (logOutlier && dischargeDuration != 0) {
480 logOutlierLocked(dischargeDuration);
481 }
482
483 mLastBatteryStatus = mBatteryProps.batteryStatus;
484 mLastBatteryHealth = mBatteryProps.batteryHealth;
485 mLastBatteryPresent = mBatteryProps.batteryPresent;
486 mLastBatteryLevel = mBatteryProps.batteryLevel;
487 mLastPlugType = mPlugType;
488 mLastBatteryVoltage = mBatteryProps.batteryVoltage;
489 mLastBatteryTemperature = mBatteryProps.batteryTemperature;
490 mLastMaxChargingCurrent = mBatteryProps.maxChargingCurrent;
491 mLastBatteryLevelCritical = mBatteryLevelCritical;
492 mLastInvalidCharger = mInvalidCharger;
493 }
healtd
healthd是安卓4.4之后提出来的,监听来自kernel的电池事件,并向上传递电池数据给framework层的BatteryService。BatteryService计算电池电量显示,剩余电量,电量级别等信息,其代码位于/system/core/healthd。
根据Android.mk文件。
代码语言:javascript复制LOCAL_SRC_FILES :=
healthd.cpp
healthd_mode_android.cpp
healthd_mode_charger.cpp
BatteryMonitor.cpp
BatteryPropertiesRegistrar.cpp
LOCAL_MODULE := healthd
LOCAL_MODULE_TAGS := optional
LOCAL_FORCE_STATIC_EXECUTABLE := true
这个目录下的文件会被编译成healthd可执行程序。
代码语言:javascript复制int main(int argc, char **argv) {
int ch;
int ret;
static pthread_t thread;//Talen
klog_set_level(KLOG_LEVEL);
//正常开机启动
healthd_mode_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':
//recovery下操作
healthd_mode_ops = &recovery_ops;
break;
case '?':
default:
KLOG_ERROR(LOG_TAG, "Talen, Unrecognized healthd option: %cn", optopt);
exit(1);
}
}
}
ret = healthd_init();
healthd_init的初始化如下:
代码语言:javascript复制static int healthd_init() {
epollfd = epoll_create(MAX_EPOLL_EVENTS);
if (epollfd == -1) {
KLOG_ERROR(LOG_TAG,
"epoll_create failed; errno=%dn",
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();
gBatteryMonitor->init(&healthd_config);
return 0;
}
init分为三种情况。
android(healthd_mode_android.cpp)
代码语言:javascript复制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 failedn");
}
gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
//将batteryProperties注册到ServiceManager中
gBatteryPropertiesRegistrar->publish();
}
charger情况(healthd_mode_charger.cpp)
代码语言:javascript复制1105 void healthd_mode_charger_init(struct healthd_config* config)
1106 {
1118 ret = ev_init(input_callback, charger);
1119 if (!ret) {
1120 epollfd = ev_get_epollfd();
1121 healthd_register_event(epollfd, charger_event_handler);
1122 }
1123
1124 ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
1125 if (ret < 0) {
1126 LOGE("Cannot load battery_fail imagen");
1127 charger->surf_unknown = NULL;
1128 }
1129
1130 charger->batt_anim = &battery_animation;
1131
1132 GRSurface** scale_frames;
1133 int scale_count;
1134 ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
1135 if (ret < 0) {
1136 LOGE("Cannot load battery_scale imagen");
1137 charger->batt_anim->num_frames = 0;
1138 charger->batt_anim->num_cycles = 1;
1139 } else if (scale_count != charger->batt_anim->num_frames) {
1140 LOGE("battery_scale image has unexpected frame count (%d, expected %d)n",
1141 scale_count, charger->batt_anim->num_frames);
uevent_init函数
代码语言:javascript复制static void uevent_init(void) {
//创建并打开一个64K的socket文件描述符uevent_fd.
uevent_fd = uevent_open_socket(64*1024, true);
//将其设置为非阻塞模式
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
//将其注册到healthd_init创建的描述符集合里
if (healthd_register_event(uevent_fd, uevent_event))
KLOG_ERROR(LOG_TAG,
"register for uevent events failedn");
}
BatteryMonitor.cpp
代码语言:javascript复制void BatteryMonitor::init(struct healthd_config *hc) {
String8 path;
char pval[PROPERTY_VALUE_MAX];
mHealthdConfig = hc;
//打开/sys/class/power_supply,遍历该节点下的电池参数初始化healthd的config参数
DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
接下来main函数调用periodic_chores更新电池状态信息。
代码语言:javascript复制void healthd_battery_update(void) {
// Fast wake interval when on charger (watch for overheat);
// slow wake interval when on battery (watch for drained battery).
//获取新的wakealarm唤醒间隔,fast wake处于充电模式,slow是处于非充电模式的唤醒间隔。
int new_wake_interval = gBatteryMonitor->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);
// 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 == -1)
awake_poll_interval = -1;
else
//轮询间隔时间调节
awake_poll_interval =
new_wake_interval == healthd_config.periodic_chores_interval_fast ?
-1 : healthd_config.periodic_chores_interval_fast * 1000;
}
static void periodic_chores() {
healthd_battery_update();
}
uevent_event处理函数如下。
代码语言:javascript复制#define UEVENT_MSG_LEN 2048
static void uevent_event(uint32_t /*epevents*/) {
char msg[UEVENT_MSG_LEN 2];
char *cp;
int n;
n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
if (n <= 0)
return;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
return;
msg[n] = '