diff options
17 files changed, 657 insertions, 1402 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 3051926..508fdee 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -269,15 +269,6 @@ public abstract class BatteryStats implements Parcelable { public abstract long getTotalTimeLocked(long elapsedRealtimeUs, int which); /** - * Returns the total time in microseconds associated with this Timer since the - * 'mark' was last set. - * - * @param elapsedRealtimeUs current elapsed realtime of system in microseconds - * @return a time in microseconds - */ - public abstract long getTimeSinceMarkLocked(long elapsedRealtimeUs); - - /** * Temporary for debugging. */ public abstract void logState(Printer pw, String prefix); @@ -341,17 +332,7 @@ public abstract class BatteryStats implements Parcelable { * @return a Map from Strings to Uid.Pkg objects. */ public abstract ArrayMap<String, ? extends Pkg> getPackageStats(); - - /** - * Returns the time in milliseconds that this app kept the WiFi controller in the - * specified state <code>type</code>. - * @param type one of {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, or - * {@link #CONTROLLER_TX_TIME}. - * @param which one of {@link #STATS_CURRENT}, {@link #STATS_SINCE_CHARGED}, or - * {@link #STATS_SINCE_UNPLUGGED}. - */ - public abstract long getWifiControllerActivity(int type, int which); - + /** * {@hide} */ @@ -1933,6 +1914,7 @@ public abstract class BatteryStats implements Parcelable { public static final int NETWORK_MOBILE_TX_DATA = 1; public static final int NETWORK_WIFI_RX_DATA = 2; public static final int NETWORK_WIFI_TX_DATA = 3; + public static final int NUM_NETWORK_ACTIVITY_TYPES = NETWORK_WIFI_TX_DATA + 1; public abstract long getNetworkActivityBytes(int type, int which); @@ -1941,25 +1923,10 @@ public abstract class BatteryStats implements Parcelable { public static final int CONTROLLER_IDLE_TIME = 0; public static final int CONTROLLER_RX_TIME = 1; public static final int CONTROLLER_TX_TIME = 2; - public static final int CONTROLLER_POWER_DRAIN = 3; - public static final int NUM_CONTROLLER_ACTIVITY_TYPES = CONTROLLER_POWER_DRAIN + 1; + public static final int CONTROLLER_ENERGY = 3; + public static final int NUM_CONTROLLER_ACTIVITY_TYPES = CONTROLLER_ENERGY + 1; - /** - * For {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, and - * {@link #CONTROLLER_TX_TIME}, returns the time spent (in milliseconds) in the - * respective state. - * For {@link #CONTROLLER_POWER_DRAIN}, returns the power used by the controller in - * milli-ampere-milliseconds (mAms). - */ public abstract long getBluetoothControllerActivity(int type, int which); - - /** - * For {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, and - * {@link #CONTROLLER_TX_TIME}, returns the time spent (in milliseconds) in the - * respective state. - * For {@link #CONTROLLER_POWER_DRAIN}, returns the power used by the controller in - * milli-ampere-milliseconds (mAms). - */ public abstract long getWifiControllerActivity(int type, int which); /** @@ -2651,7 +2618,7 @@ public abstract class BatteryStats implements Parcelable { label = "???"; } dumpLine(pw, uid, category, POWER_USE_ITEM_DATA, label, - BatteryStatsHelper.makemAh(bs.totalPowerMah)); + BatteryStatsHelper.makemAh(bs.value)); } } @@ -3297,13 +3264,6 @@ public abstract class BatteryStats implements Parcelable { sb.setLength(0); sb.append(prefix); - sb.append(" WiFi Energy use: ").append(BatteryStatsHelper.makemAh( - getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which) / (double)(1000*60*60))); - sb.append(" mAh"); - pw.println(sb.toString()); - - sb.setLength(0); - sb.append(prefix); sb.append(" Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000); sb.append("("); sb.append(formatRatioLocked(bluetoothOnTime, whichBatteryRealtime)); sb.append(")"); @@ -3416,48 +3376,48 @@ public abstract class BatteryStats implements Parcelable { final BatterySipper bs = sippers.get(i); switch (bs.drainType) { case IDLE: - pw.print(prefix); pw.print(" Idle: "); printmAh(pw, bs.totalPowerMah); + pw.print(prefix); pw.print(" Idle: "); printmAh(pw, bs.value); pw.println(); break; case CELL: - pw.print(prefix); pw.print(" Cell standby: "); printmAh(pw, bs.totalPowerMah); + pw.print(prefix); pw.print(" Cell standby: "); printmAh(pw, bs.value); pw.println(); break; case PHONE: - pw.print(prefix); pw.print(" Phone calls: "); printmAh(pw, bs.totalPowerMah); + pw.print(prefix); pw.print(" Phone calls: "); printmAh(pw, bs.value); pw.println(); break; case WIFI: - pw.print(prefix); pw.print(" Wifi: "); printmAh(pw, bs.totalPowerMah); + pw.print(prefix); pw.print(" Wifi: "); printmAh(pw, bs.value); pw.println(); break; case BLUETOOTH: - pw.print(prefix); pw.print(" Bluetooth: "); printmAh(pw, bs.totalPowerMah); + pw.print(prefix); pw.print(" Bluetooth: "); printmAh(pw, bs.value); pw.println(); break; case SCREEN: - pw.print(prefix); pw.print(" Screen: "); printmAh(pw, bs.totalPowerMah); + pw.print(prefix); pw.print(" Screen: "); printmAh(pw, bs.value); pw.println(); break; case FLASHLIGHT: - pw.print(prefix); pw.print(" Flashlight: "); printmAh(pw, bs.totalPowerMah); + pw.print(prefix); pw.print(" Flashlight: "); printmAh(pw, bs.value); pw.println(); break; case APP: pw.print(prefix); pw.print(" Uid "); UserHandle.formatUid(pw, bs.uidObj.getUid()); - pw.print(": "); printmAh(pw, bs.totalPowerMah); pw.println(); + pw.print(": "); printmAh(pw, bs.value); pw.println(); break; case USER: pw.print(prefix); pw.print(" User "); pw.print(bs.userId); - pw.print(": "); printmAh(pw, bs.totalPowerMah); pw.println(); + pw.print(": "); printmAh(pw, bs.value); pw.println(); break; case UNACCOUNTED: - pw.print(prefix); pw.print(" Unaccounted: "); printmAh(pw, bs.totalPowerMah); + pw.print(prefix); pw.print(" Unaccounted: "); printmAh(pw, bs.value); pw.println(); break; case OVERCOUNTED: - pw.print(prefix); pw.print(" Over-counted: "); printmAh(pw, bs.totalPowerMah); + pw.print(prefix); pw.print(" Over-counted: "); printmAh(pw, bs.value); pw.println(); break; } diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 1746bed..bea4ece 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -109,7 +109,6 @@ interface IBatteryStats { void noteWifiBatchedScanStoppedFromSource(in WorkSource ws); void noteWifiMulticastEnabledFromSource(in WorkSource ws); void noteWifiMulticastDisabledFromSource(in WorkSource ws); - void noteWifiRadioPowerState(int powerState, long timestampNs); void noteNetworkInterfaceType(String iface, int type); void noteNetworkStatsEnabled(); void noteDeviceIdleMode(boolean enabled, boolean fromActive, boolean fromMotion); diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java index 056b0aa..4cd959f 100644 --- a/core/java/com/android/internal/os/BatterySipper.java +++ b/core/java/com/android/internal/os/BatterySipper.java @@ -23,25 +23,17 @@ import android.os.BatteryStats.Uid; public class BatterySipper implements Comparable<BatterySipper> { public int userId; public Uid uidObj; - public double totalPowerMah; + public double value; + public double[] values; public DrainType drainType; - /** - * Generic usage time in milliseconds. - */ - public long usageTimeMs; - - /** - * Generic power usage in mAh. - */ - public double usagePowerMah; - - // Subsystem usage times. - public long cpuTimeMs; - public long gpsTimeMs; - public long wifiRunningTimeMs; - public long cpuFgTimeMs; - public long wakeLockTimeMs; + // Measured in milliseconds. + public long usageTime; + public long cpuTime; + public long gpsTime; + public long wifiRunningTime; + public long cpuFgTime; + public long wakeLockTime; public long mobileRxPackets; public long mobileTxPackets; @@ -60,13 +52,12 @@ public class BatterySipper implements Comparable<BatterySipper> { public String packageWithHighestDrain; // Measured in mAh (milli-ampere per hour). - // These are included when summed. - public double wifiPowerMah; - public double cpuPowerMah; - public double wakeLockPowerMah; - public double mobileRadioPowerMah; - public double gpsPowerMah; - public double sensorPowerMah; + public double wifiPower; + public double cpuPower; + public double wakeLockPower; + public double mobileRadioPower; + public double gpsPower; + public double sensorPower; public enum DrainType { IDLE, @@ -82,12 +73,17 @@ public class BatterySipper implements Comparable<BatterySipper> { OVERCOUNTED } - public BatterySipper(DrainType drainType, Uid uid, double value) { - this.totalPowerMah = value; + public BatterySipper(DrainType drainType, Uid uid, double[] values) { + this.values = values; + if (values != null) value = values[0]; this.drainType = drainType; uidObj = uid; } + public double[] getValues() { + return values; + } + public void computeMobilemspp() { long packets = mobileRxPackets+mobileTxPackets; mobilemspp = packets > 0 ? (mobileActive / (double)packets) : 0; @@ -105,7 +101,7 @@ public class BatterySipper implements Comparable<BatterySipper> { } } // Return the flipped value because we want the items in descending order - return Double.compare(other.totalPowerMah, totalPowerMah); + return Double.compare(other.value, value); } /** @@ -127,14 +123,11 @@ public class BatterySipper implements Comparable<BatterySipper> { * Add stats from other to this BatterySipper. */ public void add(BatterySipper other) { - totalPowerMah += other.totalPowerMah; - usageTimeMs += other.usageTimeMs; - usagePowerMah += other.usagePowerMah; - cpuTimeMs += other.cpuTimeMs; - gpsTimeMs += other.gpsTimeMs; - wifiRunningTimeMs += other.wifiRunningTimeMs; - cpuFgTimeMs += other.cpuFgTimeMs; - wakeLockTimeMs += other.wakeLockTimeMs; + cpuTime += other.cpuTime; + gpsTime += other.gpsTime; + wifiRunningTime += other.wifiRunningTime; + cpuFgTime += other.cpuFgTime; + wakeLockTime += other.wakeLockTime; mobileRxPackets += other.mobileRxPackets; mobileTxPackets += other.mobileTxPackets; mobileActive += other.mobileActive; @@ -145,20 +138,11 @@ public class BatterySipper implements Comparable<BatterySipper> { mobileTxBytes += other.mobileTxBytes; wifiRxBytes += other.wifiRxBytes; wifiTxBytes += other.wifiTxBytes; - wifiPowerMah += other.wifiPowerMah; - gpsPowerMah += other.gpsPowerMah; - cpuPowerMah += other.cpuPowerMah; - sensorPowerMah += other.sensorPowerMah; - mobileRadioPowerMah += other.mobileRadioPowerMah; - wakeLockPowerMah += other.wakeLockPowerMah; - } - - /** - * Sum all the powers and store the value into `value`. - * @return the sum of all the power in this BatterySipper. - */ - public double sumPower() { - return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + sensorPowerMah - + mobileRadioPowerMah + wakeLockPowerMah; + wifiPower += other.wifiPower; + gpsPower += other.gpsPower; + cpuPower += other.cpuPower; + sensorPower += other.sensorPower; + mobileRadioPower += other.mobileRadioPower; + wakeLockPower += other.wakeLockPower; } } diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index 024b7c5..d3611bf 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -16,12 +16,17 @@ package com.android.internal.os; +import static android.os.BatteryStats.NETWORK_MOBILE_RX_DATA; +import static android.os.BatteryStats.NETWORK_MOBILE_TX_DATA; +import static android.os.BatteryStats.NETWORK_WIFI_RX_DATA; +import static android.os.BatteryStats.NETWORK_WIFI_TX_DATA; + import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.hardware.Sensor; import android.hardware.SensorManager; import android.net.ConnectivityManager; -import android.net.wifi.WifiManager; import android.os.BatteryStats; import android.os.BatteryStats.Uid; import android.os.Bundle; @@ -33,6 +38,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; +import android.telephony.SignalStrength; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; @@ -48,6 +54,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; /** * A helper class for retrieving the power usage information for all applications and services. @@ -56,7 +63,8 @@ import java.util.List; * onAttach() for Fragment), call create() in onCreate() and call destroy() in onDestroy(). */ public final class BatteryStatsHelper { - static final boolean DEBUG = false; + + private static final boolean DEBUG = false; private static final String TAG = BatteryStatsHelper.class.getSimpleName(); @@ -73,24 +81,14 @@ public final class BatteryStatsHelper { private Intent mBatteryBroadcast; private PowerProfile mPowerProfile; - /** - * List of apps using power. - */ - private final List<BatterySipper> mUsageList = new ArrayList<>(); - - /** - * List of apps using wifi power. - */ - private final List<BatterySipper> mWifiSippers = new ArrayList<>(); - - /** - * List of apps using bluetooth power. - */ - private final List<BatterySipper> mBluetoothSippers = new ArrayList<>(); - - private final SparseArray<List<BatterySipper>> mUserSippers = new SparseArray<>(); + private final List<BatterySipper> mUsageList = new ArrayList<BatterySipper>(); + private final List<BatterySipper> mWifiSippers = new ArrayList<BatterySipper>(); + private final List<BatterySipper> mBluetoothSippers = new ArrayList<BatterySipper>(); + private final SparseArray<List<BatterySipper>> mUserSippers + = new SparseArray<List<BatterySipper>>(); + private final SparseArray<Double> mUserPower = new SparseArray<Double>(); - private final List<BatterySipper> mMobilemsppList = new ArrayList<>(); + private final List<BatterySipper> mMobilemsppList = new ArrayList<BatterySipper>(); private int mStatsType = BatteryStats.STATS_SINCE_CHARGED; @@ -104,50 +102,29 @@ public final class BatteryStatsHelper { long mChargeTimeRemaining; private long mStatsPeriod = 0; - - // The largest entry by power. private double mMaxPower = 1; - - // The largest real entry by power (not undercounted or overcounted). private double mMaxRealPower = 1; - - // Total computed power. private double mComputedPower; private double mTotalPower; + private double mWifiPower; + private double mBluetoothPower; private double mMinDrainedPower; private double mMaxDrainedPower; - PowerCalculator mCpuPowerCalculator; - PowerCalculator mWakelockPowerCalculator; - MobileRadioPowerCalculator mMobileRadioPowerCalculator; - PowerCalculator mWifiPowerCalculator; - PowerCalculator mBluetoothPowerCalculator; - PowerCalculator mSensorPowerCalculator; - - public static boolean checkWifiOnly(Context context) { - ConnectivityManager cm = (ConnectivityManager)context.getSystemService( - Context.CONNECTIVITY_SERVICE); - return !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); - } + // How much the apps together have kept the mobile radio active. + private long mAppMobileActive; - public static boolean checkHasWifiPowerReporting(Context context, PowerProfile profile) { - WifiManager manager = context.getSystemService(WifiManager.class); - if (manager.isEnhancedPowerReportingSupported()) { - if (profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE) != 0 && - profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX) != 0 && - profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX) != 0) { - return true; - } - } - return false; - } + // How much the apps together have left WIFI running. + private long mAppWifiRunning; public BatteryStatsHelper(Context context) { this(context, true); } public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast) { - this(context, collectBatteryBroadcast, checkWifiOnly(context)); + mContext = context; + mCollectBatteryBroadcast = collectBatteryBroadcast; + mWifiOnly = checkWifiOnly(context); } public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast, boolean wifiOnly) { @@ -156,6 +133,12 @@ public final class BatteryStatsHelper { mWifiOnly = wifiOnly; } + public static boolean checkWifiOnly(Context context) { + ConnectivityManager cm = (ConnectivityManager)context.getSystemService( + Context.CONNECTIVITY_SERVICE); + return !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + } + public void storeStatsHistoryInFile(String fname) { synchronized (sFileXfer) { File path = makeFilePath(mContext, fname); @@ -277,7 +260,7 @@ public final class BatteryStatsHelper { * Refreshes the power usage list. */ public void refreshStats(int statsType, int asUser) { - SparseArray<UserHandle> users = new SparseArray<>(1); + SparseArray<UserHandle> users = new SparseArray<UserHandle>(1); users.put(asUser, new UserHandle(asUser)); refreshStats(statsType, users); } @@ -287,7 +270,7 @@ public final class BatteryStatsHelper { */ public void refreshStats(int statsType, List<UserHandle> asUsers) { final int n = asUsers.size(); - SparseArray<UserHandle> users = new SparseArray<>(n); + SparseArray<UserHandle> users = new SparseArray<UserHandle>(n); for (int i = 0; i < n; ++i) { UserHandle userHandle = asUsers.get(i); users.put(userHandle.getIdentifier(), userHandle); @@ -312,52 +295,22 @@ public final class BatteryStatsHelper { 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; } - if (mCpuPowerCalculator == null) { - mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile); - } - mCpuPowerCalculator.reset(); - - if (mWakelockPowerCalculator == null) { - mWakelockPowerCalculator = new WakelockPowerCalculator(mPowerProfile); - } - mWakelockPowerCalculator.reset(); - - if (mMobileRadioPowerCalculator == null) { - mMobileRadioPowerCalculator = new MobileRadioPowerCalculator(mPowerProfile, mStats); - } - mMobileRadioPowerCalculator.reset(mStats); - - if (mWifiPowerCalculator == null) { - if (checkHasWifiPowerReporting(mContext, mPowerProfile)) { - mWifiPowerCalculator = new WifiPowerCalculator(mPowerProfile); - } else { - mWifiPowerCalculator = new WifiPowerEstimator(mPowerProfile); - } - } - mWifiPowerCalculator.reset(); - - if (mBluetoothPowerCalculator == null) { - mBluetoothPowerCalculator = new BluetoothPowerCalculator(); - } - mBluetoothPowerCalculator.reset(); - - if (mSensorPowerCalculator == null) { - mSensorPowerCalculator = new SensorPowerCalculator(mPowerProfile, - (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE)); - } - mSensorPowerCalculator.reset(); - mStatsType = statsType; mRawUptime = rawUptimeUs; mRawRealtime = rawRealtimeUs; @@ -405,113 +358,383 @@ public final class BatteryStatsHelper { Collections.sort(mMobilemsppList, new Comparator<BatterySipper>() { @Override public int compare(BatterySipper lhs, BatterySipper rhs) { - return Double.compare(rhs.mobilemspp, lhs.mobilemspp); + if (lhs.mobilemspp < rhs.mobilemspp) { + return 1; + } else if (lhs.mobilemspp > rhs.mobilemspp) { + return -1; + } + return 0; } }); processMiscUsage(); - Collections.sort(mUsageList); - - // At this point, we've sorted the list so we are guaranteed the max values are at the top. - // We have only added real powers so far. - if (!mUsageList.isEmpty()) { - mMaxRealPower = mMaxPower = mUsageList.get(0).totalPowerMah; - final int usageListCount = mUsageList.size(); - for (int i = 0; i < usageListCount; i++) { - mComputedPower += mUsageList.get(i).totalPowerMah; - } - } - if (DEBUG) { Log.d(TAG, "Accuracy: total computed=" + makemAh(mComputedPower) + ", min discharge=" + makemAh(mMinDrainedPower) + ", max discharge=" + makemAh(mMaxDrainedPower)); } - mTotalPower = mComputedPower; if (mStats.getLowDischargeAmountSinceCharge() > 1) { if (mMinDrainedPower > mComputedPower) { double amount = mMinDrainedPower - mComputedPower; mTotalPower = mMinDrainedPower; - BatterySipper bs = new BatterySipper(DrainType.UNACCOUNTED, null, amount); - - // Insert the BatterySipper in its sorted position. - int index = Collections.binarySearch(mUsageList, bs); - if (index < 0) { - index = -(index + 1); - } - mUsageList.add(index, bs); - mMaxPower = Math.max(mMaxPower, amount); + addEntryNoTotal(BatterySipper.DrainType.UNACCOUNTED, 0, amount); } else if (mMaxDrainedPower < mComputedPower) { double amount = mComputedPower - mMaxDrainedPower; - - // Insert the BatterySipper in its sorted position. - BatterySipper bs = new BatterySipper(DrainType.OVERCOUNTED, null, amount); - int index = Collections.binarySearch(mUsageList, bs); - if (index < 0) { - index = -(index + 1); - } - mUsageList.add(index, bs); - mMaxPower = Math.max(mMaxPower, amount); + addEntryNoTotal(BatterySipper.DrainType.OVERCOUNTED, 0, amount); } } + + Collections.sort(mUsageList); } private void processAppUsage(SparseArray<UserHandle> asUsers) { final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null); + final SensorManager sensorManager = + (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); + final int which = mStatsType; + final int speedSteps = mPowerProfile.getNumSpeedSteps(); + final double[] powerCpuNormal = new double[speedSteps]; + final long[] cpuSpeedStepTimes = new long[speedSteps]; + for (int p = 0; p < speedSteps; p++) { + powerCpuNormal[p] = mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p); + } + final double mobilePowerPerPacket = getMobilePowerPerPacket(); + final double mobilePowerPerMs = getMobilePowerPerMs(); + final double wifiPowerPerPacket = getWifiPowerPerPacket(); + long totalAppWakelockTimeUs = 0; + BatterySipper osApp = null; mStatsPeriod = mTypeBatteryRealtime; + final ArrayList<BatterySipper> appList = new ArrayList<>(); + + // Max values used to normalize later. + double maxWifiPower = 0; + double maxCpuPower = 0; + double maxWakeLockPower = 0; + double maxMobileRadioPower = 0; + double maxGpsPower = 0; + double maxSensorPower = 0; + final SparseArray<? extends Uid> uidStats = mStats.getUidStats(); final int NU = uidStats.size(); for (int iu = 0; iu < NU; iu++) { final Uid u = uidStats.valueAt(iu); - final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0); - - mCpuPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); - mWakelockPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); - mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); - mWifiPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); - mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); - mSensorPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); - - final double totalPower = app.sumPower(); - if (DEBUG && totalPower != 0) { - Log.d(TAG, String.format("UID %d: total power=%s", u.getUid(), - makemAh(totalPower))); + final BatterySipper app = new BatterySipper( + BatterySipper.DrainType.APP, u, new double[]{0}); + + final Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); + if (processStats.size() > 0) { + // Process CPU time. + + // Keep track of the package with highest drain. + double highestDrain = 0; + + for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent + : processStats.entrySet()) { + Uid.Proc ps = ent.getValue(); + app.cpuFgTime += ps.getForegroundTime(which); + final long totalCpuTime = ps.getUserTime(which) + ps.getSystemTime(which); + app.cpuTime += totalCpuTime; + + // Calculate the total CPU time spent at the various speed steps. + long totalTimeAtSpeeds = 0; + for (int step = 0; step < speedSteps; step++) { + cpuSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, which); + totalTimeAtSpeeds += cpuSpeedStepTimes[step]; + } + totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1); + + // Then compute the ratio of time spent at each speed and figure out + // the total power consumption. + double cpuPower = 0; + for (int step = 0; step < speedSteps; step++) { + final double ratio = (double) cpuSpeedStepTimes[step] / totalTimeAtSpeeds; + final double cpuSpeedStepPower = + ratio * totalCpuTime * powerCpuNormal[step]; + if (DEBUG && ratio != 0) { + Log.d(TAG, "UID " + u.getUid() + ": CPU step #" + + step + " ratio=" + makemAh(ratio) + " power=" + + makemAh(cpuSpeedStepPower / (60 * 60 * 1000))); + } + cpuPower += cpuSpeedStepPower; + } + + if (DEBUG && cpuPower != 0) { + Log.d(TAG, String.format("process %s, cpu power=%s", + ent.getKey(), makemAh(cpuPower / (60 * 60 * 1000)))); + } + app.cpuPower += cpuPower; + + // Each App can have multiple packages and with multiple running processes. + // Keep track of the package who's process has the highest drain. + if (app.packageWithHighestDrain == null || + app.packageWithHighestDrain.startsWith("*")) { + highestDrain = cpuPower; + app.packageWithHighestDrain = ent.getKey(); + } else if (highestDrain < cpuPower && !ent.getKey().startsWith("*")) { + highestDrain = cpuPower; + app.packageWithHighestDrain = ent.getKey(); + } + } + } + + // Ensure that the CPU times make sense. + if (app.cpuFgTime > app.cpuTime) { + if (DEBUG && app.cpuFgTime > app.cpuTime + 10000) { + Log.d(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time"); + } + + // Statistics may not have been gathered yet. + app.cpuTime = app.cpuFgTime; + } + + // Convert the CPU power to mAh + app.cpuPower /= (60 * 60 * 1000); + maxCpuPower = Math.max(maxCpuPower, app.cpuPower); + + // Process wake lock usage + final Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = + u.getWakelockStats(); + long wakeLockTimeUs = 0; + for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> wakelockEntry + : wakelockStats.entrySet()) { + final 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) { + wakeLockTimeUs += timer.getTotalTimeLocked(mRawRealtime, which); + } + } + app.wakeLockTime = wakeLockTimeUs / 1000; // convert to millis + totalAppWakelockTimeUs += wakeLockTimeUs; + + // Add cost of holding a wake lock. + app.wakeLockPower = (app.wakeLockTime * + mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60 * 60 * 1000); + if (DEBUG && app.wakeLockPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wake " + + app.wakeLockTime + " power=" + makemAh(app.wakeLockPower)); + } + maxWakeLockPower = Math.max(maxWakeLockPower, app.wakeLockPower); + + // Add cost of mobile traffic. + final long mobileActive = u.getMobileRadioActiveTime(mStatsType); + app.mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType); + app.mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType); + app.mobileActive = mobileActive / 1000; + app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType); + app.mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType); + app.mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType); + + if (mobileActive > 0) { + // We are tracking when the radio is up, so can use the active time to + // determine power use. + mAppMobileActive += mobileActive; + app.mobileRadioPower = (mobilePowerPerMs * mobileActive) / 1000; + } else { + // We are not tracking when the radio is up, so must approximate power use + // based on the number of packets. + app.mobileRadioPower = (app.mobileRxPackets + app.mobileTxPackets) + * mobilePowerPerPacket; + } + if (DEBUG && app.mobileRadioPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": mobile packets " + + (app.mobileRxPackets + app.mobileTxPackets) + + " active time " + mobileActive + + " power=" + makemAh(app.mobileRadioPower)); + } + maxMobileRadioPower = Math.max(maxMobileRadioPower, app.mobileRadioPower); + + // Add cost of wifi traffic + app.wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType); + app.wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType); + app.wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType); + app.wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType); + + final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets) + * wifiPowerPerPacket; + if (DEBUG && wifiPacketPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wifi packets " + + (app.wifiRxPackets + app.wifiTxPackets) + + " power=" + makemAh(wifiPacketPower)); + } + + // Add cost of keeping WIFI running. + app.wifiRunningTime = u.getWifiRunningTime(mRawRealtime, which) / 1000; + mAppWifiRunning += app.wifiRunningTime; + + final double wifiLockPower = (app.wifiRunningTime + * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60 * 60 * 1000); + if (DEBUG && wifiLockPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wifi running " + + app.wifiRunningTime + " power=" + makemAh(wifiLockPower)); + } + + // Add cost of WIFI scans + final long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000; + final double wifiScanPower = (wifiScanTimeMs + * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN)) + / (60 * 60 * 1000); + if (DEBUG && wifiScanPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs + + " power=" + makemAh(wifiScanPower)); + } + + // Add cost of WIFI batch scans. + double wifiBatchScanPower = 0; + for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) { + final long batchScanTimeMs = + u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000; + final double batchScanPower = ((batchScanTimeMs + * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin)) + ) / (60 * 60 * 1000); + if (DEBUG && batchScanPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wifi batched scan # " + bin + + " time=" + batchScanTimeMs + " power=" + makemAh(batchScanPower)); + } + wifiBatchScanPower += batchScanPower; + } + + // Add up all the WiFi costs. + app.wifiPower = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower; + maxWifiPower = Math.max(maxWifiPower, app.wifiPower); + + // Process Sensor usage + final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats(); + final int NSE = sensorStats.size(); + for (int ise = 0; ise < NSE; ise++) { + final Uid.Sensor sensor = sensorStats.valueAt(ise); + final int sensorHandle = sensorStats.keyAt(ise); + final BatteryStats.Timer timer = sensor.getSensorTime(); + final long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000; + double sensorPower = 0; + switch (sensorHandle) { + case Uid.Sensor.GPS: + app.gpsTime = sensorTime; + app.gpsPower = (app.gpsTime + * mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON)) + / (60 * 60 * 1000); + sensorPower = app.gpsPower; + maxGpsPower = Math.max(maxGpsPower, app.gpsPower); + break; + default: + List<Sensor> sensorList = sensorManager.getSensorList( + android.hardware.Sensor.TYPE_ALL); + for (android.hardware.Sensor s : sensorList) { + if (s.getHandle() == sensorHandle) { + sensorPower = (sensorTime * s.getPower()) / (60 * 60 * 1000); + app.sensorPower += sensorPower; + break; + } + } + } + if (DEBUG && sensorPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": sensor #" + sensorHandle + + " time=" + sensorTime + " power=" + makemAh(sensorPower)); + } + } + maxSensorPower = Math.max(maxSensorPower, app.sensorPower); + + final double totalUnnormalizedPower = app.cpuPower + app.wifiPower + app.wakeLockPower + + app.mobileRadioPower + app.gpsPower + app.sensorPower; + if (DEBUG && totalUnnormalizedPower != 0) { + Log.d(TAG, String.format("UID %d: total power=%s", + u.getUid(), makemAh(totalUnnormalizedPower))); } // Add the app to the list if it is consuming power. - if (totalPower != 0 || u.getUid() == 0) { - // - // Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list. - // - final int uid = app.getUid(); - final int userId = UserHandle.getUserId(uid); - if (uid == Process.WIFI_UID) { - mWifiSippers.add(app); - } else if (uid == Process.BLUETOOTH_UID) { - mBluetoothSippers.add(app); - } else if (!forAllUsers && asUsers.get(userId) == null - && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) { - // We are told to just report this user's apps as one large entry. - List<BatterySipper> list = mUserSippers.get(userId); - if (list == null) { - list = new ArrayList<>(); - mUserSippers.put(userId, list); - } - list.add(app); - } else { - mUsageList.add(app); + if (totalUnnormalizedPower != 0 || u.getUid() == 0) { + appList.add(app); + } + } + + // Fetch real power consumption from hardware. + double actualTotalWifiPower = 0.0; + if (mStats.getWifiControllerActivity(BatteryStats.CONTROLLER_ENERGY, mStatsType) != 0) { + final double kDefaultVoltage = 3.36; + final long energy = mStats.getWifiControllerActivity( + BatteryStats.CONTROLLER_ENERGY, mStatsType); + final double voltage = mPowerProfile.getAveragePowerOrDefault( + PowerProfile.OPERATING_VOLTAGE_WIFI, kDefaultVoltage); + actualTotalWifiPower = energy / (voltage * 1000*60*60); + } + + final int appCount = appList.size(); + for (int i = 0; i < appCount; i++) { + // Normalize power where possible. + final BatterySipper app = appList.get(i); + if (actualTotalWifiPower != 0) { + app.wifiPower = (app.wifiPower / maxWifiPower) * actualTotalWifiPower; + } + + // Assign the final power consumption here. + final double power = app.wifiPower + app.cpuPower + app.wakeLockPower + + app.mobileRadioPower + app.gpsPower + app.sensorPower; + app.values[0] = app.value = power; + + // + // Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list. + // + + final int uid = app.getUid(); + final int userId = UserHandle.getUserId(uid); + if (uid == Process.WIFI_UID) { + mWifiSippers.add(app); + mWifiPower += power; + } else if (uid == Process.BLUETOOTH_UID) { + mBluetoothSippers.add(app); + mBluetoothPower += power; + } else if (!forAllUsers && asUsers.get(userId) == null + && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) { + // We are told to just report this user's apps as one large entry. + List<BatterySipper> list = mUserSippers.get(userId); + if (list == null) { + list = new ArrayList<>(); + mUserSippers.put(userId, list); } + list.add(app); - if (uid == 0) { - // The device has probably been awake for longer than the screen on - // time and application wake lock time would account for. Assign - // this remainder to the OS, if possible. - mWakelockPowerCalculator.calculateRemaining(app, mStats, mRawRealtime, - mRawUptime, mStatsType); - app.sumPower(); + Double userPower = mUserPower.get(userId); + if (userPower == null) { + userPower = power; + } else { + userPower += power; } + mUserPower.put(userId, userPower); + } else { + mUsageList.add(app); + if (power > mMaxPower) mMaxPower = power; + if (power > mMaxRealPower) mMaxRealPower = power; + mComputedPower += power; + } + + if (uid == 0) { + osApp = app; + } + } + + // The device has probably been awake for longer than the screen on + // time and application wake lock time would account for. Assign + // this remainder to the OS, if possible. + if (osApp != null) { + long wakeTimeMillis = mBatteryUptime / 1000; + wakeTimeMillis -= (totalAppWakelockTimeUs / 1000) + + (mStats.getScreenOnTime(mRawRealtime, which) / 1000); + if (wakeTimeMillis > 0) { + double power = (wakeTimeMillis + * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) + / (60*60*1000); + if (DEBUG) Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power " + + makemAh(power)); + osApp.wakeLockTime += wakeTimeMillis; + osApp.value += power; + osApp.values[0] += power; + if (osApp.value > mMaxPower) mMaxPower = osApp.value; + if (osApp.value > mMaxRealPower) mMaxRealPower = osApp.value; + mComputedPower += power; } } } @@ -521,7 +744,7 @@ public final 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); } } @@ -550,19 +773,54 @@ public final class BatteryStatsHelper { } private void addRadioUsage() { - BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0); - mMobileRadioPowerCalculator.calculateRemaining(radio, mStats, mRawRealtime, mRawUptime, - mStatsType); - radio.sumPower(); - if (radio.totalPowerMah > 0) { - mUsageList.add(radio); + double power = 0; + final int BINS = SignalStrength.NUM_SIGNAL_STRENGTH_BINS; + long signalTimeMs = 0; + long noCoverageTimeMs = 0; + for (int i = 0; i < BINS; i++) { + long strengthTimeMs = mStats.getPhoneSignalStrengthTime(i, mRawRealtime, mStatsType) + / 1000; + double p = (strengthTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ON, i)) + / (60*60*1000); + if (DEBUG && p != 0) { + Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power=" + + makemAh(p)); + } + power += p; + signalTimeMs += strengthTimeMs; + if (i == 0) { + noCoverageTimeMs = strengthTimeMs; + } + } + long scanningTimeMs = mStats.getPhoneSignalScanningTime(mRawRealtime, mStatsType) + / 1000; + double p = (scanningTimeMs * mPowerProfile.getAveragePower( + PowerProfile.POWER_RADIO_SCANNING)) + / (60*60*1000); + if (DEBUG && p != 0) { + Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + makemAh(p)); + } + power += p; + long radioActiveTimeUs = mStats.getMobileRadioActiveTime(mRawRealtime, 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; + bs.mobileActiveCount = mStats.getMobileRadioActiveUnknownCount(mStatsType); } } private void aggregateSippers(BatterySipper bs, List<BatterySipper> from, String tag) { for (int i=0; i<from.size(); i++) { BatterySipper wbs = from.get(i); - if (DEBUG) Log.d(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTimeMs); + if (DEBUG) Log.d(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTime); bs.add(wbs); } bs.computeMobilemspp(); @@ -589,12 +847,41 @@ public final class BatteryStatsHelper { * of WiFi to the WiFi subsystem. */ private void addWiFiUsage() { - BatterySipper bs = new BatterySipper(DrainType.WIFI, null, 0); - mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime, mStatsType); - bs.sumPower(); - if (bs.totalPowerMah > 0 || !mWifiSippers.isEmpty()) { + final long idleTimeMs = mStats.getWifiControllerActivity( + BatteryStats.CONTROLLER_IDLE_TIME, mStatsType); + final long txTimeMs = mStats.getWifiControllerActivity( + BatteryStats.CONTROLLER_TX_TIME, mStatsType); + final long rxTimeMs = mStats.getWifiControllerActivity( + BatteryStats.CONTROLLER_RX_TIME, mStatsType); + final long energy = mStats.getWifiControllerActivity( + BatteryStats.CONTROLLER_ENERGY, mStatsType); + final long totalTimeRunning = idleTimeMs + txTimeMs + rxTimeMs; + + double powerDrain = 0; + if (energy == 0 && totalTimeRunning > 0) { + // Energy is not reported, which means we may have left over power drain not attributed + // to any app. Assign this power to the WiFi app. + // TODO(adamlesinski): This mimics the old behavior. However, mAppWifiRunningTime + // is the accumulation of the time each app kept the WiFi chip on. Multiple apps + // can do this at the same time, so these times do not add up to the total time + // the WiFi chip was on. Consider normalizing the time spent running and calculating + // power from that? Normalizing the times will assign a weight to each app which + // should better represent power usage. + powerDrain = ((totalTimeRunning - mAppWifiRunning) + * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000); + } + + if (DEBUG && powerDrain != 0) { + Log.d(TAG, "Wifi active: time=" + (txTimeMs + rxTimeMs) + + " power=" + makemAh(powerDrain)); + } + + // TODO(adamlesinski): mWifiPower is already added as a BatterySipper... + // Are we double counting here? + final double power = mWifiPower + powerDrain; + if (power > 0) { + BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, totalTimeRunning, power); aggregateSippers(bs, mWifiSippers, "WIFI"); - mUsageList.add(bs); } } @@ -603,10 +890,30 @@ public final class BatteryStatsHelper { * Bluetooth Category. */ private void addBluetoothUsage() { - BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0); - mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime, - mStatsType); - if (bs.sumPower() > 0) { + final double kDefaultVoltage = 3.36; + final long idleTimeMs = mStats.getBluetoothControllerActivity( + BatteryStats.CONTROLLER_IDLE_TIME, mStatsType); + final long txTimeMs = mStats.getBluetoothControllerActivity( + BatteryStats.CONTROLLER_TX_TIME, mStatsType); + final long rxTimeMs = mStats.getBluetoothControllerActivity( + BatteryStats.CONTROLLER_RX_TIME, mStatsType); + final long energy = mStats.getBluetoothControllerActivity( + BatteryStats.CONTROLLER_ENERGY, mStatsType); + final double voltage = mPowerProfile.getAveragePowerOrDefault( + PowerProfile.OPERATING_VOLTAGE_BLUETOOTH, kDefaultVoltage); + + // energy is measured in mA * V * ms, and we are interested in mAh + final double powerDrain = energy / (voltage * 60*60*1000); + + if (DEBUG && powerDrain != 0) { + Log.d(TAG, "Bluetooth active: time=" + (txTimeMs + rxTimeMs) + + " power=" + makemAh(powerDrain)); + } + + final long totalTime = idleTimeMs + txTimeMs + rxTimeMs; + final double power = mBluetoothPower + powerDrain; + if (power > 0) { + BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, totalTime, power); aggregateSippers(bs, mBluetoothSippers, "Bluetooth"); } } @@ -621,16 +928,55 @@ public final class BatteryStatsHelper { } private void addUserUsage() { - for (int i = 0; i < mUserSippers.size(); i++) { + for (int i=0; i<mUserSippers.size(); i++) { final int userId = mUserSippers.keyAt(i); - BatterySipper bs = new BatterySipper(DrainType.USER, null, 0); + final List<BatterySipper> sippers = mUserSippers.valueAt(i); + Double userPower = mUserPower.get(userId); + double power = (userPower != null) ? userPower : 0.0; + BatterySipper bs = addEntry(BatterySipper.DrainType.USER, 0, power); bs.userId = userId; - aggregateSippers(bs, mUserSippers.valueAt(i), "User"); - bs.sumPower(); - mUsageList.add(bs); + aggregateSippers(bs, sippers, "User"); } } + /** + * Return estimated power (in mAs) of sending or receiving a packet with the mobile radio. + */ + private double getMobilePowerPerPacket() { + final long MOBILE_BPS = 200000; // TODO: Extract average bit rates from system + final double MOBILE_POWER = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE) + / 3600; + + final long mobileRx = mStats.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType); + final long mobileTx = mStats.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType); + final long mobileData = mobileRx + mobileTx; + + final long radioDataUptimeMs + = mStats.getMobileRadioActiveTime(mRawRealtime, mStatsType) / 1000; + final double mobilePps = (mobileData != 0 && radioDataUptimeMs != 0) + ? (mobileData / (double)radioDataUptimeMs) + : (((double)MOBILE_BPS) / 8 / 2048); + + return (MOBILE_POWER / mobilePps) / (60*60); + } + + /** + * 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() { + final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system + final double WIFI_POWER = mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE) + / 3600; + return (WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048)) / (60*60); + } + private void processMiscUsage() { addUserUsage(); addPhoneUsage(); @@ -646,10 +992,15 @@ public final class BatteryStatsHelper { } private BatterySipper addEntry(DrainType drainType, long time, double power) { - BatterySipper bs = new BatterySipper(drainType, null, 0); - bs.usagePowerMah = power; - bs.usageTimeMs = time; - bs.sumPower(); + mComputedPower += 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}); + bs.usageTime = time; mUsageList.add(bs); return bs; } @@ -664,7 +1015,7 @@ public final class BatteryStatsHelper { public long getStatsPeriod() { return mStatsPeriod; } - public int getStatsType() { return mStatsType; } + public int getStatsType() { return mStatsType; }; public double getMaxPower() { return mMaxPower; } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 793d0d3..05ed3ab 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -55,7 +55,6 @@ import android.util.Printer; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; -import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.Xml; import android.view.Display; @@ -96,7 +95,6 @@ import java.util.concurrent.locks.ReentrantLock; public final class BatteryStatsImpl extends BatteryStats { private static final String TAG = "BatteryStatsImpl"; private static final boolean DEBUG = false; - private static final boolean DEBUG_ENERGY = false; private static final boolean DEBUG_HISTORY = false; private static final boolean USE_OLD_HISTORY = false; // for debugging. @@ -184,20 +182,22 @@ public final class BatteryStatsImpl extends BatteryStats { // elapsed time by the number of active timers to arrive at that timer's share of the time. // In order to do this, we must refresh each timer whenever the number of active timers // changes. - final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<>(); - final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers = new SparseArray<>(); - final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<>(); - final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers = new SparseArray<>(); - final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<>(); - final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<>(); + final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<StopwatchTimer>(); + final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<StopwatchTimer>(); + final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<StopwatchTimer>(); + final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers + = new SparseArray<ArrayList<StopwatchTimer>>(); + final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<StopwatchTimer>(); + final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<StopwatchTimer>(); + final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<StopwatchTimer>(); + final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<StopwatchTimer>(); + final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers = + new SparseArray<ArrayList<StopwatchTimer>>(); + final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<StopwatchTimer>(); + final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<StopwatchTimer>(); // Last partial timers we use for distributing CPU usage. - final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<>(); + final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<StopwatchTimer>(); // These are the objects that will want to do something when the device // is unplugged from power. @@ -227,7 +227,7 @@ public final class BatteryStatsImpl extends BatteryStats { final HistoryItem mHistoryLastLastWritten = new HistoryItem(); final HistoryItem mHistoryReadTmp = new HistoryItem(); final HistoryItem mHistoryAddTmp = new HistoryItem(); - final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>(); + final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap(); String[] mReadHistoryStrings; int[] mReadHistoryUids; int mReadHistoryChars; @@ -450,8 +450,6 @@ public final class BatteryStatsImpl extends BatteryStats { private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry(); - private PowerProfile mPowerProfile; - /* * Holds a SamplingTimer associated with each kernel wakelock name being tracked. */ @@ -930,12 +928,6 @@ public final class BatteryStatsImpl extends BatteryStats { long mUnpluggedTime; /** - * The total time this timer has been running until the latest mark has been set. - * Subtract this from mTotalTime to get the time spent running since the mark was set. - */ - long mTimeBeforeMark; - - /** * Constructs from a parcel. * @param type * @param timeBase @@ -953,7 +945,6 @@ public final class BatteryStatsImpl extends BatteryStats { mLoadedTime = in.readLong(); mLastTime = 0; mUnpluggedTime = in.readLong(); - mTimeBeforeMark = in.readLong(); timeBase.add(this); if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime); } @@ -973,7 +964,7 @@ public final class BatteryStatsImpl extends BatteryStats { * so can be completely dropped. */ boolean reset(boolean detachIfReset) { - mTotalTime = mLoadedTime = mLastTime = mTimeBeforeMark = 0; + mTotalTime = mLoadedTime = mLastTime = 0; mCount = mLoadedCount = mLastCount = 0; if (detachIfReset) { detach(); @@ -994,10 +985,8 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs))); out.writeLong(mLoadedTime); out.writeLong(mUnpluggedTime); - out.writeLong(mTimeBeforeMark); } - @Override public void onTimeStarted(long elapsedRealtime, long timeBaseUptime, long baseRealtime) { if (DEBUG && mType < 0) { Log.v(TAG, "unplug #" + mType + ": realtime=" + baseRealtime @@ -1013,7 +1002,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } - @Override public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) { if (DEBUG && mType < 0) { Log.v(TAG, "plug #" + mType + ": realtime=" + baseRealtime @@ -1067,13 +1055,6 @@ public final class BatteryStatsImpl extends BatteryStats { return val; } - @Override - public long getTimeSinceMarkLocked(long elapsedRealtimeUs) { - long val = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)); - return val - mTimeBeforeMark; - } - - @Override public void logState(Printer pw, String prefix) { pw.println(prefix + "mCount=" + mCount + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount @@ -1099,9 +1080,6 @@ public final class BatteryStatsImpl extends BatteryStats { mCount = mLoadedCount = in.readInt(); mLastCount = 0; mUnpluggedCount = mCount; - - // When reading the summary, we set the mark to be the latest information. - mTimeBeforeMark = mTotalTime; } } @@ -1497,6 +1475,21 @@ public final class BatteryStatsImpl extends BatteryStats { return mNesting > 0; } + long checkpointRunningLocked(long elapsedRealtimeMs) { + if (mNesting > 0) { + // We are running... + final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000); + if (mTimerPool != null) { + return refreshTimersLocked(batteryRealtime, mTimerPool, this); + } + final long heldTime = batteryRealtime - mUpdateTime; + mUpdateTime = batteryRealtime; + mTotalTime += heldTime; + return heldTime; + } + return 0; + } + void stopRunningLocked(long elapsedRealtimeMs) { // Ignore attempt to stop a timer that isn't running if (mNesting == 0) { @@ -1574,7 +1567,6 @@ public final class BatteryStatsImpl extends BatteryStats { return mCount; } - @Override boolean reset(boolean detachIfReset) { boolean canDetach = mNesting <= 0; super.reset(canDetach && detachIfReset); @@ -1585,7 +1577,6 @@ public final class BatteryStatsImpl extends BatteryStats { return canDetach; } - @Override void detach() { super.detach(); if (mTimerPool != null) { @@ -1593,31 +1584,10 @@ public final class BatteryStatsImpl extends BatteryStats { } } - @Override void readSummaryFromParcelLocked(Parcel in) { super.readSummaryFromParcelLocked(in); mNesting = 0; } - - /** - * Set the mark so that we can query later for the total time the timer has - * accumulated since this point. The timer can be running or not. - * - * @param elapsedRealtimeMs the current elapsed realtime in milliseconds. - */ - public void setMark(long elapsedRealtimeMs) { - final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000); - if (mNesting > 0) { - // We are running. - if (mTimerPool != null) { - refreshTimersLocked(batteryRealtime, mTimerPool, this); - } else { - mTotalTime += batteryRealtime - mUpdateTime; - mUpdateTime = batteryRealtime; - } - } - mTimeBeforeMark = mTotalTime; - } } public abstract class OverflowArrayMap<T> { @@ -3920,6 +3890,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: " + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(elapsedRealtime, uptime); + scheduleSyncExternalStatsLocked(); } mWifiFullLockNesting++; getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked(elapsedRealtime); @@ -3935,6 +3906,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: " + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(elapsedRealtime, uptime); + scheduleSyncExternalStatsLocked(); } getUidStatsLocked(uid).noteFullWifiLockReleasedLocked(elapsedRealtime); } @@ -3992,6 +3964,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: " + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(elapsedRealtime, uptime); + scheduleSyncExternalStatsLocked(); } mWifiMulticastNesting++; getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime); @@ -4007,6 +3980,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: " + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(elapsedRealtime, uptime); + scheduleSyncExternalStatsLocked(); } getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime); } @@ -4114,8 +4088,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. - final long elapsedRealtimeMs = SystemClock.elapsedRealtime(); - updateMobileRadioStateLocked(elapsedRealtimeMs); + updateMobileRadioStateLocked(SystemClock.elapsedRealtime()); updateWifiStateLocked(null); } @@ -4396,18 +4369,6 @@ public final class BatteryStatsImpl extends BatteryStats { LongSamplingCounter mMobileRadioActiveCount; /** - * The amount of time this uid has kept the WiFi controller in idle, tx, and rx mode. - */ - LongSamplingCounter[] mWifiControllerTime = - new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES]; - - /** - * The amount of time this uid has kept the Bluetooth controller in idle, tx, and rx mode. - */ - LongSamplingCounter[] mBluetoothControllerTime = - new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES]; - - /** * The CPU times we had at the last history details update. */ long mLastStepUserTime; @@ -4443,22 +4404,22 @@ public final class BatteryStatsImpl extends BatteryStats { /** * The statistics we have collected for this uid's sensor activations. */ - final SparseArray<Sensor> mSensorStats = new SparseArray<>(); + final SparseArray<Sensor> mSensorStats = new SparseArray<Sensor>(); /** * The statistics we have collected for this uid's processes. */ - final ArrayMap<String, Proc> mProcessStats = new ArrayMap<>(); + final ArrayMap<String, Proc> mProcessStats = new ArrayMap<String, Proc>(); /** * The statistics we have collected for this uid's processes. */ - final ArrayMap<String, Pkg> mPackageStats = new ArrayMap<>(); + final ArrayMap<String, Pkg> mPackageStats = new ArrayMap<String, Pkg>(); /** * The transient wake stats we have collected for this uid's pids. */ - final SparseArray<Pid> mPids = new SparseArray<>(); + final SparseArray<Pid> mPids = new SparseArray<Pid>(); public Uid(int uid) { mUid = uid; @@ -4619,13 +4580,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public void noteWifiControllerActivityLocked(int type, long timeMs) { - if (mWifiControllerTime[type] == null) { - mWifiControllerTime[type] = new LongSamplingCounter(mOnBatteryTimeBase); - } - mWifiControllerTime[type].addCountLocked(timeMs); - } - public StopwatchTimer createAudioTurnedOnTimerLocked() { if (mAudioTurnedOnTimer == null) { mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON, @@ -4941,15 +4895,6 @@ public final class BatteryStatsImpl extends BatteryStats { ? (int)mMobileRadioActiveCount.getCountLocked(which) : 0; } - @Override - public long getWifiControllerActivity(int type, int which) { - if (type >= 0 && type < NUM_CONTROLLER_ACTIVITY_TYPES && - mWifiControllerTime[type] != null) { - return mWifiControllerTime[type].getCountLocked(which); - } - return 0; - } - void initNetworkActivityLocked() { mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES]; mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES]; @@ -5033,16 +4978,6 @@ public final class BatteryStatsImpl extends BatteryStats { mMobileRadioActiveCount.reset(false); } - for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { - if (mWifiControllerTime[i] != null) { - mWifiControllerTime[i].reset(false); - } - - if (mBluetoothControllerTime[i] != null) { - mBluetoothControllerTime[i].reset(false); - } - } - final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap(); for (int iw=wakeStats.size()-1; iw>=0; iw--) { Wakelock wl = wakeStats.valueAt(iw); @@ -5165,16 +5100,6 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkPacketActivityCounters[i].detach(); } } - - for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { - if (mWifiControllerTime[i] != null) { - mWifiControllerTime[i].detach(); - } - - if (mBluetoothControllerTime[i] != null) { - mBluetoothControllerTime[i].detach(); - } - } mPids.clear(); } @@ -5264,7 +5189,6 @@ public final class BatteryStatsImpl extends BatteryStats { } else { out.writeInt(0); } - if (mAudioTurnedOnTimer != null) { out.writeInt(1); mAudioTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs); @@ -5316,24 +5240,6 @@ public final class BatteryStatsImpl extends BatteryStats { } else { out.writeInt(0); } - - for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { - if (mWifiControllerTime[i] != null) { - out.writeInt(1); - mWifiControllerTime[i].writeToParcel(out); - } else { - out.writeInt(0); - } - } - - for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { - if (mBluetoothControllerTime[i] != null) { - out.writeInt(1); - mBluetoothControllerTime[i].writeToParcel(out); - } else { - out.writeInt(0); - } - } } void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) { @@ -5483,22 +5389,6 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkByteActivityCounters = null; mNetworkPacketActivityCounters = null; } - - for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { - if (in.readInt() != 0) { - mWifiControllerTime[i] = new LongSamplingCounter(mOnBatteryTimeBase, in); - } else { - mWifiControllerTime[i] = null; - } - } - - for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { - if (in.readInt() != 0) { - mBluetoothControllerTime[i] = new LongSamplingCounter(mOnBatteryTimeBase, in); - } else { - mBluetoothControllerTime[i] = null; - } - } } /** @@ -6754,12 +6644,6 @@ public final class BatteryStatsImpl extends BatteryStats { readFromParcel(p); } - public void setPowerProfile(PowerProfile profile) { - synchronized (this) { - mPowerProfile = profile; - } - } - public void setCallback(BatteryCallback cb) { mCallback = cb; } @@ -7483,12 +7367,9 @@ public final class BatteryStatsImpl extends BatteryStats { * @param info The energy information from the WiFi controller. */ public void updateWifiStateLocked(@Nullable final WifiActivityEnergyInfo info) { - final long elapsedRealtimeMs = SystemClock.elapsedRealtime(); - NetworkStats delta = null; + final NetworkStats delta; try { - if (!ArrayUtils.isEmpty(mWifiIfaces)) { - delta = getNetworkStatsDeltaLocked(mWifiIfaces, mWifiNetworkStats); - } + delta = getNetworkStatsDeltaLocked(mWifiIfaces, mWifiNetworkStats); } catch (IOException e) { Slog.wtf(TAG, "Failed to get wifi network stats", e); return; @@ -7498,19 +7379,14 @@ public final class BatteryStatsImpl extends BatteryStats { return; } - SparseLongArray rxPackets = new SparseLongArray(); - SparseLongArray txPackets = new SparseLongArray(); - long totalTxPackets = 0; - long totalRxPackets = 0; if (delta != null) { final int size = delta.size(); for (int i = 0; i < size; i++) { final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry); - if (DEBUG_ENERGY) { + if (DEBUG) { Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes - + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets - + " txPackets=" + entry.txPackets); + + " tx=" + entry.txBytes); } if (entry.rxBytes == 0 || entry.txBytes == 0) { @@ -7522,13 +7398,6 @@ public final class BatteryStatsImpl extends BatteryStats { entry.rxPackets); u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes, entry.txPackets); - rxPackets.put(u.getUid(), entry.rxPackets); - txPackets.put(u.getUid(), entry.txPackets); - - // Sum the total number of packets so that the Rx Power and Tx Power can - // be evenly distributed amongst the apps. - totalRxPackets += entry.rxPackets; - totalTxPackets += entry.txPackets; mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked( entry.rxBytes); @@ -7542,119 +7411,6 @@ public final class BatteryStatsImpl extends BatteryStats { } if (info != null) { - // Measured in mAms - final long txTimeMs = info.getControllerTxTimeMillis(); - final long rxTimeMs = info.getControllerRxTimeMillis(); - final long idleTimeMs = info.getControllerIdleTimeMillis(); - final long totalTimeMs = txTimeMs + rxTimeMs + idleTimeMs; - - long leftOverRxTimeMs = rxTimeMs; - - if (DEBUG_ENERGY) { - Slog.d(TAG, "------ BEGIN WiFi power blaming ------"); - Slog.d(TAG, " Tx Time: " + txTimeMs + " ms"); - Slog.d(TAG, " Rx Time: " + rxTimeMs + " ms"); - Slog.d(TAG, " Idle Time: " + idleTimeMs + " ms"); - Slog.d(TAG, " Total Time: " + totalTimeMs + " ms"); - } - - long totalWifiLockTimeMs = 0; - long totalScanTimeMs = 0; - - // On the first pass, collect some totals so that we can normalize power - // calculations if we need to. - final int uidStatsSize = mUidStats.size(); - for (int i = 0; i < uidStatsSize; i++) { - final Uid uid = mUidStats.valueAt(i); - - // Sum the total scan power for all apps. - totalScanTimeMs += uid.mWifiScanTimer.getTimeSinceMarkLocked( - elapsedRealtimeMs * 1000) / 1000; - - // Sum the total time holding wifi lock for all apps. - totalWifiLockTimeMs += uid.mFullWifiLockTimer.getTimeSinceMarkLocked( - elapsedRealtimeMs * 1000) / 1000; - } - - if (DEBUG_ENERGY && totalScanTimeMs > rxTimeMs) { - Slog.d(TAG, " !Estimated scan time > Actual rx time (" + totalScanTimeMs + " ms > " - + rxTimeMs + " ms). Normalizing scan time."); - } - - // Actually assign and distribute power usage to apps. - for (int i = 0; i < uidStatsSize; i++) { - final Uid uid = mUidStats.valueAt(i); - - long scanTimeSinceMarkMs = uid.mWifiScanTimer.getTimeSinceMarkLocked( - elapsedRealtimeMs * 1000) / 1000; - if (scanTimeSinceMarkMs > 0) { - // Set the new mark so that next time we get new data since this point. - uid.mWifiScanTimer.setMark(elapsedRealtimeMs); - - if (totalScanTimeMs > rxTimeMs) { - // Our total scan time is more than the reported Rx time. - // This is possible because the cost of a scan is approximate. - // Let's normalize the result so that we evenly blame each app - // scanning. - // - // This means that we may have apps that received packets not be blamed - // for this, but this is fine as scans are relatively more expensive. - scanTimeSinceMarkMs = (rxTimeMs * scanTimeSinceMarkMs) / totalScanTimeMs; - } - - if (DEBUG_ENERGY) { - Slog.d(TAG, " ScanTime for UID " + uid.getUid() + ": " - + scanTimeSinceMarkMs + " ms)"); - } - uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, scanTimeSinceMarkMs); - leftOverRxTimeMs -= scanTimeSinceMarkMs; - } - - // Distribute evenly the power consumed while Idle to each app holding a WiFi - // lock. - final long wifiLockTimeSinceMarkMs = uid.mFullWifiLockTimer.getTimeSinceMarkLocked( - elapsedRealtimeMs * 1000) / 1000; - if (wifiLockTimeSinceMarkMs > 0) { - // Set the new mark so that next time we get new data since this point. - uid.mFullWifiLockTimer.setMark(elapsedRealtimeMs); - - final long myIdleTimeMs = (wifiLockTimeSinceMarkMs * idleTimeMs) - / totalWifiLockTimeMs; - if (DEBUG_ENERGY) { - Slog.d(TAG, " IdleTime for UID " + uid.getUid() + ": " - + myIdleTimeMs + " ms"); - } - uid.noteWifiControllerActivityLocked(CONTROLLER_IDLE_TIME, myIdleTimeMs); - } - } - - if (DEBUG_ENERGY) { - Slog.d(TAG, " New RxPower: " + leftOverRxTimeMs + " ms"); - } - - // Distribute the Tx power appropriately between all apps that transmitted packets. - for (int i = 0; i < txPackets.size(); i++) { - final Uid uid = getUidStatsLocked(txPackets.keyAt(i)); - final long myTxTimeMs = (txPackets.valueAt(i) * txTimeMs) / totalTxPackets; - if (DEBUG_ENERGY) { - Slog.d(TAG, " TxTime for UID " + uid.getUid() + ": " + myTxTimeMs + " ms"); - } - uid.noteWifiControllerActivityLocked(CONTROLLER_TX_TIME, myTxTimeMs); - } - - // Distribute the remaining Rx power appropriately between all apps that received - // packets. - for (int i = 0; i < rxPackets.size(); i++) { - final Uid uid = getUidStatsLocked(rxPackets.keyAt(i)); - final long myRxTimeMs = (rxPackets.valueAt(i) * leftOverRxTimeMs) / totalRxPackets; - if (DEBUG_ENERGY) { - Slog.d(TAG, " RxTime for UID " + uid.getUid() + ": " + myRxTimeMs + " ms"); - } - uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, myRxTimeMs); - } - - // Any left over power use will be picked up by the WiFi category in BatteryStatsHelper. - // Update WiFi controller stats. mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked( info.getControllerRxTimeMillis()); @@ -7662,29 +7418,19 @@ public final class BatteryStatsImpl extends BatteryStats { info.getControllerTxTimeMillis()); mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked( info.getControllerIdleTimeMillis()); - - final double powerDrainMaMs; - if (mPowerProfile.getAveragePower( - PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) == 0) { - powerDrainMaMs = 0.0; - } else { - powerDrainMaMs = info.getControllerEnergyUsed() - / mPowerProfile.getAveragePower( - PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE); - } - mWifiActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked((long) powerDrainMaMs); + mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked( + info.getControllerEnergyUsed()); } } /** * Distribute Cell radio energy info and network traffic to apps. */ - public void updateMobileRadioStateLocked(final long elapsedRealtimeMs) { - NetworkStats delta = null; + public void updateMobileRadioStateLocked(long elapsedRealtimeMs) { + final NetworkStats delta; + try { - if (!ArrayUtils.isEmpty(mMobileIfaces)) { - delta = getNetworkStatsDeltaLocked(mMobileIfaces, mMobileNetworkStats); - } + delta = getNetworkStatsDeltaLocked(mMobileIfaces, mMobileNetworkStats); } catch (IOException e) { Slog.wtf(TAG, "Failed to get mobile network stats", e); return; @@ -7694,24 +7440,14 @@ public final class BatteryStatsImpl extends BatteryStats { return; } - long radioTime = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked( - elapsedRealtimeMs * 1000); - mMobileRadioActivePerAppTimer.setMark(elapsedRealtimeMs); + long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(elapsedRealtimeMs); long totalPackets = delta.getTotalPackets(); final int size = delta.size(); for (int i = 0; i < size; i++) { final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry); - if (entry.rxBytes == 0 || entry.txBytes == 0) { - continue; - } - - if (DEBUG_ENERGY) { - Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes - + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets - + " txPackets=" + entry.txPackets); - } + if (entry.rxBytes == 0 || entry.txBytes == 0) continue; final Uid u = getUidStatsLocked(mapUid(entry.uid)); u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes, @@ -7752,14 +7488,14 @@ public final class BatteryStatsImpl extends BatteryStats { * @param info The energy information from the bluetooth controller. */ public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) { - if (info != null && mOnBatteryInternal && false) { + if (info != null && mOnBatteryInternal) { mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked( info.getControllerRxTimeMillis()); mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked( info.getControllerTxTimeMillis()); mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked( info.getControllerIdleTimeMillis()); - mBluetoothActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked( + mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked( info.getControllerEnergyUsed()); } } diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java deleted file mode 100644 index 3557209..0000000 --- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.os; - -import android.os.BatteryStats; -import android.util.Log; - -public class BluetoothPowerCalculator extends PowerCalculator { - private static final boolean DEBUG = BatteryStatsHelper.DEBUG; - private static final String TAG = "BluetoothPowerCalculator"; - - @Override - public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - // No per-app distribution yet. - } - - @Override - public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - final long idleTimeMs = stats.getBluetoothControllerActivity( - BatteryStats.CONTROLLER_IDLE_TIME, statsType); - final long txTimeMs = stats.getBluetoothControllerActivity( - BatteryStats.CONTROLLER_TX_TIME, statsType); - final long rxTimeMs = stats.getBluetoothControllerActivity( - BatteryStats.CONTROLLER_RX_TIME, statsType); - final long powerMaMs = stats.getBluetoothControllerActivity( - BatteryStats.CONTROLLER_POWER_DRAIN, statsType); - final double powerMah = powerMaMs / (double)(1000*60*60); - final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs; - - if (DEBUG && powerMah != 0) { - Log.d(TAG, "Bluetooth active: time=" + (totalTimeMs) - + " power=" + BatteryStatsHelper.makemAh(powerMah)); - } - - app.usagePowerMah = powerMah; - app.usageTimeMs = totalTimeMs; - } -} diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java deleted file mode 100644 index 6c3f958..0000000 --- a/core/java/com/android/internal/os/CpuPowerCalculator.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.os; - -import android.os.BatteryStats; -import android.util.ArrayMap; -import android.util.Log; - -public class CpuPowerCalculator extends PowerCalculator { - private static final String TAG = "CpuPowerCalculator"; - private static final boolean DEBUG = BatteryStatsHelper.DEBUG; - - private final double[] mPowerCpuNormal; - - /** - * Reusable array for calculations. - */ - private final long[] mSpeedStepTimes; - - public CpuPowerCalculator(PowerProfile profile) { - final int speedSteps = profile.getNumSpeedSteps(); - mPowerCpuNormal = new double[speedSteps]; - mSpeedStepTimes = new long[speedSteps]; - for (int p = 0; p < speedSteps; p++) { - mPowerCpuNormal[p] = profile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p); - } - } - - @Override - public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - final int speedSteps = mSpeedStepTimes.length; - - // Keep track of the package with highest drain. - double highestDrain = 0; - - final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); - final int processStatsCount = processStats.size(); - for (int i = 0; i < processStatsCount; i++) { - final BatteryStats.Uid.Proc ps = processStats.valueAt(i); - final String processName = processStats.keyAt(i); - - app.cpuFgTimeMs += ps.getForegroundTime(statsType); - final long totalCpuTime = ps.getUserTime(statsType) + ps.getSystemTime(statsType); - app.cpuTimeMs += totalCpuTime; - - // Calculate the total CPU time spent at the various speed steps. - long totalTimeAtSpeeds = 0; - for (int step = 0; step < speedSteps; step++) { - mSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, statsType); - totalTimeAtSpeeds += mSpeedStepTimes[step]; - } - totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1); - - // Then compute the ratio of time spent at each speed and figure out - // the total power consumption. - double cpuPower = 0; - for (int step = 0; step < speedSteps; step++) { - final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds; - final double cpuSpeedStepPower = ratio * totalCpuTime * mPowerCpuNormal[step]; - if (DEBUG && ratio != 0) { - Log.d(TAG, "UID " + u.getUid() + ": CPU step #" - + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power=" - + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000))); - } - cpuPower += cpuSpeedStepPower; - } - - if (DEBUG && cpuPower != 0) { - Log.d(TAG, String.format("process %s, cpu power=%s", - processName, BatteryStatsHelper.makemAh(cpuPower / (60 * 60 * 1000)))); - } - app.cpuPowerMah += cpuPower; - - // Each App can have multiple packages and with multiple running processes. - // Keep track of the package who's process has the highest drain. - if (app.packageWithHighestDrain == null || - app.packageWithHighestDrain.startsWith("*")) { - highestDrain = cpuPower; - app.packageWithHighestDrain = processName; - } else if (highestDrain < cpuPower && !processName.startsWith("*")) { - highestDrain = cpuPower; - app.packageWithHighestDrain = processName; - } - } - - // Ensure that the CPU times make sense. - if (app.cpuFgTimeMs > app.cpuTimeMs) { - if (DEBUG && app.cpuFgTimeMs > app.cpuTimeMs + 10000) { - Log.d(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time"); - } - - // Statistics may not have been gathered yet. - app.cpuTimeMs = app.cpuFgTimeMs; - } - - // Convert the CPU power to mAh - app.cpuPowerMah /= (60 * 60 * 1000); - } -} diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java deleted file mode 100644 index 9711c3b..0000000 --- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.os; - -import android.os.BatteryStats; -import android.telephony.SignalStrength; -import android.util.Log; - -public class MobileRadioPowerCalculator extends PowerCalculator { - private static final String TAG = "MobileRadioPowerController"; - private static final boolean DEBUG = BatteryStatsHelper.DEBUG; - private final double mPowerRadioOn; - private final double[] mPowerBins = new double[SignalStrength.NUM_SIGNAL_STRENGTH_BINS]; - private final double mPowerScan; - private BatteryStats mStats; - private long mTotalAppMobileActiveMs = 0; - - /** - * Return estimated power (in mAs) of sending or receiving a packet with the mobile radio. - */ - private double getMobilePowerPerPacket(long rawRealtimeUs, int statsType) { - final long MOBILE_BPS = 200000; // TODO: Extract average bit rates from system - final double MOBILE_POWER = mPowerRadioOn / 3600; - - final long mobileRx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA, - statsType); - final long mobileTx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA, - statsType); - final long mobileData = mobileRx + mobileTx; - - final long radioDataUptimeMs = - mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000; - final double mobilePps = (mobileData != 0 && radioDataUptimeMs != 0) - ? (mobileData / (double)radioDataUptimeMs) - : (((double)MOBILE_BPS) / 8 / 2048); - return (MOBILE_POWER / mobilePps) / (60*60); - } - - public MobileRadioPowerCalculator(PowerProfile profile, BatteryStats stats) { - mPowerRadioOn = profile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE); - for (int i = 0; i < mPowerBins.length; i++) { - mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE, i); - } - mPowerScan = profile.getAveragePower(PowerProfile.POWER_RADIO_SCANNING); - mStats = stats; - } - - @Override - public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - // Add cost of mobile traffic. - app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA, - statsType); - app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA, - statsType); - app.mobileActive = u.getMobileRadioActiveTime(statsType) / 1000; - app.mobileActiveCount = u.getMobileRadioActiveCount(statsType); - app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA, - statsType); - app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA, - statsType); - - if (app.mobileActive > 0) { - // We are tracking when the radio is up, so can use the active time to - // determine power use. - mTotalAppMobileActiveMs += app.mobileActive; - app.mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000*60*60); - } else { - // We are not tracking when the radio is up, so must approximate power use - // based on the number of packets. - app.mobileRadioPowerMah = (app.mobileRxPackets + app.mobileTxPackets) - * getMobilePowerPerPacket(rawRealtimeUs, statsType); - } - if (DEBUG && app.mobileRadioPowerMah != 0) { - Log.d(TAG, "UID " + u.getUid() + ": mobile packets " - + (app.mobileRxPackets + app.mobileTxPackets) - + " active time " + app.mobileActive - + " power=" + BatteryStatsHelper.makemAh(app.mobileRadioPowerMah)); - } - } - - @Override - public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - double power = 0; - long signalTimeMs = 0; - long noCoverageTimeMs = 0; - for (int i = 0; i < mPowerBins.length; i++) { - long strengthTimeMs = stats.getPhoneSignalStrengthTime(i, rawRealtimeUs, statsType) - / 1000; - final double p = (strengthTimeMs * mPowerBins[i]) / (60*60*1000); - if (DEBUG && p != 0) { - Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power=" - + BatteryStatsHelper.makemAh(p)); - } - power += p; - signalTimeMs += strengthTimeMs; - if (i == 0) { - noCoverageTimeMs = strengthTimeMs; - } - } - - final long scanningTimeMs = stats.getPhoneSignalScanningTime(rawRealtimeUs, statsType) - / 1000; - final double p = (scanningTimeMs * mPowerScan) / (60*60*1000); - if (DEBUG && p != 0) { - Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs - + " power=" + BatteryStatsHelper.makemAh(p)); - } - power += p; - long radioActiveTimeMs = mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000; - long remainingActiveTimeMs = radioActiveTimeMs - mTotalAppMobileActiveMs; - if (remainingActiveTimeMs > 0) { - power += (mPowerRadioOn * remainingActiveTimeMs) / (1000*60*60); - } - - if (power != 0) { - app.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs; - app.mobileActive = remainingActiveTimeMs; - app.mobileActiveCount = stats.getMobileRadioActiveUnknownCount(statsType); - app.mobileRadioPowerMah = power; - } - } - - @Override - public void reset() { - mTotalAppMobileActiveMs = 0; - } - - public void reset(BatteryStats stats) { - reset(); - mStats = stats; - } -} diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java deleted file mode 100644 index cd69d68..0000000 --- a/core/java/com/android/internal/os/PowerCalculator.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.os; - -import android.os.BatteryStats; - -/** - * Calculates power use of a device subsystem for an app. - */ -public abstract class PowerCalculator { - /** - * Calculate the amount of power an app used for this subsystem. - * @param app The BatterySipper that represents the power use of an app. - * @param u The recorded stats for the app. - * @param rawRealtimeUs The raw system realtime in microseconds. - * @param rawUptimeUs The raw system uptime in microseconds. - * @param statsType The type of stats. Can be {@link BatteryStats#STATS_CURRENT}, - * {@link BatteryStats#STATS_SINCE_CHARGED}, or - * {@link BatteryStats#STATS_SINCE_UNPLUGGED}. - */ - public abstract void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType); - - /** - * Calculate the remaining power that can not be attributed to an app. - * @param app The BatterySipper that will represent this remaining power. - * @param stats The BatteryStats object from which to retrieve data. - * @param rawRealtimeUs The raw system realtime in microseconds. - * @param rawUptimeUs The raw system uptime in microseconds. - * @param statsType The type of stats. Can be {@link BatteryStats#STATS_CURRENT}, - * {@link BatteryStats#STATS_SINCE_CHARGED}, or - * {@link BatteryStats#STATS_SINCE_UNPLUGGED}. - */ - public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - } - - /** - * Reset any state maintained in this calculator. - */ - public void reset() { - } -} diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index 7e6706c..944eb5a 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -18,7 +18,6 @@ package com.android.internal.os; import android.content.Context; -import android.content.res.Resources; import android.content.res.XmlResourceParser; import com.android.internal.util.XmlUtils; @@ -76,21 +75,10 @@ public class PowerProfile { */ public static final String POWER_WIFI_ACTIVE = "wifi.active"; - // - // Updated power constants. These are not estimated, they are real world - // currents and voltages for the underlying bluetooth and wifi controllers. - // - - public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle"; - public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx"; - public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx"; - public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage"; - - public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle"; - public static final String POWER_BLUETOOTH_CONTROLLER_RX = "bluetooth.controller.rx"; - public static final String POWER_BLUETOOTH_CONTROLLER_TX = "bluetooth.controller.tx"; - public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE = - "bluetooth.controller.voltage"; + /** + * Operating voltage of the WiFi controller. + */ + public static final String OPERATING_VOLTAGE_WIFI = "wifi.voltage"; /** * Power consumption when GPS is on. @@ -112,6 +100,10 @@ public class PowerProfile { */ public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at"; + /** + * Operating voltage of the Bluetooth controller. + */ + public static final String OPERATING_VOLTAGE_BLUETOOTH = "bluetooth.voltage"; /** * Power consumption when screen is on, not including the backlight power. @@ -170,7 +162,7 @@ public class PowerProfile { */ public static final String POWER_BATTERY_CAPACITY = "battery.capacity"; - static final HashMap<String, Object> sPowerMap = new HashMap<>(); + static final HashMap<String, Object> sPowerMap = new HashMap<String, Object>(); private static final String TAG_DEVICE = "device"; private static final String TAG_ITEM = "item"; @@ -188,8 +180,7 @@ public class PowerProfile { private void readPowerValuesFromXml(Context context) { int id = com.android.internal.R.xml.power_profile; - final Resources resources = context.getResources(); - XmlResourceParser parser = resources.getXml(id); + XmlResourceParser parser = context.getResources().getXml(id); boolean parsingArray = false; ArrayList<Double> array = new ArrayList<Double>(); String arrayName = null; @@ -240,36 +231,6 @@ public class PowerProfile { } finally { parser.close(); } - - // Now collect other config variables. - int[] configResIds = new int[] { - com.android.internal.R.integer.config_bluetooth_idle_cur_ma, - com.android.internal.R.integer.config_bluetooth_rx_cur_ma, - com.android.internal.R.integer.config_bluetooth_tx_cur_ma, - com.android.internal.R.integer.config_bluetooth_operating_voltage_mv, - com.android.internal.R.integer.config_wifi_idle_receive_cur_ma, - com.android.internal.R.integer.config_wifi_active_rx_cur_ma, - com.android.internal.R.integer.config_wifi_tx_cur_ma, - com.android.internal.R.integer.config_wifi_operating_voltage_mv, - }; - - String[] configResIdKeys = new String[] { - POWER_BLUETOOTH_CONTROLLER_IDLE, - POWER_BLUETOOTH_CONTROLLER_RX, - POWER_BLUETOOTH_CONTROLLER_TX, - POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE, - POWER_WIFI_CONTROLLER_IDLE, - POWER_WIFI_CONTROLLER_RX, - POWER_WIFI_CONTROLLER_TX, - POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE, - }; - - for (int i = 0; i < configResIds.length; i++) { - int value = resources.getInteger(configResIds[i]); - if (value > 0) { - sPowerMap.put(configResIdKeys[i], (double) value); - } - } } /** diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java deleted file mode 100644 index c98639b..0000000 --- a/core/java/com/android/internal/os/SensorPowerCalculator.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.os; - -import android.hardware.Sensor; -import android.hardware.SensorManager; -import android.os.BatteryStats; -import android.util.SparseArray; - -import java.util.List; - -public class SensorPowerCalculator extends PowerCalculator { - private final List<Sensor> mSensors; - private final double mGpsPowerOn; - - public SensorPowerCalculator(PowerProfile profile, SensorManager sensorManager) { - mSensors = sensorManager.getSensorList(Sensor.TYPE_ALL); - mGpsPowerOn = profile.getAveragePower(PowerProfile.POWER_GPS_ON); - } - - @Override - public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - // Process Sensor usage - final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats(); - final int NSE = sensorStats.size(); - for (int ise = 0; ise < NSE; ise++) { - final BatteryStats.Uid.Sensor sensor = sensorStats.valueAt(ise); - final int sensorHandle = sensorStats.keyAt(ise); - final BatteryStats.Timer timer = sensor.getSensorTime(); - final long sensorTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000; - switch (sensorHandle) { - case BatteryStats.Uid.Sensor.GPS: - app.gpsTimeMs = sensorTime; - app.gpsPowerMah = (app.gpsTimeMs * mGpsPowerOn) / (1000*60*60); - break; - default: - final int sensorsCount = mSensors.size(); - for (int i = 0; i < sensorsCount; i++) { - final Sensor s = mSensors.get(i); - if (s.getHandle() == sensorHandle) { - app.sensorPowerMah += (sensorTime * s.getPower()) / (1000*60*60); - break; - } - } - break; - } - } - } -} diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java deleted file mode 100644 index 7575010f..0000000 --- a/core/java/com/android/internal/os/WakelockPowerCalculator.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.os; - -import android.os.BatteryStats; -import android.util.ArrayMap; -import android.util.Log; - -public class WakelockPowerCalculator extends PowerCalculator { - private static final String TAG = "WakelockPowerCalculator"; - private static final boolean DEBUG = BatteryStatsHelper.DEBUG; - private final double mPowerWakelock; - private long mTotalAppWakelockTimeMs = 0; - - public WakelockPowerCalculator(PowerProfile profile) { - mPowerWakelock = profile.getAveragePower(PowerProfile.POWER_CPU_AWAKE); - } - - @Override - public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawUptimeUs, - long rawRealtimeUs, int statsType) { - long wakeLockTimeUs = 0; - final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = - u.getWakelockStats(); - final int wakelockStatsCount = wakelockStats.size(); - for (int i = 0; i < wakelockStatsCount; i++) { - final BatteryStats.Uid.Wakelock wakelock = wakelockStats.valueAt(i); - - // 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) { - wakeLockTimeUs += timer.getTotalTimeLocked(rawRealtimeUs, statsType); - } - } - app.wakeLockTimeMs = wakeLockTimeUs / 1000; // convert to millis - mTotalAppWakelockTimeMs += app.wakeLockTimeMs; - - // Add cost of holding a wake lock. - app.wakeLockPowerMah = (app.wakeLockTimeMs * mPowerWakelock) / (1000*60*60); - if (DEBUG && app.wakeLockPowerMah != 0) { - Log.d(TAG, "UID " + u.getUid() + ": wake " + app.wakeLockTimeMs - + " power=" + BatteryStatsHelper.makemAh(app.wakeLockPowerMah)); - } - } - - @Override - public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - long wakeTimeMillis = stats.getBatteryUptime(rawUptimeUs) / 1000; - wakeTimeMillis -= mTotalAppWakelockTimeMs - + (stats.getScreenOnTime(rawRealtimeUs, statsType) / 1000); - if (wakeTimeMillis > 0) { - final double power = (wakeTimeMillis * mPowerWakelock) / (1000*60*60); - if (DEBUG) { - Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power " - + BatteryStatsHelper.makemAh(power)); - } - app.wakeLockTimeMs += wakeTimeMillis; - app.wakeLockPowerMah += power; - } - } - - @Override - public void reset() { - mTotalAppWakelockTimeMs = 0; - } -} diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java deleted file mode 100644 index 4e77f6b..0000000 --- a/core/java/com/android/internal/os/WifiPowerCalculator.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.os; - -import android.os.BatteryStats; - -/** - * WiFi power calculator for when BatteryStats supports energy reporting - * from the WiFi controller. - */ -public class WifiPowerCalculator extends PowerCalculator { - private final double mIdleCurrentMa; - private final double mTxCurrentMa; - private final double mRxCurrentMa; - private double mTotalAppPowerDrain = 0; - - public WifiPowerCalculator(PowerProfile profile) { - mIdleCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE); - mTxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX); - mRxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX); - } - - @Override - public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - final long idleTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_IDLE_TIME, - statsType); - final long txTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_TX_TIME, statsType); - final long rxTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_RX_TIME, statsType); - app.wifiRunningTimeMs = idleTime + rxTime + txTime; - app.wifiPowerMah = - ((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa)) - / (1000*60*60); - mTotalAppPowerDrain += app.wifiPowerMah; - - app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA, - statsType); - app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA, - statsType); - app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA, - statsType); - app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA, - statsType); - } - - @Override - public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - final long idleTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_IDLE_TIME, - statsType); - final long rxTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_RX_TIME, - statsType); - final long txTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_TX_TIME, - statsType); - app.wifiRunningTimeMs = idleTimeMs + rxTimeMs + txTimeMs; - - double powerDrain = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_POWER_DRAIN, - statsType) / (1000*60*60); - if (powerDrain == 0) { - // Some controllers do not report power drain, so we can calculate it here. - powerDrain = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa) - + (rxTimeMs * mRxCurrentMa)) / (1000*60*60); - } - app.wifiPowerMah = Math.max(0, powerDrain - mTotalAppPowerDrain); - } - - @Override - public void reset() { - mTotalAppPowerDrain = 0; - } -} diff --git a/core/java/com/android/internal/os/WifiPowerEstimator.java b/core/java/com/android/internal/os/WifiPowerEstimator.java deleted file mode 100644 index 0172367..0000000 --- a/core/java/com/android/internal/os/WifiPowerEstimator.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.os; - -import android.os.BatteryStats; - -/** - * Estimates WiFi power usage based on timers in BatteryStats. - */ -public class WifiPowerEstimator extends PowerCalculator { - private final double mWifiPowerPerPacket; - private final double mWifiPowerOn; - private final double mWifiPowerScan; - private final double mWifiPowerBatchScan; - private long mTotalAppWifiRunningTimeMs = 0; - - public WifiPowerEstimator(PowerProfile profile) { - mWifiPowerPerPacket = getWifiPowerPerPacket(profile); - mWifiPowerOn = profile.getAveragePower(PowerProfile.POWER_WIFI_ON); - mWifiPowerScan = profile.getAveragePower(PowerProfile.POWER_WIFI_SCAN); - mWifiPowerBatchScan = profile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN); - } - - /** - * Return estimated power (in mAs) of sending a byte with the Wi-Fi radio. - */ - private static double getWifiPowerPerPacket(PowerProfile profile) { - final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system - final double WIFI_POWER = profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE) - / 3600; - return (WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048)) / (60*60); - } - - @Override - public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA, - statsType); - app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA, - statsType); - app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA, - statsType); - app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA, - statsType); - - final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets) - * mWifiPowerPerPacket; - - app.wifiRunningTimeMs = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000; - mTotalAppWifiRunningTimeMs += app.wifiRunningTimeMs; - final double wifiLockPower = (app.wifiRunningTimeMs * mWifiPowerOn) / (1000*60*60); - - final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType); - final double wifiScanPower = (wifiScanTimeMs * mWifiPowerScan) / (1000*60*60); - - double wifiBatchScanPower = 0; - for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) { - final long batchScanTimeMs = - u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000; - final double batchScanPower = (batchScanTimeMs * mWifiPowerBatchScan) / (1000*60*60); - wifiBatchScanPower += batchScanPower; - } - - app.wifiPowerMah = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower; - } - - @Override - public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - final long totalRunningTimeMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType) - / 1000; - final double powerDrain = ((totalRunningTimeMs - mTotalAppWifiRunningTimeMs) * mWifiPowerOn) - / (1000*60*60); - app.wifiRunningTimeMs = totalRunningTimeMs; - app.wifiPowerMah = Math.max(0, powerDrain); - } - - @Override - public void reset() { - mTotalAppWifiRunningTimeMs = 0; - } -} diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1ac1c8a..eb394c3 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1487,7 +1487,7 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkCapabilities.TRANSPORT_WIFI)) { timeout = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI, - 5); + 0); type = ConnectivityManager.TYPE_WIFI; } else { // do not track any other networks diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index b5b62b4..7b542be 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -210,7 +210,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub private boolean mMobileActivityFromRadio = false; private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; - private int mLastPowerStateFromWifi = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners = new RemoteCallbackList<INetworkActivityListener>(); @@ -435,16 +434,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } - if (ConnectivityManager.isNetworkTypeWifi(type)) { - if (mLastPowerStateFromWifi != powerState) { - mLastPowerStateFromWifi = powerState; - try { - getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos); - } catch (RemoteException e) { - } - } - } - boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH; diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index ac70d88..c8db3be 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -40,7 +40,6 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.os.WorkSource; -import android.telephony.DataConnectionRealTimeInfo; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; import android.util.Slog; @@ -123,7 +122,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub mStats.setRadioScanningTimeout(mContext.getResources().getInteger( com.android.internal.R.integer.config_radioScanningTimeout) * 1000L); - mStats.setPowerProfile(new PowerProfile(context)); } /** @@ -543,15 +541,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } - @Override - public void noteWifiRadioPowerState(int powerState, long tsNanos) { - enforceCallingPermission(); - - // There was a change in WiFi power state. - // Collect data now for the past activity. - mHandler.scheduleSync(); - } - public void noteWifiRunning(WorkSource ws) { enforceCallingPermission(); synchronized (mStats) { @@ -1106,29 +1095,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub result.mTimestamp = info.getTimeStamp(); result.mStackState = info.getStackState(); result.mControllerTxTimeMs = - info.mControllerTxTimeMs - mLastInfo.mControllerTxTimeMs; + info.getControllerTxTimeMillis()- mLastInfo.mControllerTxTimeMs; result.mControllerRxTimeMs = - info.mControllerRxTimeMs - mLastInfo.mControllerRxTimeMs; - result.mControllerEnergyUsed = - info.mControllerEnergyUsed - mLastInfo.mControllerEnergyUsed; - - // WiFi calculates the idle time as a difference from the on time and the various - // Rx + Tx times. There seems to be some missing time there because this sometimes - // becomes negative. Just cap it at 0 and move on. + info.getControllerRxTimeMillis() - mLastInfo.mControllerRxTimeMs; result.mControllerIdleTimeMs = - Math.max(0, info.mControllerIdleTimeMs - mLastInfo.mControllerIdleTimeMs); - - if (result.mControllerTxTimeMs < 0 || - result.mControllerRxTimeMs < 0) { - // The stats were reset by the WiFi system (which is why our delta is negative). - // Returns the unaltered stats. - result.mControllerEnergyUsed = info.mControllerEnergyUsed; - result.mControllerRxTimeMs = info.mControllerRxTimeMs; - result.mControllerTxTimeMs = info.mControllerTxTimeMs; - result.mControllerIdleTimeMs = info.mControllerIdleTimeMs; - - Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + result); - } + info.getControllerIdleTimeMillis() - mLastInfo.mControllerIdleTimeMs; + result.mControllerEnergyUsed = + info.getControllerEnergyUsed() - mLastInfo.mControllerEnergyUsed; mLastInfo = info; return result; } @@ -1160,12 +1133,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub */ void updateExternalStats() { synchronized (mExternalStatsLock) { - if (mContext == null) { - // We haven't started yet (which means the BatteryStatsImpl object has - // no power profile. Don't consume data we can't compute yet. - return; - } - final WifiActivityEnergyInfo wifiEnergyInfo = pullWifiEnergyInfoLocked(); final BluetoothActivityEnergyInfo bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked(); synchronized (mStats) { |
