diff options
author | Dianne Hackborn <hackbod@google.com> | 2014-02-26 12:35:32 -0800 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2014-02-26 15:53:44 -0800 |
commit | d45665bf0b26fddf5716a0fd43036848d9301960 (patch) | |
tree | f80f5f2b4ff5db4106c1ec5c8dea7fd26cd3cfb6 | |
parent | ba7d4f564c1858d46ad55e6a6ca381f532f4acef (diff) | |
download | frameworks_base-d45665bf0b26fddf5716a0fd43036848d9301960.zip frameworks_base-d45665bf0b26fddf5716a0fd43036848d9301960.tar.gz frameworks_base-d45665bf0b26fddf5716a0fd43036848d9301960.tar.bz2 |
Collect per-uid mobile radio usage.
We now compute radio active time per application, by distributing
the active time across all applications each time the radio goes
down, weighting it by the number of packets transferred.
Per-app radio power use is now computed using this radio active
time.
This also gives us a new metric "ms per packet", which give an
idea of how effectively an application is using the radio. This
is collected and reported as a new set of stats in the human-
readable checkin. (It can be computed from the raw checkin data).
Also improve sync reporting to include the sync source as used
in wake locks, not just the component name.
Change-Id: I0b0185fadd1e47ae749090ed36728ab78ac24c5e
8 files changed, 349 insertions, 68 deletions
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 25514f4..54d43d3 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -507,6 +507,17 @@ public class NetworkStats implements Parcelable { } /** + * Fast path for battery stats. + */ + public long getTotalPackets() { + long total = 0; + for (int i = size-1; i >= 0; i--) { + total += rxPackets[i] + txPackets[i]; + } + return total; + } + + /** * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over * time, and that none of them have disappeared. diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index e91f7d7..bfce0c1 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -326,6 +326,8 @@ public abstract class BatteryStats implements Parcelable { public abstract boolean hasNetworkActivity(); public abstract long getNetworkActivityBytes(int type, int which); public abstract long getNetworkActivityPackets(int type, int which); + public abstract long getMobileRadioActiveTime(int which); + public abstract int getMobileRadioActiveCount(int which); public static abstract class Sensor { /* @@ -899,6 +901,28 @@ public abstract class BatteryStats implements Parcelable { */ public abstract long getMobileRadioActiveTime(long batteryRealtime, int which); + /** + * Returns the number of times that the mobile network has transitioned to the + * active state. + * + * {@hide} + */ + public abstract int getMobileRadioActiveCount(int which); + + /** + * Returns the time in microseconds that the mobile network has been active + * (in a high power state) but not being able to blame on an app. + * + * {@hide} + */ + public abstract long getMobileRadioActiveUnknownTime(int which); + + /** + * Return count of number of times radio was app that could not be blamed on apps. + * + * {@hide} + */ + public abstract int getMobileRadioActiveUnknownCount(int which); public static final int DATA_CONNECTION_NONE = 0; public static final int DATA_CONNECTION_GPRS = 1; @@ -1238,6 +1262,13 @@ public abstract class BatteryStats implements Parcelable { sb.append("ms "); } + private final static void formatTimeMsNoSpace(StringBuilder sb, long time) { + long sec = time / 1000; + formatTimeRaw(sb, sec); + sb.append(time - (sec * 1000)); + sb.append("ms"); + } + private final String formatRatioLocked(long num, long den) { if (den == 0L) { return "--%"; @@ -1590,6 +1621,8 @@ public abstract class BatteryStats implements Parcelable { long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); + long mobileActiveTime = u.getMobileRadioActiveTime(which); + int mobileActiveCount = u.getMobileRadioActiveCount(which); long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which); @@ -1598,11 +1631,12 @@ public abstract class BatteryStats implements Parcelable { if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0 || mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0 - || wifiPacketsTx > 0) { + || wifiPacketsTx > 0 || mobileActiveTime > 0 || mobileActiveCount > 0) { dumpLine(pw, uid, category, NETWORK_DATA, mobileBytesRx, mobileBytesTx, wifiBytesRx, wifiBytesTx, mobilePacketsRx, mobilePacketsTx, - wifiPacketsRx, wifiPacketsTx); + wifiPacketsRx, wifiPacketsTx, + mobileActiveTime, mobileActiveCount); } if (fullWifiLockOnTime != 0 || wifiScanTime != 0 @@ -1932,9 +1966,9 @@ public abstract class BatteryStats implements Parcelable { pw.print(", sent "); pw.print(wifiTxTotalPackets); pw.println(")"); sb.setLength(0); sb.append(prefix); - sb.append(" Total full wakelock time: "); formatTimeMs(sb, + sb.append(" Total full wakelock time: "); formatTimeMsNoSpace(sb, (fullWakeLockTimeTotalMicros + 500) / 1000); - sb.append(", Total partial wakelock time: "); formatTimeMs(sb, + sb.append(", Total partial wakelock time: "); formatTimeMsNoSpace(sb, (partialWakeLockTimeTotalMicros + 500) / 1000); pw.println(sb.toString()); @@ -1964,7 +1998,7 @@ public abstract class BatteryStats implements Parcelable { sb.setLength(0); sb.append(prefix); sb.append(" Signal scanning time: "); - formatTimeMs(sb, getPhoneSignalScanningTime(batteryRealtime, which) / 1000); + formatTimeMsNoSpace(sb, getPhoneSignalScanningTime(batteryRealtime, which) / 1000); pw.println(sb.toString()); sb.setLength(0); @@ -1993,9 +2027,26 @@ public abstract class BatteryStats implements Parcelable { sb.setLength(0); sb.append(prefix); sb.append(" Mobile radio active time: "); - formatTimeMs(sb, getMobileRadioActiveTime(batteryRealtime, which) / 1000); + final long mobileActiveTime = getMobileRadioActiveTime(batteryRealtime, which); + formatTimeMs(sb, mobileActiveTime / 1000); + sb.append("("); sb.append(formatRatioLocked(mobileActiveTime, whichBatteryRealtime)); + sb.append(") "); sb.append(getMobileRadioActiveCount(which)); + sb.append("x"); pw.println(sb.toString()); + final long mobileActiveUnknownTime = getMobileRadioActiveUnknownTime(which); + if (mobileActiveUnknownTime != 0) { + sb.setLength(0); + sb.append(prefix); + sb.append(" Mobile radio active unknown time: "); + formatTimeMs(sb, mobileActiveUnknownTime / 1000); + sb.append("("); + sb.append(formatRatioLocked(mobileActiveUnknownTime, whichBatteryRealtime)); + sb.append(") "); sb.append(getMobileRadioActiveUnknownCount(which)); + sb.append("x"); + pw.println(sb.toString()); + } + sb.setLength(0); sb.append(prefix); sb.append(" Wifi on: "); formatTimeMs(sb, wifiOnTime / 1000); @@ -2132,7 +2183,8 @@ public abstract class BatteryStats implements Parcelable { pw.println(); break; case APP: - pw.print(prefix); pw.print(" Uid "); pw.print(bs.uidObj.getUid()); + pw.print(prefix); pw.print(" Uid "); + UserHandle.formatUid(pw, bs.uidObj.getUid()); pw.print(": "); printmAh(pw, bs.value); pw.println(); break; case USER: @@ -2152,6 +2204,23 @@ public abstract class BatteryStats implements Parcelable { pw.println(); } + sippers = helper.getMobilemsppList(); + if (sippers != null && sippers.size() > 0) { + pw.print(prefix); pw.println(" Per-app mobile ms per packet:"); + for (int i=0; i<sippers.size(); i++) { + BatterySipper bs = sippers.get(i); + sb.setLength(0); + sb.append(prefix); sb.append(" Uid "); + UserHandle.formatUid(sb, bs.uidObj.getUid()); + sb.append(": "); sb.append(BatteryStatsHelper.makemAh(bs.mobilemspp)); + sb.append(" ("); sb.append(bs.mobileRxPackets+bs.mobileTxPackets); + sb.append(" packets over "); formatTimeMsNoSpace(sb, bs.mobileActive); + sb.append(")"); + pw.println(sb.toString()); + } + pw.println(); + } + if (timers.size() > 0) { Collections.sort(timers, timerComparator); pw.print(prefix); pw.println(" All partial wake locks:"); @@ -2183,13 +2252,15 @@ public abstract class BatteryStats implements Parcelable { UserHandle.formatUid(pw, uid); pw.println(":"); boolean uidActivity = false; - + long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); + long uidMobileActiveTime = u.getMobileRadioActiveTime(which); + int uidMobileActiveCount = u.getMobileRadioActiveCount(which); long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which); @@ -2204,6 +2275,23 @@ public abstract class BatteryStats implements Parcelable { pw.print(" sent (packets "); pw.print(mobileRxPackets); pw.print(" received, "); pw.print(mobileTxPackets); pw.println(" sent)"); } + if (uidMobileActiveTime > 0 || uidMobileActiveCount > 0) { + sb.setLength(0); + sb.append(prefix); sb.append(" Mobile radio active: "); + formatTimeMs(sb, uidMobileActiveTime / 1000); + sb.append("("); + sb.append(formatRatioLocked(uidMobileActiveTime, mobileActiveTime)); + sb.append(") "); sb.append(uidMobileActiveCount); sb.append("x"); + long packets = mobileRxPackets + mobileTxPackets; + if (packets == 0) { + packets = 1; + } + sb.append(" @ "); + sb.append(BatteryStatsHelper.makemAh(uidMobileActiveTime / 1000 / (double)packets)); + sb.append(" mspp"); + pw.println(sb.toString()); + } + if (wifiRxBytes > 0 || wifiTxBytes > 0 || wifiRxPackets > 0 || wifiTxPackets > 0) { pw.print(prefix); pw.print(" Wi-Fi network: "); pw.print(formatBytesLocked(wifiRxBytes)); pw.print(" received, "); @@ -2212,6 +2300,24 @@ public abstract class BatteryStats implements Parcelable { pw.print(" received, "); pw.print(wifiTxPackets); pw.println(" sent)"); } + if (fullWifiLockOnTime != 0 || wifiScanTime != 0 + || uidWifiRunningTime != 0) { + sb.setLength(0); + sb.append(prefix); sb.append(" Wifi Running: "); + formatTimeMs(sb, uidWifiRunningTime / 1000); + sb.append("("); sb.append(formatRatioLocked(uidWifiRunningTime, + whichBatteryRealtime)); sb.append(")\n"); + sb.append(prefix); sb.append(" Full Wifi Lock: "); + formatTimeMs(sb, fullWifiLockOnTime / 1000); + sb.append("("); sb.append(formatRatioLocked(fullWifiLockOnTime, + whichBatteryRealtime)); sb.append(")\n"); + sb.append(prefix); sb.append(" Wifi Scan: "); + formatTimeMs(sb, wifiScanTime / 1000); + sb.append("("); sb.append(formatRatioLocked(wifiScanTime, + whichBatteryRealtime)); sb.append(")"); + pw.println(sb.toString()); + } + if (u.hasUserActivity()) { boolean hasData = false; for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) { @@ -2233,24 +2339,6 @@ public abstract class BatteryStats implements Parcelable { pw.println(sb.toString()); } } - - if (fullWifiLockOnTime != 0 || wifiScanTime != 0 - || uidWifiRunningTime != 0) { - sb.setLength(0); - sb.append(prefix); sb.append(" Wifi Running: "); - formatTimeMs(sb, uidWifiRunningTime / 1000); - sb.append("("); sb.append(formatRatioLocked(uidWifiRunningTime, - whichBatteryRealtime)); sb.append(")\n"); - sb.append(prefix); sb.append(" Full Wifi Lock: "); - formatTimeMs(sb, fullWifiLockOnTime / 1000); - sb.append("("); sb.append(formatRatioLocked(fullWifiLockOnTime, - whichBatteryRealtime)); sb.append(")\n"); - sb.append(prefix); sb.append(" Wifi Scan: "); - formatTimeMs(sb, wifiScanTime / 1000); - sb.append("("); sb.append(formatRatioLocked(wifiScanTime, - whichBatteryRealtime)); sb.append(")"); - pw.println(sb.toString()); - } Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats(); if (wakelocks.size() > 0) { diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java index 4eff5ac..565cee4 100644 --- a/core/java/com/android/internal/os/BatterySipper.java +++ b/core/java/com/android/internal/os/BatterySipper.java @@ -34,6 +34,8 @@ public class BatterySipper implements Comparable<BatterySipper> { public long wakeLockTime; public long mobileRxPackets; public long mobileTxPackets; + public long mobileActive; + public double mobilemspp; // milliseconds per packet public long wifiRxPackets; public long wifiTxPackets; public long mobileRxBytes; @@ -69,6 +71,11 @@ public class BatterySipper implements Comparable<BatterySipper> { return values; } + public void computeMobilemspp() { + long packets = mobileRxPackets+mobileTxPackets; + mobilemspp = packets > 0 ? (mobileActive / (double)packets) : 0; + } + @Override public int compareTo(BatterySipper other) { // Return the flipped value because we want the items in descending order diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index e0cf435..755530c 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -43,6 +43,7 @@ import com.android.internal.os.BatterySipper.DrainType; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; @@ -73,6 +74,8 @@ public class BatteryStatsHelper { = new SparseArray<List<BatterySipper>>(); private final SparseArray<Double> mUserPower = new SparseArray<Double>(); + private final List<BatterySipper> mMobilemsppList = new ArrayList<BatterySipper>(); + private int mStatsType = BatteryStats.STATS_SINCE_CHARGED; private int mAsUser = 0; @@ -90,6 +93,9 @@ public class BatteryStatsHelper { private double mMinDrainedPower; private double mMaxDrainedPower; + // How much the apps together have kept the mobile radio active. + private long mAppMobileActive; + // How much the apps together have left WIFI running. private long mAppWifiRunning; @@ -132,7 +138,7 @@ public class BatteryStatsHelper { } public static String makemAh(double power) { - if (power < .0001) return String.format("%.8f", power); + if (power < .00001) return String.format("%.8f", power); else if (power < .0001) return String.format("%.7f", power); else if (power < .001) return String.format("%.6f", power); else if (power < .01) return String.format("%.5f", power); @@ -160,6 +166,7 @@ public class BatteryStatsHelper { mTotalPower = 0; mWifiPower = 0; mBluetoothPower = 0; + mAppMobileActive = 0; mAppWifiRunning = 0; mUsageList.clear(); @@ -167,6 +174,7 @@ public class BatteryStatsHelper { mBluetoothSippers.clear(); mUserSippers.clear(); mUserPower.clear(); + mMobilemsppList.clear(); if (mStats == null) { return; @@ -193,6 +201,37 @@ public class BatteryStatsHelper { * mPowerProfile.getBatteryCapacity()) / 100; processAppUsage(); + + // Before aggregating apps in to users, collect all apps to sort by their ms per packet. + for (int i=0; i<mUsageList.size(); i++) { + BatterySipper bs = mUsageList.get(i); + bs.computeMobilemspp(); + if (bs.mobilemspp != 0) { + mMobilemsppList.add(bs); + } + } + for (int i=0; i<mUserSippers.size(); i++) { + List<BatterySipper> user = mUserSippers.valueAt(i); + for (int j=0; j<user.size(); j++) { + BatterySipper bs = user.get(j); + bs.computeMobilemspp(); + if (bs.mobilemspp != 0) { + mMobilemsppList.add(bs); + } + } + } + Collections.sort(mMobilemsppList, new Comparator<BatterySipper>() { + @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(); if (DEBUG) { @@ -225,6 +264,7 @@ public class BatteryStatsHelper { powerCpuNormal[p] = mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p); } final double mobilePowerPerPacket = getMobilePowerPerPacket(); + final double mobilePowerPerMs = getMobilePowerPerMs(); final double wifiPowerPerPacket = getWifiPowerPerPacket(); long appWakelockTime = 0; BatterySipper osApp = null; @@ -320,9 +360,20 @@ public class BatteryStatsHelper { final long mobileTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType); final long mobileRxB = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType); final long mobileTxB = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType); - p = (mobileRx + mobileTx) * mobilePowerPerPacket; + final long mobileActive = u.getMobileRadioActiveTime(mStatsType); + if (mobileActive > 0) { + // We are tracking when the radio is up, so can use the active time to + // determine power use. + mAppMobileActive += mobileActive; + p = (mobilePowerPerMs * mobileActive) / 1000; + } else { + // We are not tracking when the radio is up, so must approximate power use + // based on the number of packets. + p = (mobileRx + mobileTx) * mobilePowerPerPacket; + } if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": mobile packets " - + (mobileRx+mobileTx) + " power=" + makemAh(p)); + + (mobileRx+mobileTx) + " active time " + mobileActive + + " power=" + makemAh(p)); power += p; // Add cost of wifi traffic @@ -406,6 +457,7 @@ public class BatteryStatsHelper { app.wakeLockTime = wakelockTime; app.mobileRxPackets = mobileRx; app.mobileTxPackets = mobileTx; + app.mobileActive = mobileActive / 1000; app.wifiRxPackets = wifiRx; app.wifiTxPackets = wifiTx; app.mobileRxBytes = mobileRxB; @@ -474,7 +526,7 @@ public class BatteryStatsHelper { double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE) * phoneOnTimeMs / (60*60*1000); if (phoneOnPower != 0) { - addEntry(BatterySipper.DrainType.PHONE, phoneOnTimeMs, phoneOnPower); + BatterySipper bs = addEntry(BatterySipper.DrainType.PHONE, phoneOnTimeMs, phoneOnPower); } } @@ -531,12 +583,18 @@ public class BatteryStatsHelper { Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + makemAh(p)); } power += p; + long radioActiveTimeUs = mStats.getMobileRadioActiveTime(mBatteryRealtime, mStatsType); + long remainingActiveTime = (radioActiveTimeUs - mAppMobileActive) / 1000; + if (remainingActiveTime > 0) { + power += getMobilePowerPerMs() * remainingActiveTime; + } if (power != 0) { BatterySipper bs = addEntry(BatterySipper.DrainType.CELL, signalTimeMs, power); if (signalTimeMs != 0) { bs.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs; } + bs.mobileActive = remainingActiveTime; } } @@ -551,6 +609,7 @@ public class BatteryStatsHelper { bs.wakeLockTime += wbs.wakeLockTime; bs.mobileRxPackets += wbs.mobileRxPackets; bs.mobileTxPackets += wbs.mobileTxPackets; + bs.mobileActive += wbs.mobileActive; bs.wifiRxPackets += wbs.wifiRxPackets; bs.wifiTxPackets += wbs.wifiTxPackets; bs.mobileRxBytes += wbs.mobileRxBytes; @@ -558,6 +617,7 @@ public class BatteryStatsHelper { bs.wifiRxBytes += wbs.wifiRxBytes; bs.wifiTxBytes += wbs.wifiTxBytes; } + bs.computeMobilemspp(); } private void addWiFiUsage() { @@ -650,6 +710,13 @@ public class BatteryStatsHelper { } /** + * Return estimated power (in mAs) of keeping the radio up + */ + private double getMobilePowerPerMs() { + return mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE) / (60*60*1000); + } + + /** * Return estimated power (in mAs) of sending a byte with the Wi-Fi radio. */ private double getWifiPowerPerPacket() { @@ -691,6 +758,10 @@ public class BatteryStatsHelper { return mUsageList; } + public List<BatterySipper> getMobilemsppList() { + return mMobilemsppList; + } + public long getStatsPeriod() { return mStatsPeriod; } public int getStatsType() { return mStatsType; }; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 8843500..46983ab 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -87,7 +87,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 85 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 90 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -283,6 +283,8 @@ public final class BatteryStatsImpl extends BatteryStats { boolean mMobileRadioActive; StopwatchTimer mMobileRadioActiveTimer; + LongSamplingCounter mMobileRadioActiveUnknownTime; + LongSamplingCounter mMobileRadioActiveUnknownCount; /** Bluetooth headset object */ BluetoothHeadset mBtHeadset; @@ -1176,11 +1178,12 @@ public final class BatteryStatsImpl extends BatteryStats { void startRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) { if (mNesting++ == 0) { - mUpdateTime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000); + final long batteryRealtime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000); + mUpdateTime = batteryRealtime; if (mTimerPool != null) { // Accumulate time to all currently active timers before adding // this new one to the pool. - refreshTimersLocked(stats, mTimerPool); + refreshTimersLocked(stats, batteryRealtime, mTimerPool, null); // Add this timer to the active pool mTimerPool.add(this); } @@ -1199,21 +1202,35 @@ public final class BatteryStatsImpl extends BatteryStats { return mNesting > 0; } + long checkpointRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) { + if (mNesting > 0) { + // We are running... + final long batteryRealtime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000); + if (mTimerPool != null) { + return refreshTimersLocked(stats, batteryRealtime, mTimerPool, this); + } + final long heldTime = batteryRealtime - mUpdateTime; + mUpdateTime = batteryRealtime; + mTotalTime += heldTime; + return heldTime; + } + return 0; + } + void stopRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) { // Ignore attempt to stop a timer that isn't running if (mNesting == 0) { return; } if (--mNesting == 0) { + final long batteryRealtime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000); if (mTimerPool != null) { // Accumulate time to all active counters, scaled by the total // active in the pool, before taking this one out of the pool. - refreshTimersLocked(stats, mTimerPool); + refreshTimersLocked(stats, batteryRealtime, mTimerPool, null); // Remove this timer from the active pool mTimerPool.remove(this); } else { - final long batteryRealtime = stats.getBatteryRealtimeLocked( - elapsedRealtime * 1000); mNesting = 1; mTotalTime = computeRunTimeLocked(batteryRealtime); mNesting = 0; @@ -1235,19 +1252,23 @@ public final class BatteryStatsImpl extends BatteryStats { // Update the total time for all other running Timers with the same type as this Timer // due to a change in timer count - private static void refreshTimersLocked(final BatteryStatsImpl stats, - final ArrayList<StopwatchTimer> pool) { - final long realtime = SystemClock.elapsedRealtime() * 1000; - final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime); + private static long refreshTimersLocked(final BatteryStatsImpl stats, + long batteryRealtime, final ArrayList<StopwatchTimer> pool, StopwatchTimer self) { + long selfTime = 0; final int N = pool.size(); for (int i=N-1; i>= 0; i--) { final StopwatchTimer t = pool.get(i); long heldTime = batteryRealtime - t.mUpdateTime; if (heldTime > 0) { - t.mTotalTime += heldTime / N; + final long myTime = heldTime / N; + if (t == self) { + selfTime = myTime; + } + t.mTotalTime += myTime; } t.mUpdateTime = batteryRealtime; } + return selfTime; } @Override @@ -2368,8 +2389,12 @@ public final class BatteryStatsImpl extends BatteryStats { + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(elapsedRealtime); mMobileRadioActive = active; - if (active) mMobileRadioActiveTimer.startRunningLocked(this, elapsedRealtime); - else mMobileRadioActiveTimer.stopRunningLocked(this, elapsedRealtime); + if (active) { + mMobileRadioActiveTimer.startRunningLocked(this, elapsedRealtime); + } else { + updateNetworkActivityLocked(NET_UPDATE_MOBILE, elapsedRealtime); + mMobileRadioActiveTimer.stopRunningLocked(this, elapsedRealtime); + } } } } catch (NumberFormatException e) { @@ -3006,7 +3031,7 @@ public final class BatteryStatsImpl extends BatteryStats { // During device boot, qtaguid isn't enabled until after the inital // loading of battery stats. Now that they're enabled, take our initial // snapshot for future delta calculation. - updateNetworkActivityLocked(); + updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime()); } @Override public long getScreenOnTime(long batteryRealtime, int which) { @@ -3057,6 +3082,18 @@ public final class BatteryStatsImpl extends BatteryStats { return mMobileRadioActiveTimer.getTotalTimeLocked(batteryRealtime, which); } + @Override public int getMobileRadioActiveCount(int which) { + return mMobileRadioActiveTimer.getCountLocked(which); + } + + @Override public long getMobileRadioActiveUnknownTime(int which) { + return mMobileRadioActiveUnknownTime.getCountLocked(which); + } + + @Override public int getMobileRadioActiveUnknownCount(int which) { + return (int)mMobileRadioActiveUnknownCount.getCountLocked(which); + } + @Override public long getWifiOnTime(long batteryRealtime, int which) { return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which); } @@ -3156,6 +3193,8 @@ public final class BatteryStatsImpl extends BatteryStats { LongSamplingCounter[] mNetworkByteActivityCounters; LongSamplingCounter[] mNetworkPacketActivityCounters; + LongSamplingCounter mMobileRadioActiveTime; + LongSamplingCounter mMobileRadioActiveCount; /** * The statistics we have collected for this uid's wake locks. @@ -3556,6 +3595,14 @@ public final class BatteryStatsImpl extends BatteryStats { } } + void noteMobileRadioActiveTimeLocked(long batteryUptime) { + if (mNetworkByteActivityCounters == null) { + initNetworkActivityLocked(); + } + mMobileRadioActiveTime.addCountLocked(batteryUptime); + mMobileRadioActiveCount.addCountLocked(1); + } + @Override public boolean hasNetworkActivity() { return mNetworkByteActivityCounters != null; @@ -3581,6 +3628,18 @@ public final class BatteryStatsImpl extends BatteryStats { } } + @Override + public long getMobileRadioActiveTime(int which) { + return mMobileRadioActiveTime != null + ? mMobileRadioActiveTime.getCountLocked(which) : 0; + } + + @Override + public int getMobileRadioActiveCount(int which) { + return mMobileRadioActiveCount != null + ? (int)mMobileRadioActiveCount.getCountLocked(which) : 0; + } + void initNetworkActivityLocked() { mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES]; mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES]; @@ -3588,6 +3647,8 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkByteActivityCounters[i] = new LongSamplingCounter(mUnpluggables); mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables); } + mMobileRadioActiveTime = new LongSamplingCounter(mUnpluggables); + mMobileRadioActiveCount = new LongSamplingCounter(mUnpluggables); } /** @@ -3652,6 +3713,8 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkByteActivityCounters[i].reset(false); mNetworkPacketActivityCounters[i].reset(false); } + mMobileRadioActiveTime.reset(false); + mMobileRadioActiveCount.reset(false); } if (mWakelockStats.size() > 0) { @@ -3859,6 +3922,8 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkByteActivityCounters[i].writeToParcel(out); mNetworkPacketActivityCounters[i].writeToParcel(out); } + mMobileRadioActiveTime.writeToParcel(out); + mMobileRadioActiveCount.writeToParcel(out); } else { out.writeInt(0); } @@ -3982,6 +4047,8 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkByteActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in); mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in); } + mMobileRadioActiveTime = new LongSamplingCounter(mUnpluggables, in); + mMobileRadioActiveCount = new LongSamplingCounter(mUnpluggables, in); } else { mNetworkByteActivityCounters = null; mNetworkPacketActivityCounters = null; @@ -5076,6 +5143,8 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables); } mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mUnpluggables); + mMobileRadioActiveUnknownTime = new LongSamplingCounter(mUnpluggables); + mMobileRadioActiveUnknownCount = new LongSamplingCounter(mUnpluggables); mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables); mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables); for (int i=0; i<NUM_WIFI_STATES; i++) { @@ -5342,6 +5411,8 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkPacketActivityCounters[i].reset(false); } mMobileRadioActiveTimer.reset(this, false); + mMobileRadioActiveUnknownTime.reset(false); + mMobileRadioActiveUnknownCount.reset(false); mWifiOnTimer.reset(this, false); mGlobalWifiRunningTimer.reset(this, false); for (int i=0; i<NUM_WIFI_STATES; i++) { @@ -5419,7 +5490,7 @@ public final class BatteryStatsImpl extends BatteryStats { public void pullPendingStateUpdatesLocked() { updateKernelWakelocksLocked(); - updateNetworkActivityLocked(); + updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime()); } void setOnBatteryLocked(boolean onBattery, int oldStatus, int level) { @@ -5604,10 +5675,14 @@ public final class BatteryStatsImpl extends BatteryStats { } } - private void updateNetworkActivityLocked() { + static final int NET_UPDATE_MOBILE = 1<<0; + static final int NET_UPDATE_WIFI = 1<<1; + static final int NET_UPDATE_ALL = 0xffff; + + private void updateNetworkActivityLocked(int which, long elapsedRealtime) { if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return; - if (mMobileIfaces.length > 0) { + if ((which&NET_UPDATE_MOBILE) != 0 && mMobileIfaces.length > 0) { final NetworkStats snapshot; final NetworkStats last = mCurMobileSnapshot; try { @@ -5625,6 +5700,10 @@ public final class BatteryStatsImpl extends BatteryStats { null, null, mTmpNetworkStats); mTmpNetworkStats = delta; + long radioTime = mMobileRadioActiveTimer.checkpointRunningLocked(this, + elapsedRealtime); + long totalPackets = delta.getTotalPackets(); + final int size = delta.size(); for (int i = 0; i < size; i++) { final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry); @@ -5637,6 +5716,17 @@ public final class BatteryStatsImpl extends BatteryStats { u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes, entry.txPackets); + if (radioTime > 0) { + // Distribute total radio active time in to this app. + long appPackets = entry.rxPackets + entry.txPackets; + long appRadioTime = (radioTime*appPackets)/totalPackets; + u.noteMobileRadioActiveTimeLocked(appRadioTime); + // Remove this app from the totals, so that we don't lose any time + // due to rounding. + radioTime -= appRadioTime; + totalPackets -= appPackets; + } + mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(entry.rxBytes); mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(entry.txBytes); mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked( @@ -5644,9 +5734,15 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked( entry.txPackets); } + + if (radioTime > 0) { + // Whoops, there is some radio time we can't blame on an app! + mMobileRadioActiveUnknownTime.addCountLocked(radioTime); + mMobileRadioActiveUnknownCount.addCountLocked(1); + } } - if (mWifiIfaces.length > 0) { + if ((which&NET_UPDATE_WIFI) != 0 && mWifiIfaces.length > 0) { final NetworkStats snapshot; final NetworkStats last = mCurWifiSnapshot; try { @@ -6275,6 +6371,8 @@ public final class BatteryStatsImpl extends BatteryStats { } mMobileRadioActive = false; mMobileRadioActiveTimer.readSummaryFromParcelLocked(in); + mMobileRadioActiveUnknownTime.readSummaryFromParcelLocked(in); + mMobileRadioActiveUnknownCount.readSummaryFromParcelLocked(in); mWifiOn = false; mWifiOnTimer.readSummaryFromParcelLocked(in); mGlobalWifiRunning = false; @@ -6370,6 +6468,8 @@ public final class BatteryStatsImpl extends BatteryStats { u.mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in); u.mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in); } + u.mMobileRadioActiveTime.readSummaryFromParcelLocked(in); + u.mMobileRadioActiveCount.readSummaryFromParcelLocked(in); } int NW = in.readInt(); @@ -6506,6 +6606,8 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out); } mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL); + mMobileRadioActiveUnknownTime.writeSummaryFromParcelLocked(out); + mMobileRadioActiveUnknownCount.writeSummaryFromParcelLocked(out); mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL); for (int i=0; i<NUM_WIFI_STATES; i++) { @@ -6609,6 +6711,8 @@ public final class BatteryStatsImpl extends BatteryStats { u.mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out); u.mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out); } + u.mMobileRadioActiveTime.writeSummaryFromParcelLocked(out); + u.mMobileRadioActiveCount.writeSummaryFromParcelLocked(out); } int NW = u.mWakelockStats.size(); @@ -6748,6 +6852,8 @@ public final class BatteryStatsImpl extends BatteryStats { } mMobileRadioActive = false; mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mUnpluggables, in); + mMobileRadioActiveUnknownTime = new LongSamplingCounter(mUnpluggables, in); + mMobileRadioActiveUnknownCount = new LongSamplingCounter(mUnpluggables, in); mWifiOn = false; mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in); mGlobalWifiRunning = false; @@ -6865,6 +6971,8 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkPacketActivityCounters[i].writeToParcel(out); } mMobileRadioActiveTimer.writeToParcel(out, batteryRealtime); + mMobileRadioActiveUnknownTime.writeToParcel(out); + mMobileRadioActiveUnknownCount.writeToParcel(out); mWifiOnTimer.writeToParcel(out, batteryRealtime); mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime); for (int i=0; i<NUM_WIFI_STATES; i++) { diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 0ebbd8a..cb5946a 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -656,6 +656,7 @@ public final class BatteryService extends Binder { long ident = Binder.clearCallingIdentity(); try { if (mUpdatesStopped) { + mUpdatesStopped = false; mBatteryProps.set(mLastBatteryProps); processValuesLocked(); } diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 95bfd2f..e43dea9 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -154,7 +154,7 @@ public class SyncManager { private static final int INITIALIZATION_UNBIND_DELAY_MS = 5000; - private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*"; + private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*/"; private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm"; private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock"; @@ -1210,9 +1210,9 @@ public class SyncManager { mBound = false; } else { try { - mEventName = serviceComponent.flattenToShortString(); + mEventName = mSyncOperation.wakeLockName(); mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_SYNC_START, - serviceComponent.flattenToShortString(), mSyncAdapterUid); + mEventName, mSyncAdapterUid); } catch (RemoteException e) { } } @@ -1927,10 +1927,10 @@ public class SyncManager { } private PowerManager.WakeLock getSyncWakeLock(SyncOperation operation) { - final String wakeLockKey = operation.wakeLockKey(); + final String wakeLockKey = operation.wakeLockName(); PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey); if (wakeLock == null) { - final String name = SYNC_WAKE_LOCK_PREFIX + operation.wakeLockName(); + final String name = SYNC_WAKE_LOCK_PREFIX + wakeLockKey; wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name); wakeLock.setReferenceCounted(false); mWakeLocks.put(wakeLockKey, wakeLock); diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java index 036b21f..5233014 100644 --- a/services/core/java/com/android/server/content/SyncOperation.java +++ b/services/core/java/com/android/server/content/SyncOperation.java @@ -86,6 +86,9 @@ public class SyncOperation implements Comparable { /** Amount of time before {@link #effectiveRunTime} from which this sync can run. */ public long flexTime; + /** Descriptive string key for this operation */ + public String wakeLockName; + public SyncOperation(Account account, int userId, int reason, int source, String provider, Bundle extras, long runTimeFromNow, long flexTime, long backoff, long delayUntil, boolean allowParallelSyncs) { @@ -308,25 +311,17 @@ public class SyncOperation implements Comparable { sb.append("]"); } - public String wakeLockKey() { - if (target.target_provider) { - return target.account.name + "/" + target.account.type + ":" + target.provider; - } else if (target.target_service) { - return target.service.getPackageName() + "/" + target.service.getClassName(); - } else { - Log.wtf(TAG, "Invalid target getting wakelock for operation - " + key); - return null; - } - } - public String wakeLockName() { + if (wakeLockName != null) { + return wakeLockName; + } if (target.target_provider) { - return "/" + target.provider + return (wakeLockName = target.provider + "/" + target.account.type - + "/" + target.account.name; + + "/" + target.account.name); } else if (target.target_service) { - return "/" + target.service.getPackageName() - + "/" + target.service.getClassName(); + return (wakeLockName = target.service.getPackageName() + + "/" + target.service.getClassName()); } else { Log.wtf(TAG, "Invalid target getting wakelock name for operation - " + key); return null; |