Android BatteryStatsHelper深入理解(and5.1)

更新时间:2023-03-15 12:50:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

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 2.4

624000 699563 799500 899438 999375 1099313 1199250 1299188 1399125 1499063 1599000

54 63 72 80 90 100 109 115 121 127 135

接下来说下refreshStats是用来更新电池最新状态的,statsType是指充电状态还是非充电状态,asUsers指的是userId(多用户) [java] view plain copy

public void refreshStats(int statsType, List asUsers) { final int n = asUsers.size();

SparseArray users = new SparseArray(n); for (int i = 0; i < n; ++i) {

UserHandle userHandle = asUsers.get(i);

users.put(userHandle.getIdentifier(), userHandle); }

refreshStats(statsType, users); } /**

* Refreshes the power usage list. */

public void refreshStats(int statsType, SparseArray asUsers) { refreshStats(statsType, asUsers, SystemClock.elapsedRealtime() * 1000, SystemClock.uptimeMillis() * 1000); }

接下来分析下refreshStats函数 [java] view plain copy

public void refreshStats(int statsType, SparseArray asUsers, long rawRealtimeUs, long rawUptimeUs) { // Initialize mStats if necessary. getStats();

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 user = mUserSippers.valueAt(i); for (int j=0; j

if (bs.mobilemspp != 0) {

mMobilemsppList.add(bs); } } }

Collections.sort(mMobilemsppList, new Comparator() { @Override

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 asUsers) {

final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null); ............

SparseArray 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 processStats = u.getProcessStats(); long cpuTime = 0; long cpuFgTime = 0; long wakelockTime = 0; long gpsTime = 0;

..............

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 wakelockStats = u.getWakelockStats();

for (Map.Entry wakelockEntry : wakelockStats.entrySet()) {

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 = mUserSippers.get(userId); if (list == null) {

list = new ArrayList(); mUserSippers.put(userId, list); }

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 usageList = mStatsHelper.getUsageList(); 获取后可以根据BatterySipper的value获取每小时的耗电量.

下面我们分析下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 profiles = mUm.getUserProfiles();

mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, profiles);

final List usageList = mStatsHelper.getUsageList();//获取各个耗电

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 asUsers, long rawRealtimeUs, long rawUptimeUs) { 。。。。。。。。。。。。

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 asUsers, long rawRealtimeUs, long rawUptimeUs) { 。。。。。。。。。。。。

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 usageList = mStatsHelper.getUsageList();

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,然后就会显示没有电池使用数据了。

本文来源:https://www.bwwdw.com/article/j87v.html

Top