Merge "BatteryStats: Record energy info stats from WiFi and Bluetooth controllers"
This commit is contained in:
committed by
Android (Google) Code Review
commit
216f3edcb9
@@ -441,14 +441,14 @@ public abstract class BatteryStats implements Parcelable {
|
||||
public abstract boolean isActive();
|
||||
|
||||
/**
|
||||
* Returns the total time (in 1/100 sec) spent executing in user code.
|
||||
* Returns the total time (in milliseconds) spent executing in user code.
|
||||
*
|
||||
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
|
||||
*/
|
||||
public abstract long getUserTime(int which);
|
||||
|
||||
/**
|
||||
* Returns the total time (in 1/100 sec) spent executing in system code.
|
||||
* Returns the total time (in milliseconds) spent executing in system code.
|
||||
*
|
||||
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
|
||||
*/
|
||||
@@ -476,14 +476,14 @@ public abstract class BatteryStats implements Parcelable {
|
||||
public abstract int getNumAnrs(int which);
|
||||
|
||||
/**
|
||||
* Returns the cpu time spent in microseconds while the process was in the foreground.
|
||||
* Returns the cpu time (milliseconds) spent while the process was in the foreground.
|
||||
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
|
||||
* @return foreground cpu time in microseconds
|
||||
*/
|
||||
public abstract long getForegroundTime(int which);
|
||||
|
||||
/**
|
||||
* Returns the approximate cpu time spent in microseconds, at a certain CPU speed.
|
||||
* Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed.
|
||||
* @param speedStep the index of the CPU speed. This is not the actual speed of the
|
||||
* CPU.
|
||||
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
|
||||
@@ -1858,6 +1858,15 @@ public abstract class BatteryStats implements Parcelable {
|
||||
public abstract long getNetworkActivityBytes(int type, int which);
|
||||
public abstract long getNetworkActivityPackets(int type, int which);
|
||||
|
||||
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_ENERGY = 3;
|
||||
public static final int NUM_CONTROLLER_ACTIVITY_TYPES = CONTROLLER_ENERGY + 1;
|
||||
|
||||
public abstract long getBluetoothControllerActivity(int type, int which);
|
||||
public abstract long getWifiControllerActivity(int type, int which);
|
||||
|
||||
/**
|
||||
* Return the wall clock time when battery stats data collection started.
|
||||
*/
|
||||
@@ -3142,6 +3151,35 @@ public abstract class BatteryStats implements Parcelable {
|
||||
if (!didOne) sb.append(" (no activity)");
|
||||
pw.println(sb.toString());
|
||||
|
||||
final long wifiIdleTimeMs = getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
|
||||
final long wifiRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
|
||||
final long wifiTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
|
||||
final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs;
|
||||
|
||||
sb.setLength(0);
|
||||
sb.append(prefix);
|
||||
sb.append(" WiFi Idle time: "); formatTimeMs(sb, wifiIdleTimeMs);
|
||||
sb.append(" (");
|
||||
sb.append(formatRatioLocked(wifiIdleTimeMs, wifiTotalTimeMs));
|
||||
sb.append(")");
|
||||
pw.println(sb.toString());
|
||||
|
||||
sb.setLength(0);
|
||||
sb.append(prefix);
|
||||
sb.append(" WiFi Rx time: "); formatTimeMs(sb, wifiRxTimeMs);
|
||||
sb.append(" (");
|
||||
sb.append(formatRatioLocked(wifiRxTimeMs, wifiTotalTimeMs));
|
||||
sb.append(")");
|
||||
pw.println(sb.toString());
|
||||
|
||||
sb.setLength(0);
|
||||
sb.append(prefix);
|
||||
sb.append(" WiFi Tx time: "); formatTimeMs(sb, wifiTxTimeMs);
|
||||
sb.append(" (");
|
||||
sb.append(formatRatioLocked(wifiTxTimeMs, wifiTotalTimeMs));
|
||||
sb.append(")");
|
||||
pw.println(sb.toString());
|
||||
|
||||
sb.setLength(0);
|
||||
sb.append(prefix);
|
||||
sb.append(" Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000);
|
||||
@@ -3169,9 +3207,41 @@ public abstract class BatteryStats implements Parcelable {
|
||||
sb.append(getPhoneDataConnectionCount(i, which));
|
||||
sb.append("x");
|
||||
}
|
||||
|
||||
if (!didOne) sb.append(" (no activity)");
|
||||
pw.println(sb.toString());
|
||||
|
||||
final long bluetoothIdleTimeMs =
|
||||
getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
|
||||
final long bluetoothRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
|
||||
final long bluetoothTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
|
||||
final long bluetoothTotalTimeMs = bluetoothIdleTimeMs + bluetoothRxTimeMs +
|
||||
bluetoothTxTimeMs;
|
||||
|
||||
sb.setLength(0);
|
||||
sb.append(prefix);
|
||||
sb.append(" Bluetooth Idle time: "); formatTimeMs(sb, bluetoothIdleTimeMs);
|
||||
sb.append(" (");
|
||||
sb.append(formatRatioLocked(bluetoothIdleTimeMs, bluetoothTotalTimeMs));
|
||||
sb.append(")");
|
||||
pw.println(sb.toString());
|
||||
|
||||
sb.setLength(0);
|
||||
sb.append(prefix);
|
||||
sb.append(" Bluetooth Rx time: "); formatTimeMs(sb, bluetoothRxTimeMs);
|
||||
sb.append(" (");
|
||||
sb.append(formatRatioLocked(bluetoothRxTimeMs, bluetoothTotalTimeMs));
|
||||
sb.append(")");
|
||||
pw.println(sb.toString());
|
||||
|
||||
sb.setLength(0);
|
||||
sb.append(prefix);
|
||||
sb.append(" Bluetooth Tx time: "); formatTimeMs(sb, bluetoothTxTimeMs);
|
||||
sb.append(" (");
|
||||
sb.append(formatRatioLocked(bluetoothTxTimeMs, bluetoothTotalTimeMs));
|
||||
sb.append(")");
|
||||
pw.println(sb.toString());
|
||||
|
||||
pw.println();
|
||||
|
||||
if (which == STATS_SINCE_UNPLUGGED) {
|
||||
|
||||
@@ -26,12 +26,15 @@ public class BatterySipper implements Comparable<BatterySipper> {
|
||||
public double value;
|
||||
public double[] values;
|
||||
public DrainType drainType;
|
||||
|
||||
// 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;
|
||||
public long mobileActive;
|
||||
@@ -48,6 +51,14 @@ public class BatterySipper implements Comparable<BatterySipper> {
|
||||
public String[] mPackages;
|
||||
public String packageWithHighestDrain;
|
||||
|
||||
// Measured in mAh (milli-ampere per hour).
|
||||
public double wifiPower;
|
||||
public double cpuPower;
|
||||
public double wakeLockPower;
|
||||
public double mobileRadioPower;
|
||||
public double gpsPower;
|
||||
public double sensorPower;
|
||||
|
||||
public enum DrainType {
|
||||
IDLE,
|
||||
CELL,
|
||||
@@ -107,4 +118,31 @@ public class BatterySipper implements Comparable<BatterySipper> {
|
||||
}
|
||||
return uidObj.getUid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add stats from other to this BatterySipper.
|
||||
*/
|
||||
public void add(BatterySipper other) {
|
||||
cpuTime += other.cpuTime;
|
||||
gpsTime += other.gpsTime;
|
||||
wifiRunningTime += other.wifiRunningTime;
|
||||
cpuFgTime += other.cpuFgTime;
|
||||
wakeLockTime += other.wakeLockTime;
|
||||
mobileRxPackets += other.mobileRxPackets;
|
||||
mobileTxPackets += other.mobileTxPackets;
|
||||
mobileActive += other.mobileActive;
|
||||
mobileActiveCount += other.mobileActiveCount;
|
||||
wifiRxPackets += other.wifiRxPackets;
|
||||
wifiTxPackets += other.wifiTxPackets;
|
||||
mobileRxBytes += other.mobileRxBytes;
|
||||
mobileTxBytes += other.mobileTxBytes;
|
||||
wifiRxBytes += other.wifiRxBytes;
|
||||
wifiTxBytes += other.wifiTxBytes;
|
||||
wifiPower += other.wifiPower;
|
||||
gpsPower += other.gpsPower;
|
||||
cpuPower += other.cpuPower;
|
||||
sensorPower += other.sensorPower;
|
||||
mobileRadioPower += other.mobileRadioPower;
|
||||
wakeLockPower += other.wakeLockPower;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,6 +344,7 @@ public final class BatteryStatsHelper {
|
||||
mMobilemsppList.add(bs);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<mUserSippers.size(); i++) {
|
||||
List<BatterySipper> user = mUserSippers.valueAt(i);
|
||||
for (int j=0; j<user.size(); j++) {
|
||||
@@ -389,8 +390,8 @@ public final class BatteryStatsHelper {
|
||||
|
||||
private void processAppUsage(SparseArray<UserHandle> asUsers) {
|
||||
final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
|
||||
SensorManager sensorManager = (SensorManager) mContext.getSystemService(
|
||||
Context.SENSOR_SERVICE);
|
||||
final SensorManager sensorManager =
|
||||
(SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
|
||||
final int which = mStatsType;
|
||||
final int speedSteps = mPowerProfile.getNumSpeedSteps();
|
||||
final double[] powerCpuNormal = new double[speedSteps];
|
||||
@@ -401,238 +402,317 @@ public final class BatteryStatsHelper {
|
||||
final double mobilePowerPerPacket = getMobilePowerPerPacket();
|
||||
final double mobilePowerPerMs = getMobilePowerPerMs();
|
||||
final double wifiPowerPerPacket = getWifiPowerPerPacket();
|
||||
long appWakelockTimeUs = 0;
|
||||
long totalAppWakelockTimeUs = 0;
|
||||
BatterySipper osApp = null;
|
||||
mStatsPeriod = mTypeBatteryRealtime;
|
||||
SparseArray<? extends Uid> uidStats = mStats.getUidStats();
|
||||
|
||||
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++) {
|
||||
Uid u = uidStats.valueAt(iu);
|
||||
double p; // in mAs
|
||||
double power = 0; // in mAs
|
||||
double highestDrain = 0;
|
||||
String packageWithHighestDrain = null;
|
||||
Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
|
||||
long cpuTime = 0;
|
||||
long cpuFgTime = 0;
|
||||
long wakelockTime = 0;
|
||||
long gpsTime = 0;
|
||||
final Uid u = uidStats.valueAt(iu);
|
||||
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
|
||||
// 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();
|
||||
final long userTime = ps.getUserTime(which);
|
||||
final long systemTime = ps.getSystemTime(which);
|
||||
final long foregroundTime = ps.getForegroundTime(which);
|
||||
cpuFgTime += foregroundTime;
|
||||
final long tmpCpuTime = userTime + systemTime;
|
||||
int totalTimeAtSpeeds = 0;
|
||||
// Get the total first
|
||||
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];
|
||||
}
|
||||
if (totalTimeAtSpeeds == 0) totalTimeAtSpeeds = 1;
|
||||
// Then compute the ratio of time spent at each speed
|
||||
double processPower = 0;
|
||||
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++) {
|
||||
double ratio = (double) cpuSpeedStepTimes[step] / totalTimeAtSpeeds;
|
||||
if (DEBUG && ratio != 0) Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
|
||||
+ step + " ratio=" + makemAh(ratio) + " power="
|
||||
+ makemAh(ratio*tmpCpuTime*powerCpuNormal[step] / (60*60*1000)));
|
||||
processPower += ratio * tmpCpuTime * powerCpuNormal[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;
|
||||
}
|
||||
cpuTime += tmpCpuTime;
|
||||
if (DEBUG && processPower != 0) {
|
||||
|
||||
if (DEBUG && cpuPower != 0) {
|
||||
Log.d(TAG, String.format("process %s, cpu power=%s",
|
||||
ent.getKey(), makemAh(processPower / (60*60*1000))));
|
||||
ent.getKey(), makemAh(cpuPower / (60 * 60 * 1000))));
|
||||
}
|
||||
power += processPower;
|
||||
if (packageWithHighestDrain == null
|
||||
|| packageWithHighestDrain.startsWith("*")) {
|
||||
highestDrain = processPower;
|
||||
packageWithHighestDrain = ent.getKey();
|
||||
} else if (highestDrain < processPower
|
||||
&& !ent.getKey().startsWith("*")) {
|
||||
highestDrain = processPower;
|
||||
packageWithHighestDrain = ent.getKey();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cpuFgTime > cpuTime) {
|
||||
if (DEBUG && cpuFgTime > cpuTime + 10000) {
|
||||
|
||||
// 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");
|
||||
}
|
||||
cpuTime = cpuFgTime; // Statistics may not have been gathered yet.
|
||||
|
||||
// Statistics may not have been gathered yet.
|
||||
app.cpuTime = app.cpuFgTime;
|
||||
}
|
||||
power /= (60*60*1000);
|
||||
|
||||
// Convert the CPU power to mAh
|
||||
app.cpuPower /= (60 * 60 * 1000);
|
||||
maxCpuPower = Math.max(maxCpuPower, app.cpuPower);
|
||||
|
||||
// Process wake lock usage
|
||||
Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = u.getWakelockStats();
|
||||
final Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
|
||||
u.getWakelockStats();
|
||||
long wakeLockTimeUs = 0;
|
||||
for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> wakelockEntry
|
||||
: wakelockStats.entrySet()) {
|
||||
Uid.Wakelock wakelock = wakelockEntry.getValue();
|
||||
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) {
|
||||
wakelockTime += timer.getTotalTimeLocked(mRawRealtime, which);
|
||||
wakeLockTimeUs += timer.getTotalTimeLocked(mRawRealtime, which);
|
||||
}
|
||||
}
|
||||
appWakelockTimeUs += wakelockTime;
|
||||
wakelockTime /= 1000; // convert to millis
|
||||
app.wakeLockTime = wakeLockTimeUs / 1000; // convert to millis
|
||||
totalAppWakelockTimeUs += wakeLockTimeUs;
|
||||
|
||||
// Add cost of holding a wake lock
|
||||
p = (wakelockTime
|
||||
* mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60*60*1000);
|
||||
if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wake "
|
||||
+ wakelockTime + " power=" + makemAh(p));
|
||||
power += p;
|
||||
// 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 mobileRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType);
|
||||
final long mobileTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType);
|
||||
final long mobileRxB = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType);
|
||||
final long mobileTxB = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType);
|
||||
// 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;
|
||||
p = (mobilePowerPerMs * mobileActive) / 1000;
|
||||
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.
|
||||
p = (mobileRx + mobileTx) * mobilePowerPerPacket;
|
||||
app.mobileRadioPower = (app.mobileRxPackets + app.mobileTxPackets)
|
||||
* mobilePowerPerPacket;
|
||||
}
|
||||
if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
|
||||
+ (mobileRx+mobileTx) + " active time " + mobileActive
|
||||
+ " power=" + makemAh(p));
|
||||
power += p;
|
||||
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
|
||||
final long wifiRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType);
|
||||
final long wifiTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType);
|
||||
final long wifiRxB = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType);
|
||||
final long wifiTxB = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType);
|
||||
p = (wifiRx + wifiTx) * wifiPowerPerPacket;
|
||||
if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi packets "
|
||||
+ (mobileRx+mobileTx) + " power=" + makemAh(p));
|
||||
power += p;
|
||||
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);
|
||||
|
||||
// Add cost of keeping WIFI running.
|
||||
long wifiRunningTimeMs = u.getWifiRunningTime(mRawRealtime, which) / 1000;
|
||||
mAppWifiRunning += wifiRunningTimeMs;
|
||||
p = (wifiRunningTimeMs
|
||||
* mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000);
|
||||
if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi running "
|
||||
+ wifiRunningTimeMs + " power=" + makemAh(p));
|
||||
power += p;
|
||||
|
||||
// Add cost of WIFI scans
|
||||
long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000;
|
||||
p = (wifiScanTimeMs
|
||||
* mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN)) / (60*60*1000);
|
||||
if (DEBUG) Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs
|
||||
+ " power=" + makemAh(p));
|
||||
power += p;
|
||||
for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
|
||||
long batchScanTimeMs = u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000;
|
||||
p = ((batchScanTimeMs
|
||||
* mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin))
|
||||
) / (60*60*1000);
|
||||
if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi batched scan # " + bin
|
||||
+ " time=" + batchScanTimeMs + " power=" + makemAh(p));
|
||||
power += p;
|
||||
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
|
||||
SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
|
||||
int NSE = sensorStats.size();
|
||||
for (int ise=0; ise<NSE; ise++) {
|
||||
Uid.Sensor sensor = sensorStats.valueAt(ise);
|
||||
int sensorHandle = sensorStats.keyAt(ise);
|
||||
BatteryStats.Timer timer = sensor.getSensorTime();
|
||||
long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000;
|
||||
double multiplier = 0;
|
||||
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:
|
||||
multiplier = mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON);
|
||||
gpsTime = sensorTime;
|
||||
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) {
|
||||
multiplier = s.getPower();
|
||||
sensorPower = (sensorTime * s.getPower()) / (60 * 60 * 1000);
|
||||
app.sensorPower += sensorPower;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
p = (multiplier * sensorTime) / (60*60*1000);
|
||||
if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": sensor #" + sensorHandle
|
||||
+ " time=" + sensorTime + " power=" + makemAh(p));
|
||||
power += p;
|
||||
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)));
|
||||
}
|
||||
|
||||
if (DEBUG && power != 0) Log.d(TAG, String.format("UID %d: total power=%s",
|
||||
u.getUid(), makemAh(power)));
|
||||
// Add the app to the list if it is consuming power.
|
||||
if (totalUnnormalizedPower != 0 || u.getUid() == 0) {
|
||||
appList.add(app);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the app to the list if it is consuming power
|
||||
final int userId = UserHandle.getUserId(u.getUid());
|
||||
if (power != 0 || u.getUid() == 0) {
|
||||
BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u,
|
||||
new double[] {power});
|
||||
app.cpuTime = cpuTime;
|
||||
app.gpsTime = gpsTime;
|
||||
app.wifiRunningTime = wifiRunningTimeMs;
|
||||
app.cpuFgTime = cpuFgTime;
|
||||
app.wakeLockTime = wakelockTime;
|
||||
app.mobileRxPackets = mobileRx;
|
||||
app.mobileTxPackets = mobileTx;
|
||||
app.mobileActive = mobileActive / 1000;
|
||||
app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType);
|
||||
app.wifiRxPackets = wifiRx;
|
||||
app.wifiTxPackets = wifiTx;
|
||||
app.mobileRxBytes = mobileRxB;
|
||||
app.mobileTxBytes = mobileTxB;
|
||||
app.wifiRxBytes = wifiRxB;
|
||||
app.wifiTxBytes = wifiTxB;
|
||||
app.packageWithHighestDrain = packageWithHighestDrain;
|
||||
if (u.getUid() == Process.WIFI_UID) {
|
||||
mWifiSippers.add(app);
|
||||
mWifiPower += power;
|
||||
} else if (u.getUid() == Process.BLUETOOTH_UID) {
|
||||
mBluetoothSippers.add(app);
|
||||
mBluetoothPower += power;
|
||||
} else if (!forAllUsers && asUsers.get(userId) == null
|
||||
&& UserHandle.getAppId(u.getUid()) >= Process.FIRST_APPLICATION_UID) {
|
||||
List<BatterySipper> list = mUserSippers.get(userId);
|
||||
if (list == null) {
|
||||
list = new ArrayList<BatterySipper>();
|
||||
mUserSippers.put(userId, list);
|
||||
}
|
||||
list.add(app);
|
||||
if (power != 0) {
|
||||
Double userPower = mUserPower.get(userId);
|
||||
if (userPower == null) {
|
||||
userPower = power;
|
||||
} else {
|
||||
userPower += power;
|
||||
}
|
||||
mUserPower.put(userId, userPower);
|
||||
}
|
||||
// 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);
|
||||
|
||||
Double userPower = mUserPower.get(userId);
|
||||
if (userPower == null) {
|
||||
userPower = power;
|
||||
} else {
|
||||
mUsageList.add(app);
|
||||
if (power > mMaxPower) mMaxPower = power;
|
||||
if (power > mMaxRealPower) mMaxRealPower = power;
|
||||
mComputedPower += power;
|
||||
}
|
||||
if (u.getUid() == 0) {
|
||||
osApp = app;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,7 +721,7 @@ public final class BatteryStatsHelper {
|
||||
// this remainder to the OS, if possible.
|
||||
if (osApp != null) {
|
||||
long wakeTimeMillis = mBatteryUptime / 1000;
|
||||
wakeTimeMillis -= (appWakelockTimeUs / 1000)
|
||||
wakeTimeMillis -= (totalAppWakelockTimeUs / 1000)
|
||||
+ (mStats.getScreenOnTime(mRawRealtime, which) / 1000);
|
||||
if (wakeTimeMillis > 0) {
|
||||
double power = (wakeTimeMillis
|
||||
@@ -741,46 +821,11 @@ public final class BatteryStatsHelper {
|
||||
for (int i=0; i<from.size(); i++) {
|
||||
BatterySipper wbs = from.get(i);
|
||||
if (DEBUG) Log.d(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTime);
|
||||
bs.cpuTime += wbs.cpuTime;
|
||||
bs.gpsTime += wbs.gpsTime;
|
||||
bs.wifiRunningTime += wbs.wifiRunningTime;
|
||||
bs.cpuFgTime += wbs.cpuFgTime;
|
||||
bs.wakeLockTime += wbs.wakeLockTime;
|
||||
bs.mobileRxPackets += wbs.mobileRxPackets;
|
||||
bs.mobileTxPackets += wbs.mobileTxPackets;
|
||||
bs.mobileActive += wbs.mobileActive;
|
||||
bs.mobileActiveCount += wbs.mobileActiveCount;
|
||||
bs.wifiRxPackets += wbs.wifiRxPackets;
|
||||
bs.wifiTxPackets += wbs.wifiTxPackets;
|
||||
bs.mobileRxBytes += wbs.mobileRxBytes;
|
||||
bs.mobileTxBytes += wbs.mobileTxBytes;
|
||||
bs.wifiRxBytes += wbs.wifiRxBytes;
|
||||
bs.wifiTxBytes += wbs.wifiTxBytes;
|
||||
bs.add(wbs);
|
||||
}
|
||||
bs.computeMobilemspp();
|
||||
}
|
||||
|
||||
private void addWiFiUsage() {
|
||||
long onTimeMs = mStats.getWifiOnTime(mRawRealtime, mStatsType) / 1000;
|
||||
long runningTimeMs = mStats.getGlobalWifiRunningTime(mRawRealtime, mStatsType) / 1000;
|
||||
if (DEBUG) Log.d(TAG, "WIFI runningTime=" + runningTimeMs
|
||||
+ " app runningTime=" + mAppWifiRunning);
|
||||
runningTimeMs -= mAppWifiRunning;
|
||||
if (runningTimeMs < 0) runningTimeMs = 0;
|
||||
double wifiPower = (onTimeMs * 0 /* TODO */
|
||||
* mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)
|
||||
+ runningTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON))
|
||||
/ (60*60*1000);
|
||||
if (DEBUG && wifiPower != 0) {
|
||||
Log.d(TAG, "Wifi: time=" + runningTimeMs + " power=" + makemAh(wifiPower));
|
||||
}
|
||||
if ((wifiPower+mWifiPower) != 0) {
|
||||
BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, runningTimeMs,
|
||||
wifiPower + mWifiPower);
|
||||
aggregateSippers(bs, mWifiSippers, "WIFI");
|
||||
}
|
||||
}
|
||||
|
||||
private void addIdleUsage() {
|
||||
long idleTimeMs = (mTypeBatteryRealtime
|
||||
- mStats.getScreenOnTime(mRawRealtime, mStatsType)) / 1000;
|
||||
@@ -794,24 +839,81 @@ public final class BatteryStatsHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We do per-app blaming of WiFi activity. If energy info is reported from the controller,
|
||||
* then only the WiFi process gets blamed here since we normalize power calculations and
|
||||
* assign all the power drain to apps. If energy info is not reported, we attribute the
|
||||
* difference between total running time of WiFi for all apps and the actual running time
|
||||
* of WiFi to the WiFi subsystem.
|
||||
*/
|
||||
private void addWiFiUsage() {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bluetooth usage is not attributed to any apps yet, so the entire blame goes to the
|
||||
* Bluetooth Category.
|
||||
*/
|
||||
private void addBluetoothUsage() {
|
||||
long btOnTimeMs = mStats.getBluetoothOnTime(mRawRealtime, mStatsType) / 1000;
|
||||
double btPower = btOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_ON)
|
||||
/ (60*60*1000);
|
||||
if (DEBUG && btPower != 0) {
|
||||
Log.d(TAG, "Bluetooth: time=" + btOnTimeMs + " power=" + makemAh(btPower));
|
||||
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));
|
||||
}
|
||||
int btPingCount = mStats.getBluetoothPingCount();
|
||||
double pingPower = (btPingCount
|
||||
* mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_AT_CMD))
|
||||
/ (60*60*1000);
|
||||
if (DEBUG && pingPower != 0) {
|
||||
Log.d(TAG, "Bluetooth ping: count=" + btPingCount + " power=" + makemAh(pingPower));
|
||||
}
|
||||
btPower += pingPower;
|
||||
if ((btPower+mBluetoothPower) != 0) {
|
||||
BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, btOnTimeMs,
|
||||
btPower + mBluetoothPower);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,15 @@ import static android.net.NetworkStats.UID_ALL;
|
||||
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.bluetooth.BluetoothActivityEnergyInfo;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkStats;
|
||||
import android.net.wifi.IWifiManager;
|
||||
import android.net.wifi.WifiActivityEnergyInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.BadParcelableException;
|
||||
import android.os.BatteryManager;
|
||||
@@ -38,6 +42,8 @@ import android.os.Parcel;
|
||||
import android.os.ParcelFormatException;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.WorkSource;
|
||||
@@ -332,6 +338,12 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
final LongSamplingCounter[] mNetworkPacketActivityCounters =
|
||||
new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
|
||||
|
||||
final LongSamplingCounter[] mBluetoothActivityCounters =
|
||||
new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
|
||||
|
||||
final LongSamplingCounter[] mWifiActivityCounters =
|
||||
new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
|
||||
|
||||
boolean mWifiOn;
|
||||
StopwatchTimer mWifiOnTimer;
|
||||
|
||||
@@ -4307,6 +4319,20 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
return mBluetoothStateTimer[bluetoothState].getCountLocked(which);
|
||||
}
|
||||
|
||||
@Override public long getBluetoothControllerActivity(int type, int which) {
|
||||
if (type >= 0 && type < mBluetoothActivityCounters.length) {
|
||||
return mBluetoothActivityCounters[type].getCountLocked(which);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public long getWifiControllerActivity(int type, int which) {
|
||||
if (type >= 0 && type < mWifiActivityCounters.length) {
|
||||
return mWifiActivityCounters[type].getCountLocked(which);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public long getFlashlightOnTime(long elapsedRealtimeUs, int which) {
|
||||
return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
|
||||
}
|
||||
@@ -6652,6 +6678,10 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
|
||||
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
|
||||
}
|
||||
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
|
||||
mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
|
||||
mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
|
||||
}
|
||||
mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase);
|
||||
mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase);
|
||||
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
|
||||
@@ -7239,6 +7269,10 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
|
||||
mBluetoothStateTimer[i].reset(false);
|
||||
}
|
||||
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
|
||||
mBluetoothActivityCounters[i].reset(false);
|
||||
mWifiActivityCounters[i].reset(false);
|
||||
}
|
||||
mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
|
||||
|
||||
for (int i=0; i<mUidStats.size(); i++) {
|
||||
@@ -7325,6 +7359,9 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
public void pullPendingStateUpdatesLocked() {
|
||||
updateKernelWakelocksLocked();
|
||||
updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
|
||||
// TODO(adamlesinski): enable when bluedroid stops deadlocking. b/19248786
|
||||
// updateBluetoothControllerActivityLocked();
|
||||
updateWifiControllerActivityLocked();
|
||||
if (mOnBatteryInternal) {
|
||||
final boolean screenOn = mScreenState == Display.STATE_ON;
|
||||
updateDischargeScreenLevelsLocked(screenOn, screenOn);
|
||||
@@ -7761,6 +7798,65 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBluetoothControllerActivityLocked() {
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (adapter == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We read the data even if we are not on battery. Each read clears
|
||||
// the previous data, so we must always read to make sure the
|
||||
// data is for the current interval.
|
||||
BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo(
|
||||
BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED);
|
||||
if (info == null || !info.isValid() || !mOnBatteryInternal) {
|
||||
// Bad info or we are not on battery.
|
||||
return;
|
||||
}
|
||||
|
||||
mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
|
||||
info.getControllerRxTimeMillis());
|
||||
mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
|
||||
info.getControllerTxTimeMillis());
|
||||
mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
|
||||
info.getControllerIdleTimeMillis());
|
||||
mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked(
|
||||
info.getControllerEnergyUsed());
|
||||
}
|
||||
|
||||
private void updateWifiControllerActivityLocked() {
|
||||
IWifiManager wifiManager = IWifiManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.WIFI_SERVICE));
|
||||
if (wifiManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
WifiActivityEnergyInfo info;
|
||||
try {
|
||||
// We read the data even if we are not on battery. Each read clears
|
||||
// the previous data, so we must always read to make sure the
|
||||
// data is for the current interval.
|
||||
info = wifiManager.reportActivityInfo();
|
||||
} catch (RemoteException e) {
|
||||
// Nothing to report, WiFi is dead.
|
||||
return;
|
||||
}
|
||||
|
||||
if (info == null || !info.isValid() || !mOnBatteryInternal) {
|
||||
// Bad info or we are not on battery.
|
||||
return;
|
||||
}
|
||||
|
||||
mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
|
||||
info.getControllerRxTimeMillis());
|
||||
mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
|
||||
info.getControllerTxTimeMillis());
|
||||
mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
|
||||
info.getControllerIdleTimeMillis());
|
||||
mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked(
|
||||
info.getControllerEnergyUsed());
|
||||
}
|
||||
|
||||
public long getAwakeTimeBattery() {
|
||||
return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
|
||||
}
|
||||
@@ -8475,6 +8571,15 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
|
||||
mBluetoothStateTimer[i].readSummaryFromParcelLocked(in);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
|
||||
mBluetoothActivityCounters[i].readSummaryFromParcelLocked(in);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
|
||||
mWifiActivityCounters[i].readSummaryFromParcelLocked(in);
|
||||
}
|
||||
|
||||
mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
|
||||
mFlashlightOn = false;
|
||||
mFlashlightOnTimer.readSummaryFromParcelLocked(in);
|
||||
@@ -8763,6 +8868,12 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
|
||||
mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
|
||||
}
|
||||
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
|
||||
mBluetoothActivityCounters[i].writeSummaryFromParcelLocked(out);
|
||||
}
|
||||
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
|
||||
mWifiActivityCounters[i].writeSummaryFromParcelLocked(out);
|
||||
}
|
||||
out.writeInt(mNumConnectivityChange);
|
||||
mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
|
||||
|
||||
@@ -9067,6 +9178,15 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
|
||||
null, mOnBatteryTimeBase, in);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
|
||||
mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
|
||||
mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
|
||||
}
|
||||
|
||||
mNumConnectivityChange = in.readInt();
|
||||
mLoadedNumConnectivityChange = in.readInt();
|
||||
mUnpluggedNumConnectivityChange = in.readInt();
|
||||
@@ -9212,6 +9332,12 @@ public final class BatteryStatsImpl extends BatteryStats {
|
||||
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
|
||||
mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
|
||||
}
|
||||
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
|
||||
mBluetoothActivityCounters[i].writeToParcel(out);
|
||||
}
|
||||
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
|
||||
mWifiActivityCounters[i].writeToParcel(out);
|
||||
}
|
||||
out.writeInt(mNumConnectivityChange);
|
||||
out.writeInt(mLoadedNumConnectivityChange);
|
||||
out.writeInt(mUnpluggedNumConnectivityChange);
|
||||
|
||||
@@ -75,6 +75,11 @@ public class PowerProfile {
|
||||
*/
|
||||
public static final String POWER_WIFI_ACTIVE = "wifi.active";
|
||||
|
||||
/**
|
||||
* Operating voltage of the WiFi controller.
|
||||
*/
|
||||
public static final String OPERATING_VOLTAGE_WIFI = "wifi.voltage";
|
||||
|
||||
/**
|
||||
* Power consumption when GPS is on.
|
||||
*/
|
||||
@@ -95,6 +100,11 @@ 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.
|
||||
*/
|
||||
@@ -224,11 +234,13 @@ public class PowerProfile {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the average current in mA consumed by the subsystem
|
||||
* Returns the average current in mA consumed by the subsystem, or the given
|
||||
* default value if the subsystem has no recorded value.
|
||||
* @param type the subsystem type
|
||||
* @param defaultValue the value to return if the subsystem has no recorded value.
|
||||
* @return the average current in milliAmps.
|
||||
*/
|
||||
public double getAveragePower(String type) {
|
||||
public double getAveragePowerOrDefault(String type, double defaultValue) {
|
||||
if (sPowerMap.containsKey(type)) {
|
||||
Object data = sPowerMap.get(type);
|
||||
if (data instanceof Double[]) {
|
||||
@@ -237,9 +249,18 @@ public class PowerProfile {
|
||||
return (Double) sPowerMap.get(type);
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the average current in mA consumed by the subsystem
|
||||
* @param type the subsystem type
|
||||
* @return the average current in milliAmps.
|
||||
*/
|
||||
public double getAveragePower(String type) {
|
||||
return getAveragePowerOrDefault(type, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the average current in mA consumed by the subsystem for the given level.
|
||||
|
||||
Reference in New Issue
Block a user