前言:BatteryService用于获取电池信息、充电状态等,如果想对Android的功耗控制有更深入的了解,有必要分析一下BatteryService。
1.来看下BatteryService.java:
BatteryService.java
public BatteryService(Context context) {
super(context);
mContext = context;
mHandler = new Handler(true /*async*/);
//Led封装了LightsManager,不同电量下led灯的颜色就由它来控制
mLed = new Led(context, getLocalService(LightsManager.class));
//电池属性改变的时候,会将全部信息写到mBatteryStats中,app端从mBatteryStats中获取当前电池的电量以及状态
mBatteryStats = BatteryStatsService.getService();
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
//以下是根据配置文件,定义不同电量对应的等级
//电池危急的电量;当电池电量低于此值时,将强制关机,这里是5
mCriticalBatteryLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
//低电警告的电量;当电池电量低于此值时,系统报警,例如闪烁LED灯等,这里是15
mLowBatteryWarningLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
//关闭低电警告的电量;当电池电量高于此值时,结束低电状态,停止警示灯,这里是20
mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
//关闭电池的温度(温度失控,就会出现三星S7爆炸啥的......)
mShutdownBatteryTemperature = mContext.getResources().getInteger(
com.android.internal.R.integer.shutdownBatteryTemperature);
// 监控终端是否连接不匹配的充电器
if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
UEventObserver invalidChargerObserver = new UEventObserver() {
@Override
public void onUEvent(UEvent event) {
final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
synchronized (mLock) {
if (mInvalidCharger != invalidCharger) {
mInvalidCharger = invalidCharger;
}
}
}
};
invalidChargerObserver.startObserving(
"DEVPATH=/devices/virtual/switch/invalid_charger");
}
}
(1)既然是服务,那就看下它的onStart()方法:
public void onStart() {
//获取电源属性服务的BinderProxy对象,java层通过Binder直接与native层通信
IBinder b = ServiceManager.getService("batteryproperties");
final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
IBatteryPropertiesRegistrar.Stub.asInterface(b);
try {
//向电源属性服务注册一个回调接口
//当电源属性发生变化时,BatteryListener的batteryPropertiesChanged函数将被调用
batteryPropertiesRegistrar.registerListener(new BatteryListener());
} catch (RemoteException e) {
// Should never happen.
}
mBinderService = new BinderService();
//将自己注册到service manager进程中
publishBinderService("battery", mBinderService);
//以后BatteryManagerInternal接口类型的对象,只能有BatteryService的内部类LocalService一个
publishLocalService(BatteryManagerInternal.class, new LocalService());
}
我们使用BatteryListener监听了电池属性的变化,当电池属性改变时,native层会回调BatteryListener.batteryPropertiesChanged()方法:
private final class BatteryListener extends IBatteryPropertiesListener.Stub {
@Override
public void batteryPropertiesChanged(BatteryProperties props) {
final long identity = Binder.clearCallingIdentity();
try {
//电源属性发生变化后,回调BatteryService的update函数
BatteryService.this.update(props);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
再来看下update()方法:
private void update(BatteryProperties props) {
synchronized (mLock) {
//从代码来看,mUpdatesStopped默认为false,通过调用onShellCommand()它的值才有可能改变
if (!mUpdatesStopped) {
//mBatteryProps包含了电池的所有信息,由底层传递过来
mBatteryProps = props;
//更新电源相关的信息
processValuesLocked(false);
} else {
mLastBatteryProps.set(props);
}
}
}
这个processValuesLocked()函数会在后面重点分析;
(2)说完了BatteryService的启动过程,还需要看一下onBootPhase()函数,这个函数什么时候会被调用呢?
在SystemServiceManager中有一个startBootPhase(final int phase )函数,这个函数有啥作用呢?
android系统的启动,是分为几个阶段的,startBootPhase(final int phase)中的这个phase,就表示android系统的启动目前处于哪个阶段,SystemServiceManager将这个phase传递给每个系统服务,每个服务可以根据不同的阶段去做不同的事情;
来看下BatteryService在系统不同的启动阶段做了哪些事情:
public void onBootPhase(int phase) {
//在PHASE_ACTIVITY_MANAGER_READY阶段后,进行部分初始化即
if (phase == PHASE_ACTIVITY_MANAGER_READY) {
// check our power situation now that it is safe to display the shutdown dialog.
synchronized (mLock) {
ContentObserver obs = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
synchronized (mLock) {
updateBatteryWarningLevelLocked();
}
}
};
final ContentResolver resolver = mContext.getContentResolver();
//监听设置中低电量警告的电量值是否改变,改变时调用updateBatteryWarningLevelLocked函数
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
false, obs, UserHandle.USER_ALL);
updateBatteryWarningLevelLocked();
}
}
}
onBootPhase()函数主要是注册一个监听器,检测低电量警告的电量值是否改变,然后调用updateBatteryWarningLevelLocked()函数。
接下来就开始分析processValuesLocked()和updateBatteryWarningLevelLocked()函数;
2.processValuesLocked()函数解析
private void processValuesLocked(boolean force) {
//force表示是否需要强制更新的意思
boolean logOutlier = false;
long dischargeDuration = 0;
//判断当前电量是否危险,mBatteryProps包含了电池的所有信息,由底层传递过来,一旦小于等于5,就很危险了
mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
//得到当前的充电类型
if (mBatteryProps.chargerUsbOnline) {
//USB充电
mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
} else if (mBatteryProps.chargerWirelessOnline) {
//无限充电
mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
} else if (mBatteryProps.chargerAcOnline) {
//充电器充电
mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
} else {
//没有充电
mPlugType = BATTERY_PLUGGED_NONE;
}
try {
//电池属性改变的时候,会将全部信息写到mBatteryStats中,app端从mBatteryStats中获取当前电池的电量以及状态
mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter,
mBatteryProps.batteryFullCharge);
} catch (RemoteException e) {
// Should never happen.
}
//电池电量低(batteryLevel==0)且未充电时,弹出关机对话框
shutdownIfNoPowerLocked();
//电池温度过高(默认为68C),弹出关机对话框
shutdownIfOverTempLocked();
//强制更新,或电源相关属性发生变化时,进行对应操作
if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
mBatteryProps.batteryHealth != mLastBatteryHealth ||
mBatteryProps.batteryPresent != mLastBatteryPresent ||
mBatteryProps.batteryLevel != mLastBatteryLevel ||
mPlugType != mLastPlugType ||
mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
mBatteryProps.maxChargingCurrent != mLastMaxChargingCurrent ||
mBatteryProps.maxChargingVoltage != mLastMaxChargingVoltage ||
mBatteryProps.batteryChargeCounter != mLastChargeCounter ||
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?
// 当前未充电,且当前电量小于提醒电量,设置低电量为true
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;
}
}
mSequence++;
// 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) {
final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
mHandler.post(new Runnable() {
@Override
public void run() {
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
} else if (mPlugType == 0 && mLastPlugType != 0) {
final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
mHandler.post(new Runnable() {
@Override
public void run() {
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
}
if (shouldSendBatteryLowLocked()) {
mSentLowBatteryBroadcast = true;
final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
mHandler.post(new Runnable() {
@Override
public void run() {
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
} else if (mSentLowBatteryBroadcast &&
mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel) {
mSentLowBatteryBroadcast = false;
final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
mHandler.post(new Runnable() {
@Override
public void run() {
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
}
});
}
//发送广播ACTION_BATTERY_CHANGED给外界,内含电源当前的全部信息
sendIntentLocked();
// 根据电源的电量和状态,改变LED灯的颜色
mLed.updateLightsLocked();
if (logOutlier && dischargeDuration != 0) {
//利用BatteryInfoService记录耗电情况的dump文件
logOutlierLocked(dischargeDuration);
}
//更新本地变量
mLastBatteryStatus = mBatteryProps.batteryStatus;
mLastBatteryHealth = mBatteryProps.batteryHealth;
mLastBatteryPresent = mBatteryProps.batteryPresent;
mLastBatteryLevel = mBatteryProps.batteryLevel;
mLastPlugType = mPlugType;
mLastBatteryVoltage = mBatteryProps.batteryVoltage;
mLastBatteryTemperature = mBatteryProps.batteryTemperature;
mLastMaxChargingCurrent = mBatteryProps.maxChargingCurrent;
mLastMaxChargingVoltage = mBatteryProps.maxChargingVoltage;
mLastChargeCounter = mBatteryProps.batteryChargeCounter;
mLastBatteryLevelCritical = mBatteryLevelCritical;
mLastInvalidCharger = mInvalidCharger;
}
}
3.再来看下updateBatteryWarningLevelLocked()函数:
private void updateBatteryWarningLevelLocked() {
final ContentResolver resolver = mContext.getContentResolver();
//获取XML中配置的默认警告电量值
int defWarnLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
//获取设置中用户定义的电量警告值
mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
//用户没有定义,则使用默认的
if (mLowBatteryWarningLevel == 0) {
mLowBatteryWarningLevel = defWarnLevel;
}
//警告值不能低于危险值
if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
mLowBatteryWarningLevel = mCriticalBatteryLevel;
}
//计算出关闭警告的电量值
mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
//更新电池信息
processValuesLocked(true);
}
4.看下充电时的led灯变化
日常开发中,关于充电时的led灯的bug比较多,这里简单的说下,Led是BatteryService的内部类:
private final class Led {
private final Light mBatteryLight;
private final int mBatteryLowARGB;
private final int mBatteryMediumARGB;
private final int mBatteryFullARGB;
private final int mBatteryLedOn;
private final int mBatteryLedOff;
public Led(Context context, LightsManager lights) {
//获取充电led灯,这个在LightService中说明过
mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
//以下是不同电量状态时的led灯颜色
mBatteryLowARGB = context.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryLowARGB);
mBatteryMediumARGB = context.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
mBatteryFullARGB = context.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryFullARGB);
mBatteryLedOn = context.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryLedOn);
mBatteryLedOff = context.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryLedOff);
}
//更新led灯
public void updateLightsLocked() {
final int level = mBatteryProps.batteryLevel;
final int status = mBatteryProps.batteryStatus;
//电量低于BatteryWarning的电量
if (level < mLowBatteryWarningLevel) {
//已经连接上充电
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
//指示灯显示红色
mBatteryLight.setColor(mBatteryLowARGB);
} else {
//没有连接充电线,红灯闪烁
mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
mBatteryLedOn, mBatteryLedOff);
}
} else if (status == BatteryManager.BATTERY_STATUS_CHARGING
|| status == BatteryManager.BATTERY_STATUS_FULL) {
//当前正在充电或者当前电量已经充满
if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
//当电池已经充满或者快要充满的时候指示灯显示绿色
mBatteryLight.setColor(mBatteryFullARGB);
} else {
//当正在充电或者电量超过一半的时候,指示灯显示橘黄色
mBatteryLight.setColor(mBatteryMediumARGB);
}
} else {
//其他正常情况指示灯关闭
mBatteryLight.turnOff();
}
}
}
5.电池属性改变的时候,为什么要将全部信息传递到mBatteryStats中?
IBatteryStats mBatteryStats = BatteryStatsService.getService();
IBatteryStats的实现类是BatteryStatsImpl,BatteryStatsImpl继承自BatteryStats,BatteryStats可以被app获取到,它的setBatteryState()方法会将电池属性写到历史记录,并且计算了电池的已用时间和可用时间,这样,当我们需要用到电池信息的时候,就可以先获取到当前的BatteryStats,然后再从BatteryStats中获取电池属性;
从上面可以看出,app端既可以从广播得到电池的当前属性,还可以通过BatteryStats得到电池的当前属性;