【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完成 ... }
(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使用了不止一種計量工具。
由上圖可知
下面先從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。該函數用于添加一次歷史記錄。
|
新聞熱點
疑難解答