首页 > 学院 > 开发设计 > 正文

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

2019-11-09 18:27:51
字体:
来源:转载
供稿:网友

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和Unplugged接口是为了满足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。该函数用于添加一次历史记录。


上一篇:aqicn.org的秘密

下一篇:Linux : CPU Idle

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表