概述
BatteryStatsService负责电池信息的收集,以及各个部分耗电量的统计,它继承于IBatteryStats.Stub,因此可以通过Binder机制和其他组件进行交互。在上一节中分析过BatteryService,它负责监听从底层传上来的电量信息,当有数据时,BatteryService会将数据传给BatteryStatsService,BatteryStatsService中所有功能最终又委托给BatteryStatsImpl去处理。
和BatteryService不同的是,BatteryStatsService并非继承于SystemService,因此不是一个SystemService类,不具有SystemService的生命周期方法。
BatteryStatsService的启动、初始化和发布都是在AMS中进行,当SystemServer启动AMS后,AMS在其构造方法中启动了BSS,同时AMS在后续调用中进行了BSS的注册,下面一一进行分析!
1.实例化
在AMS中,获取BatteryStatsService实例方式如下:
public ActivityManagerService(Context systemContext) {
......
// TODO: Move creation of battery stats service outside of activity manager service.
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
//创建/data/system目录
systemDir.mkdirs();
//实例化BatteryStatsService
mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler);
//从/data/system/batterystas-daily.xml中读取信息
mBatteryStatsService.getActiveStatistics().readLocked();
//使用ExecutorService线程池将BatteryStatsImpl中统计的电池信息写入硬盘中
mBatteryStatsService.scheduleWriteToDisk();
mOnBattery = DEBUG_POWER ? true
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
//设置BatteryCallback接口
mBatteryStatsService.getActiveStatistics().setCallback(this);
}
setCallback()方法设置了BatteryCallback回调,该接口如下:
public interface BatteryCallback {
public void batteryNeedsCpuUpdate();
public void batteryPowerChanged(boolean onBattery);
public void batterySendBroadcast(Intent intent);
}
该接口负责当对应条件符合时,在Handler中调用此方法通知AMS,从而在AMS中进行回调这三个方法在AMS中的实现.
1.1.BatteryStatsService.Constructor()
按照上面的调用顺序,我们先看BatteryStatsService的构造方法:
BatteryStatsService(Context context, File systemDir, Handler handler) {
//这里传入来自AMS中的Handler,并通过handler.getLooper()获取到AMS中的Looper
mContext = context;
//BSI中一个内部类,可以通过UserManagerInternal获取UserId
mUserManagerUserInfoProvider = new BatteryStatsImpl.UserInfoProvider() {
private UserManagerInternal umi;
@Override
public int[] getUserIds() {
if (umi == null) {
umi = LocalServices.getService(UserManagerInternal.class);
}
return (umi != null) ? umi.getUserIds() : null;
}
};
//实例化BatteryStatsImpl
mStats = new BatteryStatsImpl(systemDir, handler, this, mUserManagerUserInfoProvider);
//BatteryExternalStatsWorker负责在专用线程上同步BT/WIFI等外部电池信息到BSI中
mWorker = new BatteryExternalStatsWorker(context, mStats);
mStats.setExternalStatsSyncLocked(mWorker);
//设置扫描信号超时时间
mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
//设置电源配置文件
mStats.setPowerProfileLocked(new PowerProfile(context));
}
在BatteryStatsService的构造方法中,首先实例化了BatteryStatsImpl(后简称BSI)对象和BatteryExternalStatsWorker对象,BatteryStatsImpl是BSS的委托类,BSS的所有操作都交给它去处理;BatteryExternalStatsWorker负责在专用线程上拉取如蓝牙芯片、WIFI控制器、Modem控制器等外部设备电源使用信息。
由于BatteryStatsService中所有任务都交给BatteryStatsImpl去处理,所以继续从BatteryStatsImpl的构造方法进入分析,其构造方法如下:
/**
* @param clocks 包括系统的uptime时长的elapsedrealtime时长
* @param systemDir AMS中传入的/data/system
* @param handler AMS中传入的handler
* @param cb 用于读取低电量状态的接口,BSS实现了该接口
* @param userInfoProvider 通过UserManagerService获取UserId,BSS中实例化了该接口的匿名类
*/
private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
PlatformIdleStateCallback cb,
UserInfoProvider userInfoProvider) {
init(clocks);
//在/data/system目录下创建文件
if (systemDir != null) {
mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
new File(systemDir, "batterystats.bin.tmp"));
} else {
mFile = null;
}
mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml"));
mHandler = new MyHandler(handler.getLooper());
//创建一系列的StopwatchTimer和LongSamplingCounter,并将这些对象全部
//添加到TimeBaseObserver集合中
mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null,
mOnBatteryTimeBase);
mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null,
mOnBatteryTimeBase);
.............
mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_WIFI_TX_LEVELS);
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
//创建一系列的LongSamplingCounter
mMobileRadioActiveAdjustedTime = new
LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownTime = new
LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownCount = new
LongSamplingCounter(mOnBatteryTimeBase);
mOnBattery = mOnBatteryInternal = false;
long uptime = mClocks.uptimeMillis() * 1000;
long realtime = mClocks.elapsedRealtime() * 1000;
//初始化一些计算电量相关时间值
initTimes(uptime, realtime);
mStartPlatformVersion = mEndPlatformVersion = Build.ID;
mDischargeStartLevel = 0;
mDischargeUnplugLevel = 0;
mDischargePlugLevel = -1;
mDischargeCurrentLevel = 0;
mCurrentBatteryLevel = 0;
//初始化放电时参数
initDischarge();
//清除历史信息
clearHistoryLocked();
//更新下次记录截止时间
updateDailyDeadlineLocked();
mPlatformIdleStateCallback = cb;
mUserInfoProvider = userInfoProvider;
}
在BatteryStatsImpl构造函数中,使用AtomicFile类创建了一个batterystats-daily.xml
文件,BatteryStatsImpl每次统计的电量都会写在这个文件中,AtmoicFile是一个进行File操作的帮助类,利用备份文件的操作对文件进行原子操作;此外还实例化了负责记录各个组建时间信息的StopwatchTimer
对象和LongSamlingCounter
对象。
BatteryStatsImpl的构造函数执行完毕。当实例化BSI完毕后,BSS构造方法中剩余内容就是给BSI设置相关的属性值,在注释中已经给出。不再去分析了。
2.发布BatteryStatsService
当AMS实例化完毕BSS,且BSS实例化完毕BSI后,整个实例化过程完毕了,现在回到AMS中,来看看剩余的操作:
//AMS的start()中发布了BSS
private void start() {
......
mBatteryStatsService.publish();
......
}
//BSS中:
public void publish() {
ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
}
这里通过ServiceManager.addService()
对BSS进行了发布,这样其他应用可以通过BatteryStats.SERVICE_NAME
获取一个BSS的代理对象(IBatteryStats.Stub的代理对象更加确切一点).
这里需要额外说明一点,对于继承于SystemService的系统服务(如PowerManagerService、BatteryService等),提供了publishBinderService()
方法进行发布,其内部也是通过ServiceManager.addService()
实现。
AMS中执行完start()后,还有一处和BSS相关:
public void initPowerManagement() {
......
mBatteryStatsService.initPowerManagement();
......
}
在SystemServer启动AMS后,在startBootStrapService()
方法中调用了AMS的initPowerManagerment()
,初始化一些和PM相关的东西,AMS又调用了BSS的initPowerManagerment();来看看这个方法中做了什么:
public void initPowerManagement() {
mStackSupervisor.initPowerManagement();
mBatteryStatsService.initPowerManagement();//调用BSS中的initPowerManager
//获取PMS本地对象
mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class);
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
//准备申请wakelock锁
mVoiceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*voice*");
//wakeloc类型设置为非计数锁,默认计数锁
mVoiceWakeLock.setReferenceCounted(false);
}
再看看BSS中的initPowerManagement()
:
public void initPowerManagement() {
//获取PMS本地服务对象
final PowerManagerInternal powerMgr = LocalServices.getService(PowerManagerInternal.class);
//注册低电量监听
powerMgr.registerLowPowerModeObserver(this);
synchronized (mStats) {
//省电模式相关
mStats.notePowerSaveModeLocked(
powerMgr.getLowPowerState(ServiceType.BATTERY_STATS)
.batterySaverEnabled);
}
//开启一个线程
(new WakeupReasonThread()).start();
}
在这个方法中,首先会获取PowerManagerService
的本地服务对象。PowerManagerService.LocalService
继承自PowerManagerInternal,并且在PMS中注册本地服务时将PowerManagerInternal.class作为参数,因此这里实际上得到的是PowerManagerService.LocalService对象。
获取到PMS.LocalService后,使用PMS.LocalService对象注册低电量时的监听接口PowerManagerInternal.LowPowerModeListener
。当PMS中有低电量相关逻辑触发时,回调BSS中的实现方法。该接口定义如下:
在PowerManagerInternal中:
public interface LowPowerModeListener {
int getServiceType();
void onLowPowerModeChanged(PowerSaveState state);
}
BatteryStatsService实现了该接口:
@Override
public int getServiceType() {
return ServiceType.BATTERY_STATS;
}
@Override
public void onLowPowerModeChanged(PowerSaveState result) {
synchronized (mStats) {
mStats.notePowerSaveModeLocked(result.batterySaverEnabled);
}
}
PowerManagerService.LocalService中注册如下:
@Override
public void registerLowPowerModeObserver(LowPowerModeListener listener) {
synchronized (mLock) {
mLowPowerModeListeners.add(listener);
}
}
此时,BSS的启动流程分析完毕。
BSS.setBatteryState()
由于BSS负责电池信息的收集、耗电量的统计,因此提供了许多的noteXXX()
方法进行不同模块的统计,而这些方法或许只有在实际场景中使用时才会有更加深刻的理解,因此,这些方法不再进行分析(其实搞不懂),接下来分析BSS的数据源方法——setBatteryState()
.
该方法的调用在BatteryService中,这里直接看其方法体:
@Override
public void setBatteryState(final int status, final int health, final int plugType,
final int level, final int temp, final int volt, final int chargeUAh,
final int chargeFullUAh) {
enforceCallingPermission();
// BatteryService calls us here and we may update external state. It would be wrong
// to block such a low level service like BatteryService on external stats like WiFi.
mWorker.scheduleRunnable(() -> {
synchronized (mStats) {
final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
//如果没有发生变化,则直接更新同步
if (mStats.isOnBattery() == onBattery) {
// The battery state has not changed, so we don't need to sync external
// stats immediately.
mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
chargeUAh, chargeFullUAh);
return;
}
}
// Sync external stats first as the battery has changed states. If we don't sync
// before changing the state, we may not collect the relevant data later.
// Order here is guaranteed since we're scheduling from the same thread and we are
// using a single threaded executor.
//如果onBattery改变,则首选需要同步外部设备电池信息,然后才同步内部电池信息
mWorker.scheduleSync("battery-state", BatteryExternalStatsWorker.UPDATE_ALL);
mWorker.scheduleRunnable(() -> {
synchronized (mStats) {
mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
chargeUAh, chargeFullUAh);
}
});
});
}
这里使用了ExecutorService开启了一个异步线程处理任务,而这个任务就是在BatteryStatsImpl.setBatteryStateLocked()
,这个方法是统计电量信息的主要方法,详细分析将在电量充满时间计算中进行分析。