Android BatteryStatsHelper深入理解(and5.1)
更新时间:2023-03-15 12:50:01 阅读量: 教育文库 文档下载
- android什么意思推荐度:
- 相关推荐
Android BatteryStatsHelper深入理解
(and5.1)
BatteryStatsHelper这个类主要是统计各个应用,多用户的每个用户,以及蓝牙,屏幕等耗电统计。
一般使用BatteryStatsHelper这个类,先要new一个实例,然后再调用create函数: 下面我们就先从create分析,两种create方法,其中sStatsXfer是静态的 [java] view plain copy
public void create(BatteryStats stats) {
mPowerProfile = new PowerProfile(mContext); mStats = stats; }
public void create(Bundle icicle) { if (icicle != null) {
mStats = sStatsXfer;
mBatteryBroadcast = sBatteryBroadcastXfer; }
mBatteryInfo = IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME)); mPowerProfile = new PowerProfile(mContext); }
mPowerProfile是从power_profile.xml读取的各个器件的电源消耗参数,文件如下: [java] view plain copy
3.5 54 接下来说下refreshStats是用来更新电池最新状态的,statsType是指充电状态还是非充电状态,asUsers指的是userId(多用户) [java] view plain copy public void refreshStats(int statsType, List SparseArray UserHandle userHandle = asUsers.get(i); users.put(userHandle.getIdentifier(), userHandle); } refreshStats(statsType, users); } /** * Refreshes the power usage list. */ public void refreshStats(int statsType, SparseArray 接下来分析下refreshStats函数 [java] view plain copy public void refreshStats(int statsType, SparseArray mMaxPower = 0; mMaxRealPower = 0; mComputedPower = 0; mTotalPower = 0; mWifiPower = 0; mBluetoothPower = 0; mAppMobileActive = 0; mAppWifiRunning = 0; mUsageList.clear(); mWifiSippers.clear(); mBluetoothSippers.clear(); mUserSippers.clear(); mUserPower.clear(); mMobilemsppList.clear(); if (mStats == null) { return; } mStatsType = statsType; mRawUptime = rawUptimeUs; mRawRealtime = rawRealtimeUs; mBatteryUptime = mStats.getBatteryUptime(rawUptimeUs); mBatteryRealtime = mStats.getBatteryRealtime(rawRealtimeUs); mTypeBatteryUptime = mStats.computeBatteryUptime(rawUptimeUs, mStatsType); mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType); mBatteryTimeRemaining = mStats.computeBatteryTimeRemaining(rawRealtimeUs);//获取电池剩余时间 mChargeTimeRemaining = mStats.computeChargeTimeRemaining(rawRealtimeUs);//获取充电剩余时间 if (DEBUG) { Log.d(TAG, \ + (rawUptimeUs/1000)); Log.d(TAG, \ + (mBatteryUptime/1000)); Log.d(TAG, \type time: realtime=\+ (mTypeBatteryRealtime/1000) + %uptime=\ + (mTypeBatteryUptime/1000)); } mMinDrainedPower = (mStats.getLowDischargeAmountSinceCharge() * mPowerProfile.getBatteryCapacity()) / 100; mMaxDrainedPower = (mStats.getHighDischargeAmountSinceCharge() * mPowerProfile.getBatteryCapacity()) / 100; processAppUsage(asUsers);//计算每个uid的耗电情况 // Before aggregating apps in to users, collect all apps to sort by their ms per packet. for (int i=0; i mMobilemsppList.add(bs); } } for (int i=0; i List if (bs.mobilemspp != 0) { mMobilemsppList.add(bs); } } } Collections.sort(mMobilemsppList, new Comparator public int compare(BatterySipper lhs, BatterySipper rhs) { if (lhs.mobilemspp < rhs.mobilemspp) { return 1; } else if (lhs.mobilemspp > rhs.mobilemspp) { return -1; } return 0; } }); processMiscUsage();//计算比如屏幕、wifi、蓝牙等耗电 if (DEBUG) { Log.d(TAG, \discharge=\ + makemAh(mMinDrainedPower) + \max discharge=\+ makemAh(mMaxDrainedPower)); } mTotalPower = mComputedPower; if (mStats.getLowDischargeAmountSinceCharge() > 1) { if (mMinDrainedPower > mComputedPower) { double amount = mMinDrainedPower - mComputedPower; mTotalPower = mMinDrainedPower; addEntryNoTotal(BatterySipper.DrainType.UNACCOUNTED, 0, amount);//加一个未统计电量 } else if (mMaxDrainedPower < mComputedPower) {// double amount = mComputedPower - mMaxDrainedPower; addEntryNoTotal(BatterySipper.DrainType.OVERCOUNTED, 0, amount);//加一个over统计 } } Collections.sort(mUsageList); } 下面先看processAppUsage函数,这个函数是看uid的耗电信息。 [java] view plain copy private void processAppUsage(SparseArray final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null); ............ SparseArray extends Uid> uidStats = mStats.getUidStats(); final int NU = uidStats.size(); for (int iu = 0; iu < NU; iu++) {//遍历各个uid Uid u = uidStats.valueAt(iu); double p; // in mAs double power = 0; // in mAs double highestDrain = 0; String packageWithHighestDrain = null; Map .............. if (cpuFgTime > cpuTime) {//先就算每个uid的cpu耗电 if (DEBUG && cpuFgTime > cpuTime + 10000) { Log.d(TAG, \Cputime is more than 10 seconds behind Foreground time\ } cpuTime = cpuFgTime; // Statistics may not have been gathered yet. } power /= (60*60*1000); // Process wake lock usage Map for (Map.Entry Uid.Wakelock wakelock = wakelockEntry.getValue(); // Only care about partial wake locks since full wake locks // are canceled when the user turns the screen off. BatteryStats.Timer timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL); if (timer != null) { wakelockTime += timer.getTotalTimeLocked(mRawRealtime, which); } } appWakelockTimeUs += wakelockTime; wakelockTime /= 1000; // convert to millis // Add cost of holding a wake lock//计算uid的wakelock耗电 p = (wakelockTime * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60*60*1000); if (DEBUG && p != 0) Log.d(TAG, \ + wakelockTime + \ power += p; // Add cost of mobile traffic//计算uid移动数据耗电 ................... if (DEBUG && p != 0) Log.d(TAG, \ + (mobileRx+mobileTx) + \ + \ power += p; // Add cost of wifi traffic//计算wifi数据耗电 final long wifiRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType); final long wifiTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType); final long wifiRxB = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType); final long wifiTxB = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType); p = (wifiRx + wifiTx) * wifiPowerPerPacket; if (DEBUG && p != 0) Log.d(TAG, \ + (mobileRx+mobileTx) + \ power += p; // Add cost of keeping WIFI running. long wifiRunningTimeMs = u.getWifiRunningTime(mRawRealtime, which) / 1000; mAppWifiRunning += wifiRunningTimeMs; p = (wifiRunningTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000); if (DEBUG && p != 0) Log.d(TAG, \ + wifiRunningTimeMs + \ power += p; // Add cost of WIFI scans long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000; p = (wifiScanTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN)) / (60*60*1000); if (DEBUG) Log.d(TAG, \ + \ power += p; for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) { long batchScanTimeMs = u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000; p = ((batchScanTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin)) ) / (60*60*1000); if (DEBUG && p != 0) Log.d(TAG, \\+ u.getUid() + \wifi batched scan # \ + \ power += p; } // Process Sensor usage//uid传感器耗电 ................... p = (multiplier * sensorTime) / (60*60*1000); if (DEBUG && p != 0) Log.d(TAG, \\+ u.getUid() + \sensor #\+ sensorHandle + \ power += p; } if (DEBUG && power != 0) Log.d(TAG, String.format(\%d: total power=%s\ u.getUid(), makemAh(power))); // Add the app to the list if it is consuming power final int userId = UserHandle.getUserId(u.getUid()); if (power != 0 || u.getUid() == 0) {//新建一个BatterySipper,BatterySipper 就是耗电的各个参数 BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, new double[] {power}); app.cpuTime = cpuTime; app.gpsTime = gpsTime; app.wifiRunningTime = wifiRunningTimeMs; app.cpuFgTime = cpuFgTime; app.wakeLockTime = wakelockTime; app.mobileRxPackets = mobileRx; app.mobileTxPackets = mobileTx; app.mobileActive = mobileActive / 1000; app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType); app.wifiRxPackets = wifiRx; app.wifiTxPackets = wifiTx; app.mobileRxBytes = mobileRxB; app.mobileTxBytes = mobileTxB; app.wifiRxBytes = wifiRxB; app.wifiTxBytes = wifiTxB; app.packageWithHighestDrain = packageWithHighestDrain; if (u.getUid() == Process.WIFI_UID) {//如果uid是wifi的,就加到mWifiSippers mWifiSippers.add(app); mWifiPower += power; } else if (u.getUid() == Process.BLUETOOTH_UID) {//蓝牙的就加到mBluetoothSippers mBluetoothSippers.add(app); mBluetoothPower += power; } else if (!forAllUsers && asUsers.get(userId) == null//如果没有这个userId(多用户),就重新建立一个 && UserHandle.getAppId(u.getUid()) >= Process.FIRST_APPLICATION_UID) { List list = new ArrayList list.add(app); if (power != 0) { Double userPower = mUserPower.get(userId); if (userPower == null) { userPower = power; } else { userPower += power; } mUserPower.put(userId, userPower); } } else {//或者直接加到mUsageList,mUsageList管理所有的耗电信息list mUsageList.add(app); if (power > mMaxPower) mMaxPower = power; if (power > mMaxRealPower) mMaxRealPower = power; mComputedPower += power; } if (u.getUid() == 0) { osApp = app; } } } processMiscUsage函数是统计屏幕、wifi耗电等等 [java] view plain copy private void processMiscUsage() { addUserUsage(); addPhoneUsage(); addScreenUsage(); addFlashlightUsage(); addWiFiUsage(); addBluetoothUsage(); addIdleUsage(); // Not including cellular idle power // Don't compute radio usage if it's a wifi-only device if (!mWifiOnly) { addRadioUsage(); } } [java] view plain copy private void addScreenUsage() { double power = 0; long screenOnTimeMs = mStats.getScreenOnTime(mRawRealtime, mStatsType) / 1000; power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON);//时间乘以平均功耗 final double screenFullPower = mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL); for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) { double screenBinPower = screenFullPower * (i + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; long brightnessTime = mStats.getScreenBrightnessTime(i, mRawRealtime, mStatsType) / 1000; double p = screenBinPower*brightnessTime; if (DEBUG && p != 0) { Log.d(TAG, \ + \ } power += p; } power /= (60*60*1000); // To hours最后再要除以1小时 if (power != 0) { addEntry(BatterySipper.DrainType.SCREEN, screenOnTimeMs, power); } } addEntry函数,新建一个BatterySipper,加入mUsageList [java] view plain copy private BatterySipper addEntry(DrainType drainType, long time, double power) { mComputedPower += power;//计算所有的power if (power > mMaxRealPower) mMaxRealPower = power; return addEntryNoTotal(drainType, time, power); } private BatterySipper addEntryNoTotal(DrainType drainType, long time, double power) { if (power > mMaxPower) mMaxPower = power; BatterySipper bs = new BatterySipper(drainType, null, new double[] {power});//新建一个BatterySipper,加入mUsageList bs.usageTime = time; mUsageList.add(bs); return bs; } 而如果应用想要获取各个耗电信息,先要refreshStats,再去获取getUsageList,下面是settings中电池那一栏里面的代码 [java] view plain copy mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, profiles); final List 下面我们分析下settings,电池里面的refreshStats函数: [java] view plain copy private void refreshStats() { mAppListGroup.removeAll(); mAppListGroup.setOrderingAsAdded(false); mHistPref = new BatteryHistoryPreference(getActivity(), mStatsHelper.getStats(), mStatsHelper.getBatteryBroadcast()); mHistPref.setOrder(-1); mAppListGroup.addPreference(mHistPref); boolean addedSome = false; final PowerProfile powerProfile = mStatsHelper.getPowerProfile();//每个器件的平均耗电 final BatteryStats stats = mStatsHelper.getStats(); final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL); if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP) {//如果没有配置原生的power_profile.xml,这里的averagePower 为0.1 Log.e(\\averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP\ final List mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, profiles); final List final int dischargeAmount = stats != null ? stats.getDischargeAmount(mStatsType) : 0;//BatteryStatsService统计各个的时间会在usb线拔掉后清零,dichargeaAmount相当于usb拔掉后这段时间的电量,相当于电池使用的量 final int numSippers = usageList.size(); for (int i = 0; i < numSippers; i++) { final BatterySipper sipper = usageList.get(i); if ((sipper.value * SECONDS_IN_HOUR) < MIN_POWER_THRESHOLD_MILLI_AMP) {//BatterySipper 的power都是以每小时计的 continue; } final double percentOfTotal = ((sipper.value / mStatsHelper.getTotalPower()) * dischargeAmount);//和上面一样(sipper.value / mStatsHelper.getTotalPower()统计的值,代表是该统计占该段时间内总的消耗电量的一个比,而该段时间是就是BatteryStats统计的时间,因此这段时间统计的电量还要乘以一个,这段时间内消耗的电量比上总电量的一个值。而且这个消耗电量的统计在BatteryStatsImpl中,当充电时,会把该项消耗电量统计下。 if (((int) (percentOfTotal + .5)) < 1) { continue; } if (sipper.drainType == BatterySipper.DrainType.OVERCOUNTED) { // Don't show over-counted unless it is at least 2/3 the size of // the largest real entry, and its percent of total is more significant if (sipper.value < ((mStatsHelper.getMaxRealPower()*2)/3)) { continue; } if (percentOfTotal < 10) { continue; } if (\ continue; } } if (sipper.drainType == BatterySipper.DrainType.UNACCOUNTED) { // Don't show over-counted unless it is at least 1/2 the size of // the largest real entry, and its percent of total is more significant if (sipper.value < (mStatsHelper.getMaxRealPower()/2)) { continue; } if (percentOfTotal < 5) { Log.e(\ continue; } if (\ continue; } } final UserHandle userHandle = new UserHandle(UserHandle.getUserId(sipper.getUid())); final BatteryEntry entry = new BatteryEntry(getActivity(), mHandler, mUm, sipper); final Drawable badgedIcon = mUm.getBadgedIconForUser(entry.getIcon(), userHandle); final CharSequence contentDescription = mUm.getBadgedLabelForUser(entry.getLabel(), userHandle); final PowerGaugePreference pref = new PowerGaugePreference(getActivity(), badgedIcon, contentDescription, entry); final double percentOfMax = (sipper.value * 100) / mStatsHelper.getMaxPower(); sipper.percent = percentOfTotal; pref.setTitle(entry.getLabel()); pref.setOrder(i + 1); pref.setPercent(percentOfMax, percentOfTotal); if (sipper.uidObj != null) { pref.setKey(Integer.toString(sipper.uidObj.getUid())); } addedSome = true; mAppListGroup.addPreference(pref); if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST + 1)) { break; } } } if (!addedSome) {//如果走到这里会显示\没有电池数据\,要么power_profile.xml没有配置,要么每项都continue addNotAvailableMessage(); } BatteryEntry.startRequestQueue(); } 碰到一个问题当电池电量到90%,拔去usb线,settings会显示“没有电池使用数据”,带着这个问题,我们再来看看BatteryStatsImpl: 我们先来看看BatteryStatsHelper中refreshStats函数中的一段代码,如何统计mTotalPower,先会计算一个mComputedPower,会把每个usage的power累计相加,然后下面还有一段代码,mStats.getLowDischargeAmountSinceCharge是什么意思呢?带着这个问题再去看BatteryStatsImpl的代码。 [java] view plain copy public void refreshStats(int statsType, SparseArray mTotalPower = mComputedPower; if (mStats.getLowDischargeAmountSinceCharge() > 1) {// if (mMinDrainedPower > mComputedPower) { double amount = mMinDrainedPower - mComputedPower; mTotalPower = mMinDrainedPower; addEntryNoTotal(BatterySipper.DrainType.UNACCOUNTED, 0, amount); } else if (mMaxDrainedPower < mComputedPower) { double amount = mComputedPower - mMaxDrainedPower; addEntryNoTotal(BatterySipper.DrainType.OVERCOUNTED, 0, amount); } } Collections.sort(mUsageList); } 先看BatteryStatsImpl中getLowDischargeAmountSinceCharge函数,直接从代码中找哪里改变了这个变量mLowDischargeAmountSinceCharge [java] view plain copy @Override public int getLowDischargeAmountSinceCharge() { synchronized(this) { int val = mLowDischargeAmountSinceCharge; if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) { val += mDischargeUnplugLevel-mDischargeCurrentLevel-1; } return val; } } 发现在setOnBatteryLocked函数中会改变其值,而setOnBatteryLocked函数是有BatteryService调用,只有当充电方式改变才会掉,而我们这段代码代表,只有插上usb线会调用,level代表当前电量,mDischargeUnplugLevel代表上一次拔去usb线的电量,这就代表上次拔去usb线后,电量level减少了,就是耗电了,在这次充电的时候把之前的耗电统计下,放在mLowDischargeAmountSinceCharge 和mHighDischargeAmountSinceCharge 这两个变量中,这两个变量差1,就是有一个误差的范围而已。 [java] view plain copy void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery, final int oldStatus, final int level) { else { mOnBattery = mOnBatteryInternal = onBattery; pullPendingStateUpdatesLocked(); mHistoryCur.batteryLevel = (byte)level; mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, \ + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(mSecRealtime, mSecUptime); mDischargeCurrentLevel = mDischargePlugLevel = level; if (level < mDischargeUnplugLevel) {//level代表当前电量,mDischargeUnplugLevel代表上一次拔去usb线的电量 mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;//累计消耗的电量 mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level; } updateDischargeScreenLevelsLocked(screenOn, screenOn); updateTimeBasesLocked(false, !screenOn, uptime, realtime); mNumChargeStepDurations = 0; mLastChargeStepLevel = level; mMaxChargeStepLevel = level; mLastChargeStepTime = -1; mInitStepMode = mCurStepMode; mModStepMode = 0; } 现在我们再来看看getLowDischargeAmountSinceCharge函数。 [java] view plain copy @Override public int getLowDischargeAmountSinceCharge() { synchronized(this) { int val = mLowDischargeAmountSinceCharge; if (mOnBattery && mDischargeCurrentLevel < mDischargeUnplugLevel) {//表示现在正在用电状态,mDischargeCurrentLevel 变量代表用电的时候的电量,会时时更新,mDischargeUnplugLevel代表上一次拔去usb线的一个电量,也就是最近的一次消耗电量 val += mDiscwww.sm136.comhargeUnplugLevel-mDischargeCurrentLevel-1; } return val; } } 最近一次的消耗电量加上之前累计的消耗电量就是总的消耗电量了。 下面看看几个关键变量 [java] view plain copy void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery, final int oldStatus, final int level) { boolean doWrite = false; Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE); m.arg1 = onBattery ? 1 : 0; mHandler.sendMessage(m); final long uptime = mSecUptime * 1000; final long realtime = mSecRealtime * 1000; final boolean screenOn = mScreenState == Display.STATE_ON; if (onBattery) { 。。。。。。。。。。 addHistoryRecordLocked(mSecRealtime, mSecUptime); mDischargeCurrentLevel = mDischargeUnplugLevel = level;//刚拔去usb线的时候统计下mDischargeCurrentLevel和mDischargeUnplugLevel值 if (screenOn) { mDischargeScreenOnUnplugLevel = level; mDischargeScreenOffUnplugLevel = 0; } else { mDischargeScreenOnUnplugLevel = 0; mDischargeScreenOffUnplugLevel = level; } mDischargeAmountScreenOn = 0; mDischargeAmountScreenOff = 0; updateTimeBasesLocked(true, !screenOn, uptime, realtime); } else { mOnBattery = mOnBatteryInternal = onBattery; pullPendingStateUpdatesLocked(); mHistoryCur.batteryLevel = (byte)level; mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, \ + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(mSecRealtime, mSecUptime); mDischargeCurrentLevel = mDischargePlugLevel = level;//刚插上usb线的时候统计下mDischargeCurrentLevel和mDischargePlugLevel值 setBatteryState是BatteryService时时调的,而setOnBatteryLocked只有充电方式改变后才会调用。 [java] view plain copy public void setBatteryState(int status, int health, int plugType, int level, int temp, int volt) { synchronized(this) { final boolean onBattery = plugType == BATTERY_PLUGGED_NONE; final long uptime = SystemClock.uptimeMillis(); final long elapsedRealtime = SystemClock.elapsedRealtime(); int oldStatus = mHistoryCur.batteryStatus; if (!mHaveBatteryLevel) { mHaveBatteryLevel = true; // We start out assuming that the device is plugged in (not // on battery). If our first report is now that we are indeed // plugged in, then twiddle our state to correctly reflect that // since we won't be going through the full setOnBattery(). if (onBattery == mOnBattery) { if (onBattery) { mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; } else { mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; } } oldStatus = status; } if (onBattery) { mDischargeCurrentLevel = level;//只要使用电池该mDischargeCurrentLevel 也是时时更新。 if (!mRecordingHistory) { mRecordingHistory = true; startRecordingHistory(elapsedRealtime, uptime, true); } } else if (level < 96) { if (!mRecordingHistory) { mRecordingHistory = true; startRecordingHistory(elapsedRealtime, uptime, true); } } 再回到前面一开始的BatteryStatsHelper中的mTotalPower问题, [java] view plain copy public void refreshStats(int statsType, SparseArray mTotalPower = mComputedPower; if (mStats.getLowDischargeAmountSinceCharge() > 1) {//只要统计消耗的电量大于1 if (mMinDrainedPower > mComputedPower) {//如果实际总的消耗电量比统计的电量大,那么mTotalPower 就用实际消耗的电量 double amount = mMinDrainedPower - mComputedPower; mTotalPower = mMinDrainedPower; addEntryNoTotal(BatterySipper.DrainType.UNACCOUNTED, 0, amount);//并且将没有统计到的电量,也放在usgaelist中 } else if (mMaxDrainedPower < mComputedPower) { double amount = mComputedPower - mMaxDrainedPower; addEntryNoTotal(BatterySipper.DrainType.OVERCOUNTED, 0, amount); } } Collections.sort(mUsageList); } 再看看mMinDrainedPower 和mMaxDrainedPower 两个变量,就是消耗电量除以100,乘以总电量就是消耗的实际电量而不是百分比了。 [java] view plain copy mMinDrainedPower = (mStats.getLowDischargeAmountSinceCharge() * mPowerProfile.getBatteryCapacity()) / 100; mMaxDrainedPower = (mStats.getHighDischargeAmountSinceCharge() * mPowerProfile.getBatteryCapacity()) / 100; 回过头来看看settings为什么90%之后,拔掉usb线就没有电池数据了,settings会遍历所有的usagelist,只有所有的都continue才会出现没有电池数据,一个可能及时dischargeAmount为0,mStatsHelper.getTotalPower,和sipper.value [java] view plain copy mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, profiles); final List final int dischargeAmount = stats != null ? stats.getDischargeAmount(mStatsType) : 0; final int numSippers = usageList.size(); for (int i = 0; i < numSippers; i++) { final BatterySipper sipper = usageList.get(i); if ((sipper.value * SECONDS_IN_HOUR) < MIN_POWER_THRESHOLD_MILLI_AMP) { continue; } final double percentOfTotal = ((sipper.value / mStatsHelper.getTotalPower()) * dischargeAmount); if (((int) (percentOfTotal + .5)) < 1) { continue; } if (sipper.drainType == BatterySipper.DrainType.OVERCOUNTED) { // Don't show over-counted unless it is at least 2/3 the size of // the largest real entry, and its percent of total is more significant if (sipper.value < ((mStatsHelper.getMaxRealPower()*2)/3)) { continue; } if (percentOfTotal < 10) { continue; } if (\ continue; } } if (sipper.drainType == BatterySipper.DrainType.UNACCOUNTED) { // Don't show over-counted unless it is at least 1/2 the size of // the largest real entry, and its percent of total is more significant if (sipper.value < (mStatsHelper.getMaxRealPower()/2)) { continue; } if (percentOfTotal < 5) { continue; } if (\ continue; } } 而我们看看BatteryStatsImpl中getDischargeAmount就是getHighDischargeAmountSinceCharge函数,而getHighDischargeAmountSinceCharge就是统计了电池消耗的电量,只是范围比较大的那个值,所有到90%没有关系。 [java] view plain copy @Override public int getDischargeAmount(int which) { int dischargeAmount = which == STATS_SINCE_CHARGED ? getHighDischargeAmountSinceCharge() : (getDischargeStartLevel() - getDischargeCurrentLevel()); if (dischargeAmount < 0) { dischargeAmount = 0; } return dischargeAmount; } mStatsHelper.getTotalPower也是BatteryStatsHelper统计的消耗电量,和到90%也没有关系。 那么剩下只有一个可能,sipper.value 为0. 而每个usage的消耗电量为0,只有是统计的时间为0. 再去BatteryStatsImpl看看什么时候会将统计的时间置为0. 在resetAllStatsLocked接口里会把所有的timer重新reset,之后看看谁调用了这个函数 [java] view plain copy private void resetAllStatsLocked() { mStartCount = 0; initTimes(SystemClock.uptimeMillis() * 1000, SystemClock.elapsedRealtime() * 1000); mScreenOnTimer.reset(false); for (int i=0; i mInteractiveTimer.reset(false); mLowPowerModeEnabledTimer.reset(false); mPhoneOnTimer.reset(false); mAudioOnTimer.reset(false); mVideoOnTimer.reset(false); mFlashlightOnTimer.reset(false); for (int i=0; i mPhoneSignalScanningTimer.reset(false); for (int i=0; i 结果就发现在setOnBatteryLocked [java] view plain copy void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery, final int oldStatus, final int level) { boolean doWrite = false; Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE); m.arg1 = onBattery ? 1 : 0; mHandler.sendMessage(m); final long uptime = mSecUptime * 1000; final long realtime = mSecRealtime * 1000; final boolean screenOn = mScreenState == Display.STATE_ON; if (onBattery) { // We will reset our status if we are unplugging after the // battery was last full, or the level is at 100, or // we have gone through a significant charge (from a very low // level to a now very high level). boolean reset = false; if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL || level >= 90//当当前电量大于90% || (mDischargeCurrentLevel < 20 && level >= 80)//当上次插电时的电量是 20,现在充电充到80 || (getHighDischargeAmountSinceCharge() >= 200 && mHistoryBuffer.dataSize() >= MAX_HISTORY_BUFFER))) { Slog.i(TAG, \ + \ + \ + \ // Before we write, collect a snwww.tt951.comapshot of the final aggregated // stats to be reported in the next checkin. Only do this if we have // a sufficient amount of data to make it interesting. if (getLowDischargeAmountSinceCharge() >= 20) { final Parcel parcel = Parcel.obtain(); writeSummaryToParcel(parcel, true); BackgroundThread.getHandler().post(new Runnable() { @Override pubnc630.comlic void run() { synchronized (mCheckinFile) { FileOutputStream stream = null; try { stream = mCheckinFile.startWrite(); stream.write(parcel.marshall()); stream.flush(); FileUtils.sync(stream); stream.close(); mCheckinFile.finishWrite(stream); } catch (IOException e) { Slog.w(\ \ mCheckinFile.failWrite(stream); } finally { parcel.recycle(); } } } }); } doWrite = true; resetAllStatsLocked();//会将所有的timer,重置 mDischargeStartLevel = level; reset = true; mNumDischargeStepDurations = 0; } 好了,现在有答案了,当电量大于90的时候,BatteryStatsImpl会将所有timer重置,导致BatteryStatsHelper的各个Usage统计的电量为0,之后Settings就会在遍历每个usage的时候continue,然后就会显示没有电池使用数据了。
正在阅读:
Android BatteryStatsHelper深入理解(and5.1)03-15
街道2022年重点工作谋划08-01
企业战略管理参考文献02-19
心理健康题06-11
句子成分和句子的主干01-30
2018届毕业生实习就业动员大会主持稿04-20
2017-2018学年度外研版必修5Module 2 单元试题07-04
水采样复习题及参考答案06-25
安徽省装备制造业调整和振兴规划概要11-24
2012年高考政治《经济生活》考点解读03-29
- 1Android5.1SystemUI详解 - 图文
- 2Android-JNI-03JNI深入
- 3最新-初中数学教学论文 深入理解课标教材 努力提高教学质量 精品
- 4android6.0 power显示(亮度等)深入分析(二)DisplayManagerSe
- 5android6.0 power显示(亮度等)深入分析(二)DisplayManagerServic
- 6android6.0 power显示(亮度等)深入分析(二)DisplayManagerServic
- 7第一部分 第4章 VMware vSphere 5.1 群集深入解析
- 8第一部分 第4章 VMware vSphere 5.1 群集深入解析
- 9转载深入浅出-通俗易懂的的矩阵理解文章
- 10转载深入浅出-通俗易懂的的矩阵理解文章
- exercise2
- 铅锌矿详查地质设计 - 图文
- 厨余垃圾、餐厨垃圾堆肥系统设计方案
- 陈明珠开题报告
- 化工原理精选例题
- 政府形象宣传册营销案例
- 小学一至三年级语文阅读专项练习题
- 2014.民诉 期末考试 复习题
- 巅峰智业 - 做好顶层设计对建设城市的重要意义
- (三起)冀教版三年级英语上册Unit4 Lesson24练习题及答案
- 2017年实心轮胎现状及发展趋势分析(目录)
- 基于GIS的农用地定级技术研究定稿
- 2017-2022年中国医疗保健市场调查与市场前景预测报告(目录) - 图文
- 作业
- OFDM技术仿真(MATLAB代码) - 图文
- Android工程师笔试题及答案
- 生命密码联合密码
- 空间地上权若干法律问题探究
- 江苏学业水平测试《机械基础》模拟试题
- 选课走班实施方案
- BatteryStatsHelp
- 深入
- 理解
- Android
- 5.1
- er
- 十佳社团评优材料 - 图文
- 药理学名词解释必考
- 百科知识竞赛题库
- 外研版初二上英语Module 3复习
- 实践性作业设计 精品 - 图文
- 安徽省省道网调整规划-报批稿 - 图文
- 《运输管理实务》课程考试试题及答案
- 劳务队伍管理措施
- 关于一些插件开发的参考代码
- 2018临沂市智慧云平台培训心得体会
- 临水临电施工方案(恒大泉都)
- 软件体系结构实验指导书
- 矛盾的统一性和斗争性与构建和谐社会
- VDA6.3 - -过程审核,VDA6.5产品审核,内审检查表
- 8个数码管动态显示
- 项目分公司书记安全生产责任制
- “互联网+”时代企业文化塑造研究 - 以华为企业为例
- 2012年决算财务情况说明书
- 莎士比亚三个时期的创作变化分析
- 初三保送生选拔数学试卷及答案