赞
踩
Android 中关于耗电的统计一般是关于功耗分析的重要信息,Bettery-historian工具也是依托于解析BatteryStats 的dump 信息来提供界面直观分析,并且电池电量耗费的源头实在太多,基本Android 设备上任何一个活动都会引起电池电量的消耗,Android 在统计电量上也在不断完善,不断的在更新,具体化耗电详情。耗电名单在主要记录在BatterySipper里面,虽然在源码中他并没有集成在service 端,实在frameworks/base/core 下,但是谷歌开放sdk 中并没有公开电量统计的API 或者文档,但是并不代表没有,因为安全中心->省电优化→耗电排行 中就是通过app 能显示出耗电详情排行,所以我们将从这个入口开始分析Android 是如何记录设备电池的耗电详情信息的
由于系统中形形色色,所有的活动都会耗电,所以BatteryStats服务也是相当的复杂,所以首先我们需要摸清楚该服务的架构设计,以此来切入分析,我们首先来看一下BatteryStats 电池电量统计服务的架构图:
从图中我们可以看出整个电池管理服务的大概架构是如何的。那么这里面的每个类所担当的角色是怎样的呢?
BatteryStats: 这是一个抽象类,在我看来也算是整个电池信息统计服务的架构核心类,这里面定义了很多内部类:
Timer (记录时间信息状态);
ControllerActivityCounter(统计无线电数据传输,接受,以及idle状态);
Counter(记录计数信息的状态。如Alarm,Wakelock 等统计计数);
LongCounter(针对长期持续的活动统计,如屏幕亮灭,插拔充电等);
UID(针对App Uid 统计信息):
Uid由于是统计app 的耗电量,所以其还定义内部类:Wakelock (统计应用申请Wakelock 的情况),Sensor(统计应用使用sensor的情况),Proc(统计应用进程的信息),Pkg(统计应用包的信息,内部类Serv(统计该包名下服务的信息));
BatteryStatsImpl :为整个电池信息统计服务的计算核心类,虽然该类是在frameworks/base 端(并非放在services 端),但是从分析该服务源码能看出来,BatteryStatsServices 虽然是system_server 中一个服务,但是实际上该服务只是一个空壳(后面即将讲到),所有的电池耗电信息相关计算都是在BatteryStatsImpl 中实现的,该类继承自BatteryStats,并且实现了BatteryStats 中定义的所有的抽象类以及计算方法。
BatteryStatsHelper : 是BatteryStatsImpl 计算的一个辅助类,主要是提供给应用(比如设置,安全中心,360等)来展示耗电信息,这里面的定义了软件类和硬件耗电信息的计算类***PowerCalculator,并且提供获取耗电信息列表方法getUsageList()
BatterySipper: 英文解释为:电池吸管,这个类的对象才是每个耗电的实体项统计,在安全中心中耗电排行中,每一个耗电项都是一个BatterySipper对象。
以上对BatteryStats 服务中各个相关的类以及其作用做了一个大致的解释,那么其服务是怎么统计的呢,我们继续来一步一步剖析源码
BatteryStats 服务是在AMS 的构造函数中启动的
ActivityManagerService 构造函数中:
mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler);
mBatteryStatsService.getActiveStatistics().readLocked();
mBatteryStatsService.scheduleWriteToDisk();
mOnBattery = DEBUG_POWER ? true
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);
在AMS 构造函数中创建BatteryStatsService 的对象,并且开始读取统计文件里已经保存的统计信息。并且开始异步 的去记录信息,设置Callback
BatteryStatsService初始化:
BatteryStatsService(Context context, File systemDir, Handler handler) {
// BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
mContext = context;
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;
}
};
mStats = new BatteryStatsImpl(systemDir, handler, this, mUserManagerUserInfoProvider);
mWorker = new BatteryExternalStatsWorker(context, mStats);
mStats.setExternalStatsSyncLocked(mWorker);
mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout) * 1000L); //设置RadioScanningTimeout 值(0 * 1000L)
mStats.setPowerProfileLocked(new PowerProfile(context)); //设置PowerProfile(电池基本参数信息)。
}
public void publish() {
ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
}
1.在构造函数中,使用BatteryExternalStatsWorker 内部统计集合来收集电池耗电信息了(8.1之前的是创建一个新的线程batterystats-sync用来记录电池电量信息) ,从AMS中传过来的mHandler(ActivityManager线程)给BatteryStatsImpl 用于记录wakelock,PowerChange,charging 等信息。设置外部硬件统计对象mWorker
2.在AMS 中onStart()函数中调用BatteryStatsService.publish() ,将batterystats 服务注册到system_server 进程中。可以看到在publish 中逻辑:3.将batterystats 服务添加到ServiceManager 中。
我们这里需要重点关注BatteryStatsImpl 的初始化,因为从以上分析来看虽然电量统计服务是system_server进程中的一个服务,但是其主要只是一个proxy 的作用,整体的计算工作还是交给BatteryStatsImpl 去做的,所以BatteryStatsImpl 才是整个耗电信息的计算核心类。
BatteryStatsImpl 构造函数
private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
PlatformIdleStateCallback cb,
UserInfoProvider userInfoProvider) {
init(clocks);
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());
mStartCount++;
mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
........
initDischarge();
clearHistoryLocked();
updateDailyDeadlineLocked();
mPlatformIdleStateCallback = cb;
mUserInfoProvider = userInfoProvider;
}
构造函数大概干了几件事:
1.传入的mClocks 为AMS 启动时候创建的SystemClock。
2. 在/data/system/ 下创建 batterystats.bin 文件和其备份文
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。