Merge "Convert BatteryStats.dumpLocked from BatteryStatsHelper to BatteryUsageStats" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
7b32d78264
@@ -18,6 +18,8 @@ package android.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Contains power consumption data across the entire device.
|
||||
*
|
||||
@@ -37,6 +39,11 @@ public final class AggregateBatteryConsumer extends BatteryConsumer implements P
|
||||
mConsumedPowerMah = source.readDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, boolean skipEmptyComponents) {
|
||||
mPowerComponents.dump(pw, skipEmptyComponents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.os;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@@ -27,7 +28,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class BatteryConsumer {
|
||||
public abstract class BatteryConsumer {
|
||||
|
||||
/**
|
||||
* Power usage component, describing the particular part of the system
|
||||
@@ -85,12 +86,37 @@ public class BatteryConsumer {
|
||||
public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
|
||||
public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
|
||||
|
||||
private static final String[] sPowerComponentNames = new String[POWER_COMPONENT_COUNT];
|
||||
|
||||
static {
|
||||
// Assign individually to avoid future mismatch
|
||||
sPowerComponentNames[POWER_COMPONENT_SCREEN] = "screen";
|
||||
sPowerComponentNames[POWER_COMPONENT_CPU] = "cpu";
|
||||
sPowerComponentNames[POWER_COMPONENT_BLUETOOTH] = "bluetooth";
|
||||
sPowerComponentNames[POWER_COMPONENT_CAMERA] = "camera";
|
||||
sPowerComponentNames[POWER_COMPONENT_AUDIO] = "audio";
|
||||
sPowerComponentNames[POWER_COMPONENT_VIDEO] = "video";
|
||||
sPowerComponentNames[POWER_COMPONENT_FLASHLIGHT] = "flashlight";
|
||||
sPowerComponentNames[POWER_COMPONENT_SYSTEM_SERVICES] = "system_services";
|
||||
sPowerComponentNames[POWER_COMPONENT_MOBILE_RADIO] = "mobile_radio";
|
||||
sPowerComponentNames[POWER_COMPONENT_SENSORS] = "sensors";
|
||||
sPowerComponentNames[POWER_COMPONENT_GNSS] = "gnss";
|
||||
sPowerComponentNames[POWER_COMPONENT_WIFI] = "wifi";
|
||||
sPowerComponentNames[POWER_COMPONENT_WAKELOCK] = "wakelock";
|
||||
sPowerComponentNames[POWER_COMPONENT_MEMORY] = "memory";
|
||||
sPowerComponentNames[POWER_COMPONENT_PHONE] = "phone";
|
||||
sPowerComponentNames[POWER_COMPONENT_AMBIENT_DISPLAY] = "ambient_display";
|
||||
sPowerComponentNames[POWER_COMPONENT_IDLE] = "idle";
|
||||
sPowerComponentNames[POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS] = "reattributed";
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifiers of models used for power estimation.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = {"POWER_MODEL_"}, value = {
|
||||
POWER_MODEL_UNDEFINED,
|
||||
POWER_MODEL_POWER_PROFILE,
|
||||
POWER_MODEL_MEASURED_ENERGY,
|
||||
})
|
||||
@@ -98,16 +124,21 @@ public class BatteryConsumer {
|
||||
public @interface PowerModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unspecified power model.
|
||||
*/
|
||||
public static final int POWER_MODEL_UNDEFINED = 0;
|
||||
|
||||
/**
|
||||
* Power model that is based on average consumption rates that hardware components
|
||||
* consume in various states.
|
||||
*/
|
||||
public static final int POWER_MODEL_POWER_PROFILE = 0;
|
||||
public static final int POWER_MODEL_POWER_PROFILE = 1;
|
||||
|
||||
/**
|
||||
* Power model that is based on energy consumption measured by on-device power monitors.
|
||||
*/
|
||||
public static final int POWER_MODEL_MEASURED_ENERGY = 1;
|
||||
public static final int POWER_MODEL_MEASURED_ENERGY = 2;
|
||||
|
||||
protected final PowerComponents mPowerComponents;
|
||||
|
||||
@@ -197,6 +228,41 @@ public class BatteryConsumer {
|
||||
mPowerComponents.writeToParcel(dest, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the specified component. Intended for logging and debugging.
|
||||
*/
|
||||
public static String powerComponentIdToString(@BatteryConsumer.PowerComponent int componentId) {
|
||||
return sPowerComponentNames[componentId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the specified power model. Intended for logging and debugging.
|
||||
*/
|
||||
public static String powerModelToString(@BatteryConsumer.PowerModel int powerModel) {
|
||||
switch (powerModel) {
|
||||
case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
|
||||
return "measured energy";
|
||||
case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
|
||||
return "power profile";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the stats in a human-readable format.
|
||||
*/
|
||||
public void dump(PrintWriter pw) {
|
||||
dump(pw, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the stats in a human-readable format.
|
||||
*
|
||||
* @param skipEmptyComponents if true, omit any power components with a zero amount.
|
||||
*/
|
||||
public abstract void dump(PrintWriter pw, boolean skipEmptyComponents);
|
||||
|
||||
protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
|
||||
final PowerComponents.Builder mPowerComponentsBuilder;
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ import android.view.Display;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.os.BatterySipper;
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.internal.os.BatteryUsageStatsProvider;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -5299,154 +5300,19 @@ public abstract class BatteryStats implements Parcelable {
|
||||
pw.println(getDischargeAmountScreenDozeSinceCharge());
|
||||
pw.println();
|
||||
|
||||
final BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, this);
|
||||
final BatteryUsageStats stats = provider.getBatteryUsageStats(
|
||||
new BatteryUsageStatsQuery.Builder()
|
||||
.setMaxStatsAgeMs(0)
|
||||
.includePowerModels()
|
||||
.build());
|
||||
stats.dump(pw, prefix);
|
||||
|
||||
final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
|
||||
helper.create(this);
|
||||
helper.refreshStats(which, UserHandle.USER_ALL);
|
||||
List<BatterySipper> sippers = helper.getUsageList();
|
||||
if (sippers != null && sippers.size() > 0) {
|
||||
pw.print(prefix); pw.println(" Estimated power use (mAh):");
|
||||
pw.print(prefix); pw.print(" Capacity: ");
|
||||
printmAh(pw, helper.getPowerProfile().getBatteryCapacity());
|
||||
pw.print(", Computed drain: "); printmAh(pw, helper.getComputedPower());
|
||||
pw.print(", actual drain: "); printmAh(pw, helper.getMinDrainedPower());
|
||||
if (helper.getMinDrainedPower() != helper.getMaxDrainedPower()) {
|
||||
pw.print("-"); printmAh(pw, helper.getMaxDrainedPower());
|
||||
}
|
||||
pw.println();
|
||||
for (int i=0; i<sippers.size(); i++) {
|
||||
final BatterySipper bs = sippers.get(i);
|
||||
pw.print(prefix);
|
||||
switch (bs.drainType) {
|
||||
case AMBIENT_DISPLAY:
|
||||
pw.print(" Ambient display: ");
|
||||
break;
|
||||
case IDLE:
|
||||
pw.print(" Idle: ");
|
||||
break;
|
||||
case CELL:
|
||||
pw.print(" Cell standby: ");
|
||||
break;
|
||||
case PHONE:
|
||||
pw.print(" Phone calls: ");
|
||||
break;
|
||||
case WIFI:
|
||||
pw.print(" Wifi: ");
|
||||
break;
|
||||
case BLUETOOTH:
|
||||
pw.print(" Bluetooth: ");
|
||||
break;
|
||||
case SCREEN:
|
||||
pw.print(" Screen: ");
|
||||
break;
|
||||
case FLASHLIGHT:
|
||||
pw.print(" Flashlight: ");
|
||||
break;
|
||||
case APP:
|
||||
pw.print(" Uid ");
|
||||
UserHandle.formatUid(pw, bs.uidObj.getUid());
|
||||
pw.print(": ");
|
||||
break;
|
||||
case USER:
|
||||
pw.print(" User "); pw.print(bs.userId);
|
||||
pw.print(": ");
|
||||
break;
|
||||
case UNACCOUNTED:
|
||||
pw.print(" Unaccounted: ");
|
||||
break;
|
||||
case OVERCOUNTED:
|
||||
pw.print(" Over-counted: ");
|
||||
break;
|
||||
case CAMERA:
|
||||
pw.print(" Camera: ");
|
||||
break;
|
||||
default:
|
||||
pw.print(" ???: ");
|
||||
break;
|
||||
}
|
||||
printmAh(pw, bs.totalPowerMah);
|
||||
|
||||
if (bs.usagePowerMah != bs.totalPowerMah) {
|
||||
// If the usage (generic power) isn't the whole amount, we list out
|
||||
// what components are involved in the calculation.
|
||||
|
||||
pw.print(" (");
|
||||
if (bs.usagePowerMah != 0) {
|
||||
pw.print(" usage=");
|
||||
printmAh(pw, bs.usagePowerMah);
|
||||
}
|
||||
if (bs.cpuPowerMah != 0) {
|
||||
pw.print(" cpu=");
|
||||
printmAh(pw, bs.cpuPowerMah);
|
||||
}
|
||||
if (bs.wakeLockPowerMah != 0) {
|
||||
pw.print(" wake=");
|
||||
printmAh(pw, bs.wakeLockPowerMah);
|
||||
}
|
||||
if (bs.mobileRadioPowerMah != 0) {
|
||||
pw.print(" radio=");
|
||||
printmAh(pw, bs.mobileRadioPowerMah);
|
||||
}
|
||||
if (bs.wifiPowerMah != 0) {
|
||||
pw.print(" wifi=");
|
||||
printmAh(pw, bs.wifiPowerMah);
|
||||
}
|
||||
if (bs.bluetoothPowerMah != 0) {
|
||||
pw.print(" bt=");
|
||||
printmAh(pw, bs.bluetoothPowerMah);
|
||||
}
|
||||
if (bs.gpsPowerMah != 0) {
|
||||
pw.print(" gps=");
|
||||
printmAh(pw, bs.gpsPowerMah);
|
||||
}
|
||||
if (bs.sensorPowerMah != 0) {
|
||||
pw.print(" sensor=");
|
||||
printmAh(pw, bs.sensorPowerMah);
|
||||
}
|
||||
if (bs.cameraPowerMah != 0) {
|
||||
pw.print(" camera=");
|
||||
printmAh(pw, bs.cameraPowerMah);
|
||||
}
|
||||
if (bs.flashlightPowerMah != 0) {
|
||||
pw.print(" flash=");
|
||||
printmAh(pw, bs.flashlightPowerMah);
|
||||
}
|
||||
if (bs.customMeasuredPowerMah != null) {
|
||||
for (int idx = 0; idx < bs.customMeasuredPowerMah.length; idx++) {
|
||||
final double customPowerMah = bs.customMeasuredPowerMah[idx];
|
||||
if (customPowerMah != 0) {
|
||||
pw.print(" custom[" + idx + "]=");
|
||||
printmAh(pw, customPowerMah);
|
||||
}
|
||||
}
|
||||
}
|
||||
pw.print(" )");
|
||||
}
|
||||
|
||||
// If there is additional smearing information, include it.
|
||||
if (bs.totalSmearedPowerMah != bs.totalPowerMah) {
|
||||
pw.print(" Including smearing: ");
|
||||
printmAh(pw, bs.totalSmearedPowerMah);
|
||||
pw.print(" (");
|
||||
if (bs.screenPowerMah != 0) {
|
||||
pw.print(" screen=");
|
||||
printmAh(pw, bs.screenPowerMah);
|
||||
}
|
||||
if (bs.proportionalSmearMah != 0) {
|
||||
pw.print(" proportional=");
|
||||
printmAh(pw, bs.proportionalSmearMah);
|
||||
}
|
||||
pw.print(" )");
|
||||
}
|
||||
if (bs.shouldHide) {
|
||||
pw.print(" Excluded from smearing");
|
||||
}
|
||||
|
||||
pw.println();
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
|
||||
sippers = helper.getMobilemsppList();
|
||||
final List<BatterySipper> sippers = helper.getMobilemsppList();
|
||||
if (sippers != null && sippers.size() > 0) {
|
||||
pw.print(prefix); pw.println(" Per-app mobile ms per packet:");
|
||||
long totalTime = 0;
|
||||
|
||||
@@ -23,10 +23,13 @@ import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.os.BatteryStatsHistory;
|
||||
import com.android.internal.os.BatteryStatsHistoryIterator;
|
||||
import com.android.internal.os.PowerCalculator;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -73,6 +76,7 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
|
||||
private final int mDischargePercentage;
|
||||
private final long mStatsStartTimestampMs;
|
||||
private final double mBatteryCapacityMah;
|
||||
private final double mDischargedPowerLowerBound;
|
||||
private final double mDischargedPowerUpperBound;
|
||||
private final long mBatteryTimeRemainingMs;
|
||||
@@ -86,6 +90,7 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
|
||||
private BatteryUsageStats(@NonNull Builder builder) {
|
||||
mStatsStartTimestampMs = builder.mStatsStartTimestampMs;
|
||||
mBatteryCapacityMah = builder.mBatteryCapacityMah;
|
||||
mDischargePercentage = builder.mDischargePercentage;
|
||||
mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah;
|
||||
mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
|
||||
@@ -144,6 +149,13 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
.getConsumedPower();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns battery capacity in milli-amp-hours.
|
||||
*/
|
||||
public double getBatteryCapacity() {
|
||||
return mBatteryCapacityMah;
|
||||
}
|
||||
|
||||
/**
|
||||
* Portion of battery charge drained since BatteryStats reset (e.g. due to being fully
|
||||
* charged), as percentage of the full charge in the range [0:100]
|
||||
@@ -217,6 +229,7 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
|
||||
private BatteryUsageStats(@NonNull Parcel source) {
|
||||
mStatsStartTimestampMs = source.readLong();
|
||||
mBatteryCapacityMah = source.readDouble();
|
||||
mDischargePercentage = source.readInt();
|
||||
mDischargedPowerLowerBound = source.readDouble();
|
||||
mDischargedPowerUpperBound = source.readDouble();
|
||||
@@ -274,6 +287,7 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeLong(mStatsStartTimestampMs);
|
||||
dest.writeDouble(mBatteryCapacityMah);
|
||||
dest.writeInt(mDischargePercentage);
|
||||
dest.writeDouble(mDischargedPowerLowerBound);
|
||||
dest.writeDouble(mDischargedPowerUpperBound);
|
||||
@@ -321,6 +335,104 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Prints the stats in a human-readable format.
|
||||
*/
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
pw.print(prefix);
|
||||
pw.println(" Estimated power use (mAh):");
|
||||
pw.print(prefix);
|
||||
pw.print(" Capacity: ");
|
||||
PowerCalculator.printPowerMah(pw, getBatteryCapacity());
|
||||
pw.print(", Computed drain: ");
|
||||
PowerCalculator.printPowerMah(pw, getConsumedPower());
|
||||
final Range<Double> dischargedPowerRange = getDischargedPowerRange();
|
||||
pw.print(", actual drain: ");
|
||||
PowerCalculator.printPowerMah(pw, dischargedPowerRange.getLower());
|
||||
if (!dischargedPowerRange.getLower().equals(dischargedPowerRange.getUpper())) {
|
||||
pw.print("-");
|
||||
PowerCalculator.printPowerMah(pw, dischargedPowerRange.getUpper());
|
||||
}
|
||||
pw.println();
|
||||
|
||||
pw.println(" Global");
|
||||
final BatteryConsumer deviceConsumer = getAggregateBatteryConsumer(
|
||||
AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
|
||||
final BatteryConsumer appsConsumer = getAggregateBatteryConsumer(
|
||||
AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS);
|
||||
|
||||
for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
|
||||
componentId++) {
|
||||
final double devicePowerMah = deviceConsumer.getConsumedPower(componentId);
|
||||
final double appsPowerMah = appsConsumer.getConsumedPower(componentId);
|
||||
if (devicePowerMah == 0 && appsPowerMah == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String componentName = BatteryConsumer.powerComponentIdToString(componentId);
|
||||
printPowerComponent(pw, prefix, componentName, devicePowerMah, appsPowerMah,
|
||||
deviceConsumer.getPowerModel(componentId),
|
||||
deviceConsumer.getUsageDurationMillis(componentId));
|
||||
}
|
||||
|
||||
for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
|
||||
+ mCustomPowerComponentNames.length;
|
||||
componentId++) {
|
||||
final double devicePowerMah =
|
||||
deviceConsumer.getConsumedPowerForCustomComponent(componentId);
|
||||
final double appsPowerMah =
|
||||
appsConsumer.getConsumedPowerForCustomComponent(componentId);
|
||||
if (devicePowerMah == 0 && appsPowerMah == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
printPowerComponent(pw, prefix, deviceConsumer.getCustomPowerComponentName(componentId),
|
||||
devicePowerMah, appsPowerMah,
|
||||
BatteryConsumer.POWER_MODEL_UNDEFINED,
|
||||
deviceConsumer.getUsageDurationForCustomComponentMillis(componentId));
|
||||
}
|
||||
|
||||
dumpSortedBatteryConsumers(pw, prefix, getUidBatteryConsumers());
|
||||
dumpSortedBatteryConsumers(pw, prefix, getUserBatteryConsumers());
|
||||
}
|
||||
|
||||
private void printPowerComponent(PrintWriter pw, String prefix, String componentName,
|
||||
double devicePowerMah, double appsPowerMah, int powerModel, long durationMs) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(prefix).append(" ").append(componentName).append(": ")
|
||||
.append(PowerCalculator.formatCharge(devicePowerMah));
|
||||
if (powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED
|
||||
&& powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
|
||||
sb.append(" [");
|
||||
sb.append(BatteryConsumer.powerModelToString(powerModel));
|
||||
sb.append("]");
|
||||
}
|
||||
sb.append(" apps: ").append(PowerCalculator.formatCharge(appsPowerMah));
|
||||
if (durationMs != 0) {
|
||||
sb.append(" duration: ");
|
||||
BatteryStats.formatTimeMs(sb, durationMs);
|
||||
}
|
||||
|
||||
pw.println(sb.toString());
|
||||
}
|
||||
|
||||
private void dumpSortedBatteryConsumers(PrintWriter pw, String prefix,
|
||||
List<? extends BatteryConsumer> batteryConsumers) {
|
||||
batteryConsumers.sort(
|
||||
Comparator.<BatteryConsumer>comparingDouble(BatteryConsumer::getConsumedPower)
|
||||
.reversed());
|
||||
for (BatteryConsumer consumer : batteryConsumers) {
|
||||
if (consumer.getConsumedPower() == 0) {
|
||||
continue;
|
||||
}
|
||||
pw.print(prefix);
|
||||
pw.print(" ");
|
||||
consumer.dump(pw);
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for BatteryUsageStats.
|
||||
*/
|
||||
@@ -329,6 +441,7 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
private final String[] mCustomPowerComponentNames;
|
||||
private final boolean mIncludePowerModels;
|
||||
private long mStatsStartTimestampMs;
|
||||
private double mBatteryCapacityMah;
|
||||
private int mDischargePercentage;
|
||||
private double mDischargedPowerLowerBoundMah;
|
||||
private double mDischargedPowerUpperBoundMah;
|
||||
@@ -364,6 +477,14 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
return new BatteryUsageStats(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the battery capacity in milli-amp-hours.
|
||||
*/
|
||||
public Builder setBatteryCapacity(double batteryCapacityMah) {
|
||||
mBatteryCapacityMah = batteryCapacityMah;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp of the latest battery stats reset, in milliseconds.
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,10 @@ package android.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.internal.os.PowerCalculator;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Contains details of battery attribution data broken down to individual power drain types
|
||||
* such as CPU, RAM, GPU etc.
|
||||
@@ -202,6 +206,37 @@ class PowerComponents {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, boolean skipEmptyComponents) {
|
||||
String separator = "";
|
||||
for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
|
||||
componentId++) {
|
||||
final double componentPower = getConsumedPower(componentId);
|
||||
if (skipEmptyComponents && componentPower == 0) {
|
||||
continue;
|
||||
}
|
||||
pw.print(separator); separator = " ";
|
||||
pw.print(BatteryConsumer.powerComponentIdToString(componentId));
|
||||
pw.print("=");
|
||||
PowerCalculator.printPowerMah(pw, componentPower);
|
||||
}
|
||||
|
||||
final int customComponentCount = getCustomPowerComponentCount();
|
||||
for (int customComponentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
customComponentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
|
||||
+ customComponentCount;
|
||||
customComponentId++) {
|
||||
final double customComponentPower =
|
||||
getConsumedPowerForCustomComponent(customComponentId);
|
||||
if (skipEmptyComponents && customComponentPower == 0) {
|
||||
continue;
|
||||
}
|
||||
pw.print(separator); separator = " ";
|
||||
pw.print(getCustomPowerComponentName(customComponentId));
|
||||
pw.print("=");
|
||||
PowerCalculator.printPowerMah(pw, customComponentPower);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for PowerComponents.
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,9 @@ import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import com.android.internal.os.PowerCalculator;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@@ -112,6 +115,18 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
|
||||
dest.writeLong(mTimeInBackgroundMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, boolean skipEmptyComponents) {
|
||||
final double consumedPower = getConsumedPower();
|
||||
pw.print("UID ");
|
||||
UserHandle.formatUid(pw, getUid());
|
||||
pw.print(": ");
|
||||
PowerCalculator.printPowerMah(pw, consumedPower);
|
||||
pw.print(" ( ");
|
||||
mPowerComponents.dump(pw, skipEmptyComponents /* skipTotalPowerComponent */);
|
||||
pw.print(" ) ");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<UidBatteryConsumer> CREATOR = new Creator<UidBatteryConsumer>() {
|
||||
public UidBatteryConsumer createFromParcel(@NonNull Parcel source) {
|
||||
|
||||
@@ -18,6 +18,9 @@ package android.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.internal.os.PowerCalculator;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -52,6 +55,18 @@ public class UserBatteryConsumer extends BatteryConsumer implements Parcelable {
|
||||
dest.writeInt(mUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, boolean skipEmptyComponents) {
|
||||
final double consumedPower = getConsumedPower();
|
||||
pw.print("User ");
|
||||
pw.print(mUserId);
|
||||
pw.print(": ");
|
||||
PowerCalculator.printPowerMah(pw, consumedPower);
|
||||
pw.print(" ( ");
|
||||
mPowerComponents.dump(pw, skipEmptyComponents /* skipTotalPowerComponent */);
|
||||
pw.print(" ) ");
|
||||
}
|
||||
|
||||
public static final Creator<UserBatteryConsumer> CREATOR =
|
||||
new Creator<UserBatteryConsumer>() {
|
||||
@Override
|
||||
|
||||
@@ -42,6 +42,8 @@ public class BatteryChargeCalculator extends PowerCalculator {
|
||||
batteryCapacityMah = batteryStats.getEstimatedBatteryCapacity();
|
||||
}
|
||||
}
|
||||
builder.setBatteryCapacity(batteryCapacityMah);
|
||||
|
||||
final double dischargedPowerLowerBoundMah =
|
||||
batteryStats.getLowDischargeAmountSinceCharge() * batteryCapacityMah / 100.0;
|
||||
final double dischargedPowerUpperBoundMah =
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.os.UidBatteryConsumer;
|
||||
import android.os.UserHandle;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -157,6 +158,12 @@ public abstract class PowerCalculator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints formatted amount of power in milli-amp-hours.
|
||||
*/
|
||||
public static void printPowerMah(PrintWriter pw, double powerMah) {
|
||||
pw.print(formatCharge(powerMah));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts charge in mAh to string.
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.os.BatteryConsumer;
|
||||
import android.os.BatteryUsageStats;
|
||||
import android.os.Parcel;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.os.UserBatteryConsumer;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
@@ -31,7 +32,11 @@ import androidx.test.runner.AndroidJUnit4;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -60,13 +65,42 @@ public class BatteryUsageStatsTest {
|
||||
validateBatteryUsageStats(inBatteryUsageStats);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDump() {
|
||||
final BatteryUsageStats stats = buildBatteryUsageStats();
|
||||
final StringWriter out = new StringWriter();
|
||||
try (PrintWriter pw = new PrintWriter(out)) {
|
||||
stats.dump(pw, " ");
|
||||
}
|
||||
final String dump = out.toString();
|
||||
|
||||
assertThat(dump).contains("Capacity: 4000");
|
||||
assertThat(dump).contains("Computed drain: 30000");
|
||||
assertThat(dump).contains("actual drain: 1000-2000");
|
||||
assertThat(dump).contains("cpu: 20100 apps: 10100 duration: 20s 300ms");
|
||||
assertThat(dump).contains("FOO: 20200 apps: 10200 duration: 20s 400ms");
|
||||
assertThat(dump).contains("UID 2000: 1200 ( screen=300 cpu=400 FOO=500 )");
|
||||
assertThat(dump).contains("User 42: 30.0 ( cpu=10.0 FOO=20.0 )");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPowerComponentNames_existAndUnique() {
|
||||
Set<String> allNames = new HashSet<>();
|
||||
for (int i = 0; i < BatteryConsumer.POWER_COMPONENT_COUNT; i++) {
|
||||
assertThat(BatteryConsumer.powerComponentIdToString(i)).isNotNull();
|
||||
allNames.add(BatteryConsumer.powerComponentIdToString(i));
|
||||
}
|
||||
assertThat(allNames).hasSize(BatteryConsumer.POWER_COMPONENT_COUNT);
|
||||
}
|
||||
|
||||
private BatteryUsageStats buildBatteryUsageStats() {
|
||||
final MockClocks clocks = new MockClocks();
|
||||
final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
|
||||
final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);
|
||||
|
||||
final BatteryUsageStats.Builder builder =
|
||||
new BatteryUsageStats.Builder(new String[]{"FOO"})
|
||||
new BatteryUsageStats.Builder(new String[]{"FOO"}, true)
|
||||
.setBatteryCapacity(4000)
|
||||
.setDischargePercentage(20)
|
||||
.setDischargedPowerRange(1000, 2000)
|
||||
.setStatsStartTimestamp(1000);
|
||||
@@ -108,11 +142,22 @@ public class BatteryUsageStatsTest {
|
||||
.setUsageDurationForCustomComponentMillis(
|
||||
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 20400);
|
||||
|
||||
builder.getOrCreateUserBatteryConsumerBuilder(42)
|
||||
.setConsumedPower(
|
||||
BatteryConsumer.POWER_COMPONENT_CPU, 10)
|
||||
.setConsumedPowerForCustomComponent(
|
||||
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 20)
|
||||
.setUsageDurationMillis(
|
||||
BatteryConsumer.POWER_COMPONENT_CPU, 30)
|
||||
.setUsageDurationForCustomComponentMillis(
|
||||
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 40);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public void validateBatteryUsageStats(BatteryUsageStats batteryUsageStats) {
|
||||
assertThat(batteryUsageStats.getConsumedPower()).isEqualTo(30000);
|
||||
assertThat(batteryUsageStats.getBatteryCapacity()).isEqualTo(4000);
|
||||
assertThat(batteryUsageStats.getDischargePercentage()).isEqualTo(20);
|
||||
assertThat(batteryUsageStats.getDischargedPowerRange().getLower()).isEqualTo(1000);
|
||||
assertThat(batteryUsageStats.getDischargedPowerRange().getUpper()).isEqualTo(2000);
|
||||
@@ -173,5 +218,26 @@ public class BatteryUsageStatsTest {
|
||||
assertThat(deviceBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1);
|
||||
assertThat(deviceBatteryConsumer.getCustomPowerComponentName(
|
||||
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO");
|
||||
|
||||
final List<UserBatteryConsumer> userBatteryConsumers =
|
||||
batteryUsageStats.getUserBatteryConsumers();
|
||||
for (UserBatteryConsumer userBatteryConsumer : userBatteryConsumers) {
|
||||
if (userBatteryConsumer.getUserId() == 42) {
|
||||
assertThat(userBatteryConsumer.getConsumedPower(
|
||||
BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10);
|
||||
assertThat(userBatteryConsumer.getConsumedPowerForCustomComponent(
|
||||
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(20);
|
||||
assertThat(userBatteryConsumer.getUsageDurationMillis(
|
||||
BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(30);
|
||||
assertThat(userBatteryConsumer.getUsageDurationForCustomComponentMillis(
|
||||
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(40);
|
||||
assertThat(userBatteryConsumer.getConsumedPower()).isEqualTo(30);
|
||||
assertThat(userBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1);
|
||||
assertThat(userBatteryConsumer.getCustomPowerComponentName(
|
||||
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO");
|
||||
} else {
|
||||
fail("Unexpected user ID " + userBatteryConsumer.getUserId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user