4、电量计算
Android中计算耗电量离不开BatteryStatsHelper这个类,它主要用于计算所有应用和服务的用电量。
示例:在Settings设置中显示电量相关信息,就是通过调用BatteryStatsHelper的接口来实现的。
从BatteryStatsHelper类的注释来看,当需要使用BatteryStatsHelper时: 必须在Activity或者Fragment初始化时,在onAttach(Fragment)或onCreate(Activity)中立即调用BatteryStatsHelper的create(); 同时在activity或者Fragment销毁时,在onDestroy()调用BatteryStatsHelper的destroy()。
4.1 用法示例
Settings中的BatteryStatsHelper的使用方式。
代码路径:/packages/apps/Settings/src/com/android/settings/fuelgauge/PowerUsageBase.java
(http://androidxref.com/8.0.0_r4/xref/packages/apps/Settings/src/com/android/settings/fuelgauge/PowerUsageBase.java)
41 protected BatteryStatsHelper mStatsHelper; 42 protected UserManager mUm; 43 private BatteryBroadcastReceiver mBatteryBroadcastReceiver; 44 45 @Override 46 public void onAttach(Activity activity) { 47 super.onAttach(activity); 48 mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE); 49 mStatsHelper = new BatteryStatsHelper(activity, true);//创建 50 } 51 52 @Override 53 public void onCreate(Bundle icicle) { 54 super.onCreate(icicle); 55 mStatsHelper.create(icicle);//初始化 56 setHasOptionsMenu(true); 57 58 mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext()); 59 mBatteryBroadcastReceiver.setBatteryChangedListener(() -> { 60 restartBatteryStatsLoader(); 61 }); 62 63 getLoaderManager().initLoader(0, icicle, this); 64 }
BatteryStatsHelper的构造函数比较简单,就是初始化一些变量。
代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java)
172 public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast, boolean wifiOnly) { 173 mContext = context; 174 mCollectBatteryBroadcast = collectBatteryBroadcast; 175 mWifiOnly = wifiOnly; 176 mPackageManager = context.getPackageManager(); 177 178 final Resources resources = context.getResources(); 179 mSystemPackageArray = resources.getStringArray( 180 com.android.internal.R.array.config_batteryPackageTypeSystem); 181 mServicepackageArray = resources.getStringArray( 182 com.android.internal.R.array.config_batteryPackageTypeService); 183 }
BatteryStatsHelper.create:
代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java)
275 public void create(Bundle icicle) { 276 if (icicle != null) { 277 mStats = sStatsXfer; 278 mBatteryBroadcast = sBatteryBroadcastXfer; 279 } 280 mBatteryInfo = IBatteryStats.Stub.asInterface( 281 ServiceManager.getService(BatteryStats.SERVICE_NAME));//获取BSS的服务端代理 282 mPowerProfile = new PowerProfile(mContext);//读取PowerProfile 283 }
PowerProfile在前文分析BSImpl的构造函数时已经提到过了,主要记录不同硬件模块在不同状态下的耗电量。更新用电量时主要依赖于BatteryStatsHelper的refreshStats函数
4.2 BatteryStatsHelper的refreshStats函数
代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java)
348 public void refreshStats(int statsType, SparseArray<UserHandle> asUsers, long rawRealtimeUs, 349 long rawUptimeUs) { 350 // Initialize mStats if necessary. 351 getStats();//确保获取了BSImp的统计信息 352 //初始化基本的状态 353 mMaxPower = 0; 354 mMaxRealPower = 0; 355 mComputedPower = 0; 356 mTotalPower = 0; 357 //重置相关的列表 358 mUsageList.clear(); 359 mWifiSippers.clear(); 360 mBluetoothSippers.clear(); 361 mUserSippers.clear(); 362 mMobilemsppList.clear(); 363 364 if (mStats == null) { 365 return; 366 } 367 //初始化相关的电量计算工具,各种计算工具都继承自PowerCalculator类,用于计算不同模块的耗电量 368 if (mCpuPowerCalculator == null) { 369 mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile); 370 } 371 mCpuPowerCalculator.reset(); ............................................ 423 //利用BSImpl中的信息,初始化一些变量 424 mStatsType = statsType; 425 mRawUptimeUs = rawUptimeUs; 426 mRawRealtimeUs = rawRealtimeUs; 427 mBatteryUptimeUs = mStats.getBatteryUptime(rawUptimeUs); 428 mBatteryRealtimeUs = mStats.getBatteryRealtime(rawRealtimeUs); 429 mTypeBatteryUptimeUs = mStats.computeBatteryUptime(rawUptimeUs, mStatsType); 430 mTypeBatteryRealtimeUs = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType); 431 mBatteryTimeRemainingUs = mStats.computeBatteryTimeRemaining(rawRealtimeUs); 432 mChargeTimeRemainingUs = mStats.computeChargeTimeRemaining(rawRealtimeUs); ....................................................... 446 447 processAppUsage(asUsers);//1、计算各个应用的耗电量 448 .................................................... 474 475 processMiscUsage();//计算各个模块,除去APP之外消耗的电量 476 477 Collections.sort(mUsageList);//按照耗电量排序 478 479 // At this point, we've sorted the list so we are guaranteed the max values are at the top. 480 // We have only added real powers so far. 481 if (!mUsageList.isEmpty()) {//计算耗电量最大的应用,及整个机器耗电量之和 482 mMaxRealPower = mMaxPower = mUsageList.get(0).totalPowerMah; 483 final int usageListCount = mUsageList.size(); 484 for (int i = 0; i < usageListCount; i++) { 485 mComputedPower += mUsageList.get(i).totalPowerMah; 486 } 487 } 488 ................................................. 494 mTotalPower = mComputedPower; 495 if (mStats.getLowDischargeAmountSinceCharge() > 1) {//计算耗电量最大的应用,及整个机器耗电量之和 496 if (mMinDrainedPower > mComputedPower) {//mMinDrainedPower是统计出的电池的实际消耗电量,电池耗电量大于统计的总耗电量 497 double amount = mMinDrainedPower - mComputedPower;//计算差异 498 mTotalPower = mMinDrainedPower;//更新耗电量 499 BatterySipper bs = new BatterySipper(DrainType.UNACCOUNTED, null, amount);//利用差异量,构造一个耗电对象,type为UNACCOUNTED 500 501 // Insert the BatterySipper in its sorted position. 502 int index = Collections.binarySearch(mUsageList, bs);//按大小插入表中,同时更新最大耗电量 503 if (index < 0) { 504 index = -(index + 1); 505 } 506 mUsageList.add(index, bs); 507 mMaxPower = Math.max(mMaxPower, amount); 508 } else if (mMaxDrainedPower < mComputedPower) {//电池耗电量小于统计的总耗电量 509 double amount = mComputedPower - mMaxDrainedPower; 510 511 // Insert the BatterySipper in its sorted position. 512 BatterySipper bs = new BatterySipper(DrainType.OVERCOUNTED, null, amount);//同样插入一个耗电对象,type为OVERCOUNTED 513 int index = Collections.binarySearch(mUsageList, bs); 514 if (index < 0) { 515 index = -(index + 1); 516 } 517 mUsageList.add(index, bs); 518 mMaxPower = Math.max(mMaxPower, amount); 519 } 520 } .................................................... 536 }
refreshStats函数的主要作用就是重新统计终端的耗电量,然后更新自身的存储变量。 进行更新后,创建BatteryStatsHelper的类,就可以调用BatteryStatsHelper的getTotalPower、getUsageList等接口,获取终端耗电信息
4.2.1 processAppUsage
refreshStats函数中比较重要的函数是processAppUsage:
代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java)
538 private void processAppUsage(SparseArray<UserHandle> asUsers) { 539 final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null); 540 mStatsPeriod = mTypeBatteryRealtimeUs; 541 542 BatterySipper osSipper = null; 543 final SparseArray<? extends Uid> uidStats = mStats.getUidStats();//得到BSImpl中的BatteryStatsImpl.Uid对象组成的列表,统计每个uid的耗电信息(主要是时间) 544 final int NU = uidStats.size(); 545 for (int iu = 0; iu < NU; iu++) {//循环计算每个应用的耗电量 546 final Uid u = uidStats.valueAt(iu); 547 final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0); 548 549 mCpuPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//得到该app的占用CPU消耗的电量 550 mWakelockPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//得到该app的持有WakeLock消耗的电量 551 mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, 552 mStatsType);//得到该app的使用射频消耗的电量 553 mWifiPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType); 554 mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, 555 mStatsType); 556 mSensorPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType); 557 mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType); 558 mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, 559 mStatsType); 560 561 final double totalPower = app.sumPower();//计算这个应用耗电量的总和 562 if (DEBUG && totalPower != 0) { 563 Log.d(TAG, String.format("UID %d: total power=%s", u.getUid(), 564 makemAh(totalPower))); 565 } 566 567 // Add the app to the list if it is consuming power. 568 if (totalPower != 0 || u.getUid() == 0) { 569 // 570 // Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list. 571 // 572 final int uid = app.getUid();//根据应用的类型,将应用耗电量信息添加到对应的列表 573 final int userId = UserHandle.getUserId(uid); 574 if (uid == Process.WIFI_UID) { 575 mWifiSippers.add(app); 576 } else if (uid == Process.BLUETOOTH_UID) { 577 mBluetoothSippers.add(app); 578 } else if (!forAllUsers && asUsers.get(userId) == null 579 && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) { 580 // We are told to just report this user's apps as one large entry. 581 List<BatterySipper> list = mUserSippers.get(userId);//如果该应用是单独某个用户下的应用则添加的userSippers列表 582 if (list == null) { 583 list = new ArrayList<>(); 584 mUserSippers.put(userId, list); 585 } 586 list.add(app); 587 } else { 588 mUsageList.add(app);//否则直接添加到普通的应用列表 589 } 590 591 if (uid == 0) { 592 osSipper = app;//android系统 593 } 594 } 595 } 596 597 if (osSipper != null) {// 计算os消耗的电量,除去app消耗 598 // The device has probably been awake for longer than the screen on 599 // time and application wake lock time would account for. Assign 600 // this remainder to the OS, if possible. 601 mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtimeUs, 602 mRawUptimeUs, mStatsType); 603 osSipper.sumPower(); 604 } 605 }
4.2.2 processMiscUsage
refreshStats中另一个比较重要的函数processMiscUsage:
代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java)
737 private void processMiscUsage() { 738 addUserUsage(); 739 addPhoneUsage(); 740 addScreenUsage(); 741 addWiFiUsage(); 742 addBluetoothUsage(); 743 addMemoryUsage(); 744 addIdleUsage(); // Not including cellular idle power 745 // Don't compute radio usage if it's a wifi-only device 746 if (!mWifiOnly) { 747 addRadioUsage(); 748 } 749 }
processMiscUsage中使用的几个函数,也是用于计算工具统计每个模块的耗电量。 但与processAppUsage统计的侧重点不一样。
Android将一个模块的电量粗略分为两种。 一种是app在实际使用模块,引起的耗电量;一种是没有app调用,只要开启就会消耗的电量。 例如:WiFi只要开启,不论是否有app利用WiFi上网,WiFi都需要进行CSMA,因此会有基础的电量消耗。
4.2.3 计算方法举例
以数据业务相关的MobileRadioPowerCalculator为例,看看计算工具到底是如何工作的。
代码路径:/frameworks/base/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/MobileRadioPowerCalculator.java)
22public class MobileRadioPowerCalculator extends PowerCalculator {//从PowerProfile下,得到各种场景的单位耗电量 ............................................................. 52 public MobileRadioPowerCalculator(PowerProfile profile, BatteryStats stats) { 53 mPowerRadioOn = profile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE);//radio on时的单位耗电量 54 for (int i = 0; i < mPowerBins.length; i++) { //各种信号强度下的单位耗电量 55 mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i); 56 } 57 mPowerScan = profile.getAveragePower(PowerProfile.POWER_RADIO_SCANNING);//搜网时的单位耗电量 58 mStats = stats; 59 } 60 61 @Override 62 public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, 63 long rawUptimeUs, int statsType) { 64 // Add cost of mobile traffic. 65 app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA, 66 statsType);//得到APP利用mobile发送分组的数量 67 app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA, 68 statsType); 69 app.mobileActive = u.getMobileRadioActiveTime(statsType) / 1000;//得到APP在mobile active时的运行时间 70 app.mobileActiveCount = u.getMobileRadioActiveCount(statsType); 71 app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA, 72 statsType);//得到APP利用mobile发送字节的数量 73 app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA, 74 statsType); 75 76 if (app.mobileActive > 0) { 77 // We are tracking when the radio is up, so can use the active time to 78 // determine power use. 79 mTotalAppMobileActiveMs += app.mobileActive;//总体时间 80 app.mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000*60*60);//运行时间 * 单位耗电量 得到整体的耗电情况 81 } else { 82 // We are not tracking when the radio is up, so must approximate power use 83 // based on the number of packets. 84 app.mobileRadioPowerMah = (app.mobileRxPackets + app.mobileTxPackets) 85 * getMobilePowerPerPacket(rawRealtimeUs, statsType);//mobile处于active时,app并没有运行,利用整体的收发包数量得到耗电量 86 } 87 if (DEBUG && app.mobileRadioPowerMah != 0) { 88 Log.d(TAG, "UID " + u.getUid() + ": mobile packets " 89 + (app.mobileRxPackets + app.mobileTxPackets) 90 + " active time " + app.mobileActive 91 + " power=" + BatteryStatsHelper.makemAh(app.mobileRadioPowerMah)); 92 } 93 } 94 95 @Override 96 public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, 97 long rawUptimeUs, int statsType) { 98 double power = 0; 99 long signalTimeMs = 0; 100 long noCoverageTimeMs = 0; 101 for (int i = 0; i < mPowerBins.length; i++) { 102 long strengthTimeMs = stats.getPhoneSignalStrengthTime(i, rawRealtimeUs, statsType) 103 / 1000; 104 final double p = (strengthTimeMs * mPowerBins[i]) / (60*60*1000);//计算处于每个信号强度下的耗电量 105 if (DEBUG && p != 0) { 106 Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power=" 107 + BatteryStatsHelper.makemAh(p)); 108 } 109 power += p;//累加 110 signalTimeMs += strengthTimeMs;//整体的统计时间 111 if (i == 0) { 112 noCoverageTimeMs = strengthTimeMs;//无信号时间 113 } 114 } 115 116 final long scanningTimeMs = stats.getPhoneSignalScanningTime(rawRealtimeUs, statsType) 117 / 1000;//计算出搜网的耗电量 118 final double p = (scanningTimeMs * mPowerScan) / (60*60*1000); 119 if (DEBUG && p != 0) { 120 Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs 121 + " power=" + BatteryStatsHelper.makemAh(p)); 122 } 123 power += p; 124 long radioActiveTimeMs = mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;//计算出radio on,但app未使用时段的基础耗电量 125 long remainingActiveTimeMs = radioActiveTimeMs - mTotalAppMobileActiveMs; 126 if (remainingActiveTimeMs > 0) { 127 power += (mPowerRadioOn * remainingActiveTimeMs) / (1000*60*60); 128 } 129 130 if (power != 0) { //将计算的结果保存在app对应的BatterySipper中 131 if (signalTimeMs != 0) { 132 app.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs; 133 } 134 app.mobileActive = remainingActiveTimeMs; 135 app.mobileActiveCount = stats.getMobileRadioActiveUnknownCount(statsType); 136 app.mobileRadioPowerMah = power; 137 } 138 } 139 140 @Override 141 public void reset() { 142 mTotalAppMobileActiveMs = 0; 143 } 144 145 public void reset(BatteryStats stats) { 146 reset(); 147 mStats = stats; 148 } 149}
Android将一个模块的电量粗略分为两种。 一种是app在实际使用模块,引起的耗电量;一种是没有app调用,只要开启就会消耗的电量。 对于数据业务而言: app在进行实际的收发数据,那么这部分电量就是app引起的耗电量。终端维持一定的信号强度消耗的电量;搜网消耗的电量;打开数据开关,但没有数据收发时消耗的电量,统称为基础耗电量。
5、BSS的setBatteryState函数
代码路径:/frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java)
1030 public void setBatteryState(final int status, final int health, final int plugType, 1031 final int level, final int temp, final int volt, final int chargeUAh, 1032 final int chargeFullUAh) { 1033 enforceCallingPermission(); 1034 1035 // BatteryService calls us here and we may update external state. It would be wrong 1036 // to block such a low level service like BatteryService on external stats like WiFi. 1037 mHandler.post(new Runnable() { 1038 @Override 1039 public void run() { 1040 synchronized (mStats) {//判断是否充电 1041 final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE; 1042 if (mStats.isOnBattery() == onBattery) { 1043 // The battery state has not changed, so we don't need to sync external 1044 // stats immediately. 1045 mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt, 1046 chargeUAh, chargeFullUAh);//充电状态未改变,仅做记录 1047 return; 1048 } 1049 } 1050 1051 // Sync external stats first as the battery has changed states. If we don't sync 1052 // immediately here, we may not collect the relevant data later. 1053 updateExternalStatsSync("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);//充电状态改变,则先同步WIFI、BT等的信息 1054 synchronized (mStats) { 1055 mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt, 1056 chargeUAh, chargeFullUAh); 1057 } 1058 } 1059 }); 1060 }
实际的记录工作还是依赖于BSImpl的setBatteryStateLocked函数
代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java)
10553 public void setBatteryStateLocked(int status, int health, int plugType, int level, 10554 int temp, int volt, int chargeUAh, int chargeFullUAh) { 10555 // Temperature is encoded without the signed bit, so clamp any negative temperatures to 0. 10556 temp = Math.max(0, temp); 10557 10558 final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;//判断当前是否是电池供电(即是否没有插着充电器) 10559 final long uptime = mClocks.uptimeMillis(); 10560 final long elapsedRealtime = mClocks.elapsedRealtime(); 10561 if (!mHaveBatteryLevel) { 10562 mHaveBatteryLevel = true; 10563 // We start out assuming that the device is plugged in (not 10564 // on battery). If our first report is now that we are indeed 10565 // plugged in, then twiddle our state to correctly reflect that 10566 // since we won't be going through the full setOnBattery(). 10567 if (onBattery == mOnBattery) { 10568 if (onBattery) { 10569 mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; 10570 } else { 10571 mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; 10572 } 10573 } 10574 // Always start out assuming charging, that will be updated later. 10575 mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG; 10576 mHistoryCur.batteryStatus = (byte)status; 10577 mHistoryCur.batteryLevel = (byte)level; 10578 mHistoryCur.batteryChargeUAh = chargeUAh; 10579 mMaxChargeStepLevel = mMinDischargeStepLevel = 10580 mLastChargeStepLevel = mLastDischargeStepLevel = level; 10581 mLastChargingStateLevel = level; 10582 } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) { 10583 recordDailyStatsIfNeededLocked(level >= 100 && onBattery); 10584 } 10585 int oldStatus = mHistoryCur.batteryStatus; 10586 if (onBattery) {//如果是电池供电,则记录下当前的未充电的电量 10587 mDischargeCurrentLevel = level; 10588 if (!mRecordingHistory) { 10589 mRecordingHistory = true; 10590 startRecordingHistory(elapsedRealtime, uptime, true);//将当前的电池状态添加到历史记录 10591 } 10592 } else if (level < 96) {//充电但电量低于96%,同时没有记录过 10593 if (!mRecordingHistory) { 10594 mRecordingHistory = true; 10595 startRecordingHistory(elapsedRealtime, uptime, true); 10596 } 10597 } 10598 mCurrentBatteryLevel = level; 10599 if (mDischargePlugLevel < 0) { 10600 mDischargePlugLevel = level; 10601 } 10602 10603 if (onBattery != mOnBattery) {//充电状态发生改变,进行一些历史信息记录 10604 mHistoryCur.batteryLevel = (byte)level; 10605 mHistoryCur.batteryStatus = (byte)status; 10606 mHistoryCur.batteryHealth = (byte)health; 10607 mHistoryCur.batteryPlugType = (byte)plugType; 10608 mHistoryCur.batteryTemperature = (short)temp; 10609 mHistoryCur.batteryVoltage = (char)volt; 10610 if (chargeUAh < mHistoryCur.batteryChargeUAh) { 10611 // Only record discharges 10612 final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh; 10613 mDischargeCounter.addCountLocked(chargeDiff); 10614 mDischargeScreenOffCounter.addCountLocked(chargeDiff); 10615 } 10616 mHistoryCur.batteryChargeUAh = chargeUAh; 10617 setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level, chargeUAh);//setOnBatteryLocked执行充电状态发生变化的逻辑 10618 } else { 10619 boolean changed = false;//判断电池信息是否发生变化,变化时将changed置为true 10620 if (mHistoryCur.batteryLevel != level) { 10621 mHistoryCur.batteryLevel = (byte)level; 10622 changed = true; 10623 10624 // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record 10625 // which will pull external stats. 10626 scheduleSyncExternalStatsLocked("battery-level", ExternalStatsSync.UPDATE_ALL); 10627 } 10628 ...................................................... 10710 if (changed) { 10711 addHistoryRecordLocked(elapsedRealtime, uptime);//如果电量信息发生变化,就将当前的状态添加到历史记录中 10712 } 10713 } 10714 if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) { 10715 // We don't record history while we are plugged in and fully charged. 10716 // The next time we are unplugged, history will be cleared. 10717 mRecordingHistory = DEBUG; 10718 } 10719 10720 if (mMinLearnedBatteryCapacity == -1) { 10721 mMinLearnedBatteryCapacity = chargeFullUAh; 10722 } else { 10723 Math.min(mMinLearnedBatteryCapacity, chargeFullUAh); 10724 } 10725 mMaxLearnedBatteryCapacity = Math.max(mMaxLearnedBatteryCapacity, chargeFullUAh); 10726 }
setBatteryStateLocked函数: 首先判断供电状态是否发生了变化,如果发生变化,则调用setOnBatteryLocked进行处理;如果供电状态没有发生变化,则判断当前电池的各种信息是否发生变化。如果发生了变化,就将当前的电池信息添加到历史记录中。
setOnBatteryLocked相关的代码:
代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java)
10388 void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery, 10389 final int oldStatus, final int level, final int chargeUAh) { 10390 boolean doWrite = false; 10391 Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);//触发回调 10392 m.arg1 = onBattery ? 1 : 0; 10393 mHandler.sendMessage(m); 10394 10395 final long uptime = mSecUptime * 1000; 10396 final long realtime = mSecRealtime * 1000; 10397 final boolean screenOn = mScreenState == Display.STATE_ON; 10398 if (onBattery) { 10399 // We will reset our status if we are unplugging after the 10400 // battery was last full, or the level is at 100, or 10401 // we have gone through a significant charge (from a very low 10402 // level to a now very high level). 10403 boolean reset = false;
//如果拔去充电器的时候电量是满的,或当前电量大于90,或从一个很低的电量充电到很高的电量,或电量历史记录的数据太大 10404 if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL 10405 || level >= 90 10406 || (mDischargeCurrentLevel < 20 && level >= 80) 10407 || (getHighDischargeAmountSinceCharge() >= 200 10408 && mHistoryBuffer.dataSize() >= MAX_HISTORY_BUFFER))) { 10409 Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus 10410 + " dischargeLevel=" + mDischargeCurrentLevel 10411 + " lowAmount=" + getLowDischargeAmountSinceCharge() 10412 + " highAmount=" + getHighDischargeAmountSinceCharge()); 10413 // Before we write, collect a snapshot of the final aggregated 10414 // stats to be reported in the next checkin. Only do this if we have 10415 // a sufficient amount of data to make it interesting. 10416 if (getLowDischargeAmountSinceCharge() >= 20) {//变化的信息的数据足够时(累积耗电量足够大),生成一个snapshot,写入到mCheckinFile中 10417 final Parcel parcel = Parcel.obtain(); 10418 writeSummaryToParcel(parcel, true); 10419 BackgroundThread.getHandler().post(new Runnable() { 10420 @Override public void run() { 10421 synchronized (mCheckinFile) { 10422 FileOutputStream stream = null; 10423 try { 10424 stream = mCheckinFile.startWrite(); 10425 stream.write(parcel.marshall()); 10426 stream.flush(); 10427 FileUtils.sync(stream); 10428 stream.close(); 10429 mCheckinFile.finishWrite(stream); 10430 } catch (IOException e) { 10431 Slog.w("BatteryStats", 10432 "Error writing checkin battery statistics", e); 10433 mCheckinFile.failWrite(stream); 10434 } finally { 10435 parcel.recycle(); 10436 } 10437 } 10438 } 10439 }); 10440 } 10441 doWrite = true; 10442 resetAllStatsLocked();//重置电量统计的相关信息,清除当前的电量统计 10443 if (chargeUAh > 0 && level > 0) { 10444 // Only use the reported coulomb charge value if it is supported and reported. 10445 mEstimatedBatteryCapacity = (int) ((chargeUAh / 1000) / (level / 100.0)); 10446 } 10447 mDischargeStartLevel = level; 10448 reset = true; 10449 mDischargeStepTracker.init(); 10450 } 10451 if (mCharging) { 10452 setChargingLocked(false); 10453 } 10454 mLastChargingStateLevel = level; 10455 mOnBattery = mOnBatteryInternal = true; 10456 mLastDischargeStepLevel = level; 10457 mMinDischargeStepLevel = level; 10458 mDischargeStepTracker.clearTime(); 10459 mDailyDischargeStepTracker.clearTime(); 10460 mInitStepMode = mCurStepMode; 10461 mModStepMode = 0; 10462 pullPendingStateUpdatesLocked(); 10463 mHistoryCur.batteryLevel = (byte)level; 10464 mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; 10465 if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: " 10466 + Integer.toHexString(mHistoryCur.states)); 10467 if (reset) { 10468 mRecordingHistory = true; 10469 startRecordingHistory(mSecRealtime, mSecUptime, reset); 10470 } 10471 addHistoryRecordLocked(mSecRealtime, mSecUptime); 10472 mDischargeCurrentLevel = mDischargeUnplugLevel = level;//由充电变为不充电,记录下变成不充电状态时的电量 10473 if (screenOn) { 10474 mDischargeScreenOnUnplugLevel = level; 10475 mDischargeScreenOffUnplugLevel = 0; 10476 } else { 10477 mDischargeScreenOnUnplugLevel = 0; 10478 mDischargeScreenOffUnplugLevel = level; 10479 } 10480 mDischargeAmountScreenOn = 0; 10481 mDischargeAmountScreenOff = 0; 10482 updateTimeBasesLocked(true, !screenOn, uptime, realtime);//更新TimeBase,和电量统计计时器有关 10483 } else { 10484 mLastChargingStateLevel = level; 10485 mOnBattery = mOnBatteryInternal = false; 10486 pullPendingStateUpdatesLocked(); 10487 mHistoryCur.batteryLevel = (byte)level; 10488 mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; 10489 if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: " 10490 + Integer.toHexString(mHistoryCur.states)); 10491 addHistoryRecordLocked(mSecRealtime, mSecUptime); 10492 mDischargeCurrentLevel = mDischargePlugLevel = level;//记录变成充电状态时的电量 10493 if (level < mDischargeUnplugLevel) {//当前电量低于断开电源时的电量,表示电量消耗了 10494 mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;//记录下电池用电时的电量消耗 10495 mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level; 10496 } 10497 updateDischargeScreenLevelsLocked(screenOn, screenOn); 10498 updateTimeBasesLocked(false, !screenOn, uptime, realtime);//更新TimeBase,和电量统计计时器有关 10499 mChargeStepTracker.init(); 10500 mLastChargeStepLevel = level; 10501 mMaxChargeStepLevel = level; 10502 mInitStepMode = mCurStepMode; 10503 mModStepMode = 0; 10504 } 10505 if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {//从充电变为未充电,或写入的间隔够大 10506 if (mFile != null) { 10507 writeAsyncLocked();//将信息写入到BatteryStats.bin中 10508 } 10509 } 10510 } 10511