BatteryService与PMS之间的关系比较密切,提供接口用于获取电池信息、充电状态等。
为了对Android的功耗控制有更深入的了解,我们有必要分析一下BatteryService。
一、启动过程
BatteryService与系统中的许多服务一样,是由SystemServer启动的。
我们一起看看SystemServer中相关的代码:
..............
//PMS是在startBootstrapServices中创建的
startBootstrapServices();
//BatteryService在startCoreServices中创建的
startCoreServices();
..............
跟进一下startCoreServices:
private void startCoreServices() {
mSystemServiceManager.startService(BatteryService.class);
..................
}
之前的博客分析过SystemServiceManager的startService方法。
该方法主要通过反射的方式创建出对应的服务,
然后,将服务保存在SystemServiceManager的mServices变量中,
最后,调用服务对应的onStart方法。
我们不再赘述SystemServiceManager固有启动服务的流程,直接来看看本篇博客的主角BatteryService相关的代码。
1、BatteryService的构造函数
public BatteryService(Context context) {
super(context);
mContext = context;
mHandler = new Handler(true /*async*/);
//内部类Led,控制不同电量下led灯的颜色
mLed = new Led(context, getLocalService(LightsManager.class));
//电量统计服务
mBatteryStats = BatteryStatsService.getService();
//以下是根据配置文件,定义不同电量对应的等级
//电池危急的电量;当电池电量低于此值时,将强制关机
mCriticalBatteryLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
//低电警告的电量;当电池电量低于此值时,系统报警,例如闪烁LED灯等
mLowBatteryWarningLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
//关闭低电警告的电量;当电池电量高于此值时,结束低电状态,停止警示灯
mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
//这里定义的不再是电量,而是关闭电池的温度(温度失控,就会出现三星S7爆炸啥的......)
mShutdownBatteryTemperature = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shutdownBatteryTemperature);
// watch for invalid charger messages if the invalid_charger switch exists
// 监控终端是否连接不匹配的充电器
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");
}
}
从上面的代码可以看出,整体来看BatteryService构造函数是比较简单的,主要的目的就是得到一些变量。
2、onStart函数
接下来我们看看BatteryService的onStart函数:
public void onStart() {
//获取电源属性服务的BinderProxy对象
//电源属性服务运行在android的healthd进程中
//对应文件为system/core/healthd/BatteryPropertiesRegistrar.cpp
//这个写法确实很风骚,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();
//与PMS等很多系统服务一样,将自己注册到service manager进程中
publishBinderService("battery", mBinderService);
//之前介绍PMS时,提到过这个函数
//对于基于LocalServices管理的对象而言,这个函数调用相当于单例模式的进阶版
//以后BatteryManagerInternal接口类型的对象,只能有BatteryService的内部类LocalService一个
publishLocalService(BatteryManagerInternal.class, new LocalService());
}
从以上代码可以看出,BatteryService在onStart函数中主要完成一些服务注册、接口注册的工作。
2.1 BatteryPropertiesRegistrar服务
我们看看BatteryPropertiesRegistrar.h的定义:
.......
namespace android {
class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar,
public IBinder::DeathRecipient {
public:
void publish(const sp<BatteryPropertiesRegistrar>& service);
void notifyListeners(struct BatteryProperties props);
............
}
}; // namespace android
......
再看看BatteryPropertiesRegistrar.cpp中我们目前关注的函数:
namespace android {
void BatteryPropertiesRegistrar::publish(
const sp& service) {
//注册服务到service manager进程
defaultServiceManager()->addService(String16("batteryproperties"), service);
}
void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
Mutex::Autolock _l(mRegistrationLock);
for (size_t i = 0; i < mListeners.size(); i++) {
//通知观察者
mListeners[i]->batteryPropertiesChanged(props);
}
}
void BatteryPropertiesRegistrar::registerListener(const sp& listener) {
{
if (listener == NULL)
return;
Mutex::Autolock _l(mRegistrationLock);
// check whether this is a duplicate
for (size_t i = 0; i < mListeners.size(); i++) {
if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) {
return;
}
}
//存储观察者
mListeners.add(listener);
IInterface::asBinder(listener)->linkToDeath(this);
}
//更新底层的电源状态,最终将调用到BatteryMonitor.cpp的update函数
//也是BatteryService第一次启动,注册Listener后,立马就会更新一次电源信息
healthd_battery_update();
}
..........
} // namespace android
这里我们不展开native层healthd_battery_update的流程,主要是从大量的文件中读取电源的信息,有兴趣的朋友可以进一步研究一下。
此处,我们仅思考一下这种Java层和native层的Binder通信过程。
我们见过太多对等的Binder通信结构,即双方的主体均在native层,或都在Java层。
这是第一次看到客户端在Java层,服务端在native层。
其实仔细想想,这是完全符合Binder通信架构的。
对于客户端而言,它只需要从service manager进程获取到服务端的BpBinder值,然后利用这个BpBinder值逐步构成Java层的BinderProxy对象(会进一步转化为基于业务的服务代理)。
客户端根本就不要求服务端具有Java层的结构。在实际的通信过程中,客户端数据通过Binder驱动,传到服务端的native层。若native层就能够完成处理过程,就不需要往Java层作进一步的传输,直接返回结果即可。整个处理过程,对于客户端而言,完全是透明的。
2.2 回调接口的作用
第一次看到这样的通信用法,扯的有点远了。
我们回过头来看一下BatteryListener的回调接口:
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);
}
}
}
BatteryService的update函数定义如下:
private void update(BatteryProperties props) {
synchronized (mLock) {
//从代码来看,mUpdatesStopped默认为false,通过shell command才有可能改变
if (!mUpdatesStopped) {
mBatteryProps = props;
// Process the new values.
//更新电源相关的信息,后文详细介绍
processValuesLocked(false);
} else {
mLastBatteryProps.set(props);
}
}
}
易于看出,BatteryService注册回调接口的作用是:更新其维护的电源信息。
二、onBootPhase
除去上述的基本启动过程外,还需要关注一下BatteryService的onBootPhase函数。
1、基础知识
以前分析系统服务时,忽视了这个接口,现在借此机会补充一下此处的知识。
在SystemServiceManager中提供了以下接口:
/**
* Starts the specified boot phase for all system services that have been started up to
* this point.
*
*/
public void startBootPhase(final int phase) {
..............
mCurrentPhase = phase;
..............
try {
.............
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
//前面的博客已经分析过,SystemServer利用SystemServiceManager启动的系统服务
//均会保留在mServices中
final SystemService service = mServices.get(i);
try {
//调用此时已经加入的service的onBootPhase函数
service.onBootPhase(mCurrentPhase);
} catch (Exception ex) {
............
}
}
} finally {
.............
}
}
SystemServiceManager的startBootPhase函数中的参数,对应于系统启动的不同阶段。
详细的定义在SystemService.java中:
/*
* Boot Phases
*/
public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100;
/**
* After receiving this boot phase, services can obtain lock settings data.
*/
public static final int PHASE_LOCK_SETTINGS_READY = 480;
/**
* After receiving this boot phase, services can safely call into core system services
* such as the PowerManager or PackageManager.
*/
public static final int PHASE_SYSTEM_SERVICES_READY = 500;
/**
* After receiving this boot phase, services can broadcast Intents.
*/
public static final int PHASE_ACTIVITY_MANAGER_READY = 550;
/**
* After receiving this boot phase, services can start/bind to third party apps.
* Apps will be able to make Binder calls into services at this point.
*/
public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
/**
* After receiving this boot phase, services can allow user interaction with the device.
* This phase occurs when boot has completed and the home application has started.
* System services may prefer to listen to this phase rather than registering a
* broadcast receiver for ACTION_BOOT_COMPLETED to reduce overall latency.
*/
public static final int PHASE_BOOT_COMPLETED = 1000;
以上是原生定义的系统启动的不同阶段。
这么做的目的是:
SystemServer会依次启动许多服务,但服务之间的功能是相互依赖的。
因此,每个服务刚被启动时,都完成最基本的初始化。
当系统运行到某个阶段后,调用SystemServiceManager的startBootPhase函数,
于是所有的服务都可以进一步完成这个阶段可以进行的初始化工作。
通过这种方式,每个服务的初始化过程可以按阶段分为好几个部分,增加了不同阶段的初始化工作的清晰度;
同时,每个阶段调用startBootPhase函数,就像一种同步机制一样,让所有服务的初始化进程保持一致的步调。
我们按照先后顺序,看看每个阶段对应的代码:
在SystemServer的startBootstrapServices方法中:
private void startBootstrapServices() {
..............
// We need the default display before we can initialize the package manager.
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
..............
}
在SystemServer的startOtherService方法中:
private void startOtherServices() {
................
// Needed by DevicePolicyManager for initialization
mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
.................
mActivityManagerService.systemReady(new Runnable() {
@Override
public void run() {
............
mSystemServiceManager.startBootPhase(
SystemService.PHASE_ACTIVITY_MANAGER_READY);
............
mSystemServiceManager.startBootPhase(
SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
................
}
});
}
在ActivityManagerService的finishBooting函数中:
final void finishBooting() {
..........
// Let system services know.
mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
..........
}
需要注意的是,不是每个服务都需要将初始化过程拆解成不同的部分,按需进行对应的实现即可。
2、BatteryService的onBootPhase
有了以上的知识,我们回过头来看一下BatteryService的onBootPhase函数:
public void onBootPhase(int phase) {
//BatteryService只需要在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();
}
}
}
从上面的代码可以看出,BatteryService的onBootPhase函数主要是注册一个监听器,检测低电量警告的电量值是否改变,然后调用updateBatteryWarningLevelLocked函数。
接下来,我们就一起看看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);
}
可以看出updateBatteryWarningLevelLocked函数主要关注低电提醒相关的变量更新,然后将剩余的工作交给processValuesLocked处理。
三、processValuesLocked主要功能
我们跟进一下processValuesLocked函数:
//force表示是否强制更新信息
//当force为false时,只有新旧信息不一致才更新
private void processValuesLocked(boolean force) {
...........
//判断当前电量是否危险;mBatteryProps由电源属性服务提供
mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
//以下是得到充电的类型
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;
}
..............
// Let the battery stats keep track of the current level.
try {
//将信息递交给电源统计服务,我们介绍BatteryStatsService时,再分析该函数
mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter);
} catch (RemoteException e) {
// Should never happen.
}
//电池电量低(batteryLevel==0)且未充电时,拉起关机对话框
shutdownIfNoPowerLocked();
//电池温度过高(默认为68C),拉起关机对话框
shutdownIfOverTempLocked();
//强制更新,或电源相关属性发生变化时,进行对应操作
//这段代码真的是没法不吐槽,Google难道不能重写一下BatteryProperties的equals方法
//Effective Java
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)) {
//充电状态发生变化(不关注充电的方式,即usb变为AC之类的,只是关注充电变为未充电等事件)
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;
}
}
//发送广播ACTION_BATTERY_CHANGED,内含电源当前的全部信息
sendIntentLocked();
//单独发送一些广播信息:
//通知进入充电状态,或离开充电状态
//通知电源进入低电模式,或离开低电模式
..............
// Update the battery LED
// 根据电源的电量和状态,改变LED灯的颜色
mLed.updateLightsLocked();
// This needs to be done after sendIntent() so that we get the lastest battery stats.
if (logOutlier && dischargeDuration != 0) {
//利用BatteryInfoService记录耗电情况的dump文件
logOutlierLocked(dischargeDuration);
}
//更新本地变量
....................
}
}
这一部分代码其实没什么太大的难度,就是写的比较繁琐。
我们还是画个图整理一下:
总结
从BatteryService整个代码结构来看,我们大致了解到BatterySerivce负责与native层通信,更新fwk中维护的电源信息。
BatteryService既通过广播的方式将信息发送给观察者,也提供了接口供外界调用。
同时,BatteryService提供的信息,应该是BatteryStatsService统计的重要依据。