您的位置:首页 > 其它

BatteryStatsService分析(系统各模块和应用用电情况采集的分析)

2017-02-05 15:38 811 查看
BatteryService和系统中的供电系统交互,通过它可获取电池状态等信息。 而BatteryStatsService用于统计系统用电量的情况。 BSS较复杂,因为android对系统耗电量进行详细统计,统计量复杂。另外,电量统计大多采用被动通知的方式(即需要其他服务主动调用BSS提供的noteXXXOn()接口),这种实现方法加重了其他服务的负担】

【附注:setting中和电量相关的文件在android源码的packages\apps\Settings\src\com\android\settings\fuelgauge\目录中】

【本文可结合之前博文BatteryService部分了解底层数据上报(其中BSS和BatteryService交互部分在processValuesLocked()中)http://blog.csdn.net/ossoom/article/details/52587682

BatteryStatsService简称BSS,主要功能是收集系统中各模块和应用进程用电情况。抽象地说,BSS就是一块“电表”,不过这块“电表”不只是显示总的耗电量,而是分门别类地显示电量。

和其他服务不太一样的是,BSS的创建和注册是在ActivityManagerService中进行的。

首先

SystemServer.java(frameworks\base\services\java\com\android\server\SystemServer.java)中 会start services, 调用startBootstrapServices();

startBootstrapServices()函数实现中获取ActivityManagerService服务

startBootstrapServices()
{
...
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
...
}


在ActivityManagerService构造函数中会创建BatteryStatsService对象

public ActivityManagerService(Context systemContext) {
...
mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
...
}


在ActivityManagerService.java中start()函数中

private void start() {
...
mBatteryStatsService.publish(mContext);     //将BSS服务注册到ServiceManager中
...
}


下面看BSS构造函数

其实BSS只是一个壳,具体实现是由BatteryStatsImpl(后面简称BSImpl)完成。

BatteryStatsService(File systemDir, Handler handler) {
...
mStats = new BatteryStatsImpl(systemDir, handler, mHandler, this);      //功能由BSImpl完成
...
}




由上图可知BSS通过成员变量mStats指向一个BSImpl类型的对象。

BatteryStatsImpl实际上又是从BatteryStats类的派生, 而重要的是BatteryStats又实现了Parcelable接口,由此可知,BSImpl对象的信息可以写到Parcel包中,从而可通过Binder在进程间传递。实际上,在Android手机的设置中查到的用电信息就是来自BSImpl的。

(frameworks\base\services\core\java\com\android\server\am\BatteryStatsService.java)

public final class BatteryStatsService extends IBatteryStats.Stub
implements PowerManagerInternal.LowPowerModeListener,
BatteryStatsImpl.PlatformIdleStateCallback {
static final String TAG = "BatteryStatsService";
...
final BatteryStatsImpl mStats;
...
}


BatteryStatsImpl实际上是BatteryStats的派生类,

public class BatteryStatsImpl extends BatteryStats {
...
}


而BatteryStats又实现了Parcelable接口,(frameworks\base\core\java\android\os\BatteryStats.java)

public abstract class BatteryStats implements Parcelable {
...
}


BSS的getStatistics成员函数提供了查询系统用电信息的接口,该函数如下,

public byte[] getStatistics() {
mContext.enforceCallingPermission(
android.Manifest.permission.BATTERY_STATS, null);//检查调用进程是否有BATTERY_STATS权限
//Slog.i("foo", "SENDING BATTERY INFO:");
//mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
Parcel out = Parcel.obtain();
updateExternalStatsSync("get-stats", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
synchronized (mStats) {
mStats.writeToParcel(out, 0);   //将BSImpl信息写到数据包中
}
byte[] data = out.marshall();   //序列化为一个buffer,然后通过binder传递
out.recycle();
return data;
}


由此可以看出,电量统计的核心类是BSImpl,下面分析它

BSImpl功能是进行电量统计,那么是否存在计量工具呢?答案是肯定的,并且BSImpl使用了不止一种计量工具。



由上图可知

一共有两大类计量工具,Counter用于计数,Timer用于计时。

BSImpl实现了StopwatchTimer(秒表),SamplingCounter(抽样计数),SamplingTimer(抽样计时),Counter(计数器)等四个具体的计量工具。

BSImpl定义了一个Unplugged借口,plug和Unplugge
4000
d接口是为了满足BSImpl对各种情况下系统用电量统计的要求。

下面先从BSImpl的构造函数看起:

(frameworks\base\core\java\com\android\internal\os\BatteryStatsImpl.java)

public BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
ExternalStatsSync externalSync, PlatformIdleStateCallback cb) {
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"));
mExternalSync = externalSync;
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
mOnBatteryTimeBase);
}
mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase);
mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
mOnBatteryTimeBase);
mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -11, null,
mOnBatteryTimeBase);
mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null, mOnBatteryTimeBase);
mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase);
mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i, null,
mOnBatteryTimeBase);
}
mPhoneSignalScanningTimer = new StopwatchTimer(mClocks, null, -200+1, null,
mOnBatteryTimeBase);
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClocks, null, -300-i, null,
mOnBatteryTimeBase);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
}
mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, NUM_WIFI_TX_LEVELS);
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
ModemActivityInfo.TX_POWER_LEVELS);

mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null, mOnBatteryTimeBase);
mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
mOnBatteryTimeBase);
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase);
mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_WIFI_STATES; i++) {
mWifiStateTimer[i] = new StopwatchTimer(mClocks, null, -600-i, null,
mOnBatteryTimeBase);
}
for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
mWifiSupplStateTimer[i] = new StopwatchTimer(mClocks, null, -700-i, null,
mOnBatteryTimeBase);
}
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i, null,
mOnBatteryTimeBase);
}
mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase);
mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase);
mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryScreenOffTimeBase);
mDischargeCounter = 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;
}


上面代码变量较多,了解即可。

都是构造StopwatchTimer。接着了解下StopwatchTimer和startRunningLocked函数

其他应用需要调用用电统计时,会调用BatteryStatsService.java中的noteXXXOn(),

例如notePhoneOn(),会调用BSImpl的notePhoneOnLocked(),其中mPhoneOnTimer即为StopwatchTimer,StopwatchTimer再调用startRunningLocked

public void notePhoneOn() {
enforceCallingPermission();
synchronized (mStats) {
mStats.notePhoneOnLocked();
}
}


public void notePhoneOnLocked() {
if (!mPhoneOn) {
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
mHistoryCur.states2 |= HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
mPhoneOn = true;
mPhoneOnTimer.startRunningLocked(elapsedRealtime);
}
}


public void startRunningLocked(long elapsedRealtimeMs) {
if (mNesting++ == 0) {
final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
mUpdateTime = batteryRealtime;
if (mTimerPool != null) {
// Accumulate time to all currently active timers before adding
// this new one to the pool.
refreshTimersLocked(batteryRealtime, mTimerPool, null);
// Add this timer to the active pool
mTimerPool.add(this);
}
// Increment the count
mCount++;
mAcquireTime = mTotalTime;
if (DEBUG && mType < 0) {
Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTime
+ " mTotalTime=" + mTotalTime + " mCount=" + mCount
+ " mAcquireTime=" + mAcquireTime);
}
}
}


启动秒表调用startRunningLocked,停止秒表调用stopRunningLocked。

前面提到的 BSS和BatteryService交互部分在processValuesLocked()中,

BatteryService.java中

private void processValuesLocked(boolean force) {
...
// Let the battery stats keep track of the current level.
try {
mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter);
} catch (RemoteException e) {
// Should never happen.
}

...
}


BatteryService其中调用BSS接口setBatteryState,而BSS的工作是由BSImpl来完成。BSImpl的startRunningLocked如下,

public void startRunningLocked(long elapsedRealtimeMs) {
if (mNesting++ == 0) {
final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
mUpdateTime = batteryRealtime;
if (mTimerPool != null) {
// Accumulate time to all currently active timers before adding
// this new one to the pool.
refreshTimersLocked(batteryRealtime, mTimerPool, null);
// Add this timer to the active pool
mTimerPool.add(this);
}
// Increment the count
mCount++;
mAcquireTime = mTotalTime;

if (DEBUG && mType < 0) {
Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTime
+ " mTotalTime=" + mTotalTime + " mCount=" + mCount
+ " mAcquireTime=" + mAcquireTime);
}
}
}


其实现判断当前供电状态是否变化,由OnBattery和mOnBattery进行比较决定。OnBattery记录当前是否为电池供电,mOnBattery为上次调用该函数时得到的判断值。

如果供电状态变化(其实就是一次插拔USB过程),则调用setOnBatteryLocked函数。若供电状态未变化,则需要判断电池信息是否发生变化,如电量和电压等。若变化,则调用addHistoryRecordLocked。该函数用于添加一次历史记录。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  BatterySta