MeasuredEnergyStats supports custom energy buckets
MeasuredEnergyStats now supports a variable number of 'buckets', including both the standard buckets (fixed number) and additional custom buckets (variable number) whose meaning is unknown to BatteryStats (but is enumerated as an 'ordinal'). This will be used to store per-uid energy data from custom power components. Test: atest MeasuredEnergyStatsTest Test: atest com.android.internal.os.BatteryStatsTests Bug: 179107328 Bug: 174186358 Change-Id: I0022ac6940daca5f1e7d0e502eed01effa71f796
This commit is contained in:
@@ -21,8 +21,6 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||
import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
|
||||
import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
|
||||
|
||||
import static com.android.internal.power.MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -107,7 +105,7 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeRea
|
||||
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
|
||||
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
|
||||
import com.android.internal.power.MeasuredEnergyStats;
|
||||
import com.android.internal.power.MeasuredEnergyStats.EnergyBucket;
|
||||
import com.android.internal.power.MeasuredEnergyStats.StandardEnergyBucket;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FastPrintWriter;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
@@ -173,7 +171,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
|
||||
|
||||
// Current on-disk Parcel version
|
||||
static final int VERSION = 192 + (USE_OLD_HISTORY ? 1000 : 0);
|
||||
static final int VERSION = 193 + (USE_OLD_HISTORY ? 1000 : 0);
|
||||
|
||||
// The maximum number of names wakelocks we will keep track of
|
||||
// per uid; once the limit is reached, we batch the remaining wakelocks
|
||||
@@ -7161,8 +7159,8 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
if (mGlobalMeasuredEnergyStats == null) {
|
||||
return ENERGY_DATA_UNAVAILABLE;
|
||||
}
|
||||
return mGlobalMeasuredEnergyStats.getAccumulatedBucketEnergy(
|
||||
MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON);
|
||||
return mGlobalMeasuredEnergyStats
|
||||
.getAccumulatedStandardBucketEnergy(MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -7170,8 +7168,8 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
if (mGlobalMeasuredEnergyStats == null) {
|
||||
return ENERGY_DATA_UNAVAILABLE;
|
||||
}
|
||||
return mGlobalMeasuredEnergyStats.getAccumulatedBucketEnergy(
|
||||
MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE);
|
||||
return mGlobalMeasuredEnergyStats
|
||||
.getAccumulatedStandardBucketEnergy(MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE);
|
||||
}
|
||||
|
||||
@Override public long getStartClockTime() {
|
||||
@@ -7935,27 +7933,27 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
return mUidMeasuredEnergyStats;
|
||||
}
|
||||
|
||||
/** Adds the given energy to the given energy bucket for this uid. */
|
||||
private void addEnergyToEnergyBucketLocked(long energyDeltaUJ,
|
||||
@MeasuredEnergyStats.EnergyBucket int energyBucket, boolean accumulate) {
|
||||
/** Adds the given energy to the given standard energy bucket for this uid. */
|
||||
private void addEnergyToStandardBucketLocked(long energyDeltaUJ,
|
||||
@StandardEnergyBucket int energyBucket, boolean accumulate) {
|
||||
getOrCreateMeasuredEnergyStatsLocked()
|
||||
.updateBucket(energyBucket, energyDeltaUJ, accumulate);
|
||||
.updateStandardBucket(energyBucket, energyDeltaUJ, accumulate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the energy used by this uid for an energy bucket of interest.
|
||||
* @param bucket energy bucket of interest
|
||||
* Returns the energy used by this uid for a standard energy bucket of interest.
|
||||
* @param bucket standard energy bucket of interest
|
||||
* @return energy (in microjoules) used by this uid for this energy bucket
|
||||
*/
|
||||
public long getMeasuredEnergyMicroJoules(@MeasuredEnergyStats.EnergyBucket int bucket) {
|
||||
public long getMeasuredEnergyMicroJoules(@StandardEnergyBucket int bucket) {
|
||||
if (mBsi.mGlobalMeasuredEnergyStats == null
|
||||
|| !mBsi.mGlobalMeasuredEnergyStats.isEnergyBucketSupported(bucket)) {
|
||||
|| !mBsi.mGlobalMeasuredEnergyStats.isStandardBucketSupported(bucket)) {
|
||||
return ENERGY_DATA_UNAVAILABLE;
|
||||
}
|
||||
if (mUidMeasuredEnergyStats == null) {
|
||||
return 0L; // It is supported, but was never filled, so it must be 0
|
||||
}
|
||||
return mUidMeasuredEnergyStats.getAccumulatedBucketEnergy(bucket);
|
||||
return mUidMeasuredEnergyStats.getAccumulatedStandardBucketEnergy(bucket);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -12396,7 +12394,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
return;
|
||||
}
|
||||
|
||||
final @EnergyBucket int energyBucket =
|
||||
final @StandardEnergyBucket int energyBucket =
|
||||
MeasuredEnergyStats.getDisplayEnergyBucket(mScreenStateAtLastEnergyMeasurement);
|
||||
mScreenStateAtLastEnergyMeasurement = screenState;
|
||||
|
||||
@@ -12415,7 +12413,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
return;
|
||||
}
|
||||
|
||||
mGlobalMeasuredEnergyStats.updateBucket(energyBucket, energyUJ, true);
|
||||
mGlobalMeasuredEnergyStats.updateStandardBucket(energyBucket, energyUJ, true);
|
||||
|
||||
// Now we blame individual apps, but only if the display was ON.
|
||||
if (energyBucket != MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON) {
|
||||
@@ -12453,7 +12451,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
final long appDisplayEnergyMJ =
|
||||
(totalDisplayEnergyMJ * fgTimeMs + (totalFgTimeMs / 2))
|
||||
/ totalFgTimeMs;
|
||||
uid.addEnergyToEnergyBucketLocked(appDisplayEnergyMJ * 1000, energyBucket, true);
|
||||
uid.addEnergyToStandardBucketLocked(appDisplayEnergyMJ * 1000, energyBucket, true);
|
||||
|
||||
// To mitigate round-off errors, remove this app from numerator & denominator totals
|
||||
totalDisplayEnergyMJ -= appDisplayEnergyMJ;
|
||||
@@ -14138,33 +14136,34 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
/**
|
||||
* Initialize the measured energy stats data structures.
|
||||
*
|
||||
* @param supportedEnergyBuckets boolean array indicating which buckets are currently supported
|
||||
* @param supportedStandardBuckets boolean array indicating which {@link StandardEnergyBucket}s
|
||||
* are currently supported.
|
||||
* If null, none are supported (regardless of numCustomBuckets).
|
||||
* @param numCustomBuckets number of custom (OTHER) EnergyConsumers on this device
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
public void initMeasuredEnergyStatsLocked(boolean[] supportedEnergyBuckets) {
|
||||
public void initMeasuredEnergyStatsLocked(@Nullable boolean[] supportedStandardBuckets,
|
||||
int numCustomBuckets) {
|
||||
boolean supportedBucketMismatch = false;
|
||||
mScreenStateAtLastEnergyMeasurement = mScreenState;
|
||||
|
||||
if (supportedEnergyBuckets == null) {
|
||||
if (supportedStandardBuckets == null) {
|
||||
if (mGlobalMeasuredEnergyStats != null) {
|
||||
// Measured energy buckets no longer supported, wipe out the existing data.
|
||||
supportedBucketMismatch = true;
|
||||
}
|
||||
} else if (mGlobalMeasuredEnergyStats == null) {
|
||||
mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedEnergyBuckets);
|
||||
mGlobalMeasuredEnergyStats
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
return;
|
||||
} else {
|
||||
for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
|
||||
if (mGlobalMeasuredEnergyStats.isEnergyBucketSupported(i)
|
||||
!= supportedEnergyBuckets[i]) {
|
||||
mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedEnergyBuckets);
|
||||
supportedBucketMismatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
supportedBucketMismatch = !mGlobalMeasuredEnergyStats.isSupportEqualTo(
|
||||
supportedStandardBuckets, numCustomBuckets);
|
||||
}
|
||||
|
||||
if (supportedBucketMismatch) {
|
||||
mGlobalMeasuredEnergyStats = supportedStandardBuckets == null ?
|
||||
null : new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
// Supported energy buckets changed since last boot.
|
||||
// Existing data is no longer reliable.
|
||||
resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime());
|
||||
|
||||
@@ -20,8 +20,10 @@ package com.android.internal.power;
|
||||
import static android.os.BatteryStats.ENERGY_DATA_UNAVAILABLE;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
import android.util.DebugUtils;
|
||||
import android.util.Slog;
|
||||
import android.view.Display;
|
||||
|
||||
@@ -33,7 +35,9 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Tracks the measured energy usage of various subsystems according to their {@link EnergyBucket}.
|
||||
* Tracks the measured energy usage of various subsystems according to their
|
||||
* {@link StandardEnergyBucket} or custom energy bucket (which is tied to
|
||||
* {@link android.hardware.power.stats.EnergyConsumer.ordinal}).
|
||||
*
|
||||
* This class doesn't use a TimeBase, and instead requires manually decisions about when to
|
||||
* accumulate since it is trivial. However, in the future, a TimeBase could be used instead.
|
||||
@@ -42,15 +46,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
public class MeasuredEnergyStats {
|
||||
private static final String TAG = "MeasuredEnergyStats";
|
||||
|
||||
// Note: {@link com.android.internal.os.BatteryStatsImpl#VERSION} must be updated if energy
|
||||
// bucket integers are modified.
|
||||
// Note: {@link com.android.internal.os.BatteryStatsImpl#VERSION} MUST be updated if standard
|
||||
// energy bucket integers are modified/added/removed.
|
||||
public static final int ENERGY_BUCKET_UNKNOWN = -1;
|
||||
public static final int ENERGY_BUCKET_SCREEN_ON = 0;
|
||||
public static final int ENERGY_BUCKET_SCREEN_DOZE = 1;
|
||||
public static final int ENERGY_BUCKET_SCREEN_OTHER = 2;
|
||||
public static final int NUMBER_ENERGY_BUCKETS = 3;
|
||||
private static final String[] ENERGY_BUCKET_NAMES =
|
||||
{"screen-on", "screen-doze", "screen-other"};
|
||||
public static final int NUMBER_STANDARD_ENERGY_BUCKETS = 3; // Buckets above this are custom.
|
||||
|
||||
@IntDef(prefix = {"ENERGY_BUCKET_"}, value = {
|
||||
ENERGY_BUCKET_UNKNOWN,
|
||||
@@ -59,28 +61,37 @@ public class MeasuredEnergyStats {
|
||||
ENERGY_BUCKET_SCREEN_OTHER,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface EnergyBucket {
|
||||
public @interface StandardEnergyBucket {
|
||||
}
|
||||
|
||||
/**
|
||||
* Total energy (in microjoules) that an {@link EnergyBucket} has accumulated since the last
|
||||
* reset. Values MUST be non-zero or ENERGY_DATA_UNAVAILABLE. Accumulation only occurs
|
||||
* Total energy (in microjoules) that an energy bucket (including both
|
||||
* {@link StandardEnergyBucket} and custom buckets) has accumulated since the last reset.
|
||||
* Values MUST be non-zero or ENERGY_DATA_UNAVAILABLE. Accumulation only occurs
|
||||
* while the necessary conditions are satisfied (e.g. on battery).
|
||||
*
|
||||
* Energy for both {@link StandardEnergyBucket}s and custom energy buckets are stored in this
|
||||
* array, and may internally both referred to as 'buckets'. This is an implementation detail;
|
||||
* externally, we differentiate between these two data sources.
|
||||
*
|
||||
* Warning: Long array is used for access speed. If the number of supported subsystems
|
||||
* becomes large, consider using an alternate data structure such as a SparseLongArray.
|
||||
*/
|
||||
private final long[] mAccumulatedEnergiesMicroJoules = new long[NUMBER_ENERGY_BUCKETS];
|
||||
private final long[] mAccumulatedEnergiesMicroJoules;
|
||||
|
||||
/**
|
||||
* Creates a MeasuredEnergyStats set to support the provided energy buckets.
|
||||
* supportedEnergyBuckets should generally be of size {@link #NUMBER_ENERGY_BUCKETS}.
|
||||
* supportedStandardBuckets must be of size {@link #NUMBER_STANDARD_ENERGY_BUCKETS}.
|
||||
* numCustomBuckets >= 0 is the number of (non-standard) custom energy buckets on the device.
|
||||
*/
|
||||
public MeasuredEnergyStats(boolean[] supportedEnergyBuckets) {
|
||||
public MeasuredEnergyStats(boolean[] supportedStandardBuckets, int numCustomBuckets) {
|
||||
final int numTotalBuckets = NUMBER_STANDARD_ENERGY_BUCKETS + numCustomBuckets;
|
||||
mAccumulatedEnergiesMicroJoules = new long[numTotalBuckets];
|
||||
// Initialize to all zeros where supported, otherwise ENERGY_DATA_UNAVAILABLE.
|
||||
for (int bucket = 0; bucket < NUMBER_ENERGY_BUCKETS; bucket++) {
|
||||
if (!supportedEnergyBuckets[bucket]) {
|
||||
mAccumulatedEnergiesMicroJoules[bucket] = ENERGY_DATA_UNAVAILABLE;
|
||||
// All custom buckets are, by definition, supported, so their values stay at 0.
|
||||
for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_ENERGY_BUCKETS; stdBucket++) {
|
||||
if (!supportedStandardBuckets[stdBucket]) {
|
||||
mAccumulatedEnergiesMicroJoules[stdBucket] = ENERGY_DATA_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,10 +101,13 @@ public class MeasuredEnergyStats {
|
||||
* supported. This certainly does NOT produce an exact clone of the template.
|
||||
*/
|
||||
private MeasuredEnergyStats(MeasuredEnergyStats template) {
|
||||
final int numIndices = template.getNumberOfIndices();
|
||||
mAccumulatedEnergiesMicroJoules = new long[numIndices];
|
||||
// Initialize to all zeros where supported, otherwise ENERGY_DATA_UNAVAILABLE.
|
||||
for (int bucket = 0; bucket < NUMBER_ENERGY_BUCKETS; bucket++) {
|
||||
if (!template.isEnergyBucketSupported(bucket)) {
|
||||
mAccumulatedEnergiesMicroJoules[bucket] = ENERGY_DATA_UNAVAILABLE;
|
||||
// All custom buckets are, by definition, supported, so their values stay at 0.
|
||||
for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_ENERGY_BUCKETS; stdBucket++) {
|
||||
if (!template.isIndexSupported(stdBucket)) {
|
||||
mAccumulatedEnergiesMicroJoules[stdBucket] = ENERGY_DATA_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,18 +122,22 @@ public class MeasuredEnergyStats {
|
||||
|
||||
/**
|
||||
* Constructor for creating a temp MeasuredEnergyStats.
|
||||
* See {@link #readSummaryFromParcel(MeasuredEnergyStats, Parcel)}.
|
||||
* See {@link #createAndReadSummaryFromParcel(Parcel, MeasuredEnergyStats)}.
|
||||
*/
|
||||
private MeasuredEnergyStats() {
|
||||
private MeasuredEnergyStats(int numIndices) {
|
||||
mAccumulatedEnergiesMicroJoules = new long[numIndices];
|
||||
}
|
||||
|
||||
/** Construct from parcel. */
|
||||
public MeasuredEnergyStats(Parcel in) {
|
||||
final int size = in.readInt();
|
||||
mAccumulatedEnergiesMicroJoules = new long[size];
|
||||
in.readLongArray(mAccumulatedEnergiesMicroJoules);
|
||||
}
|
||||
|
||||
/** Write to parcel */
|
||||
public void writeToParcel(Parcel out) {
|
||||
out.writeInt(mAccumulatedEnergiesMicroJoules.length);
|
||||
out.writeLongArray(mAccumulatedEnergiesMicroJoules);
|
||||
}
|
||||
|
||||
@@ -129,16 +147,18 @@ public class MeasuredEnergyStats {
|
||||
* summary parcel was written. Availability has already been correctly set in the constructor.
|
||||
* Note: {@link com.android.internal.os.BatteryStatsImpl#VERSION} must be updated if summary
|
||||
* parceling changes.
|
||||
*
|
||||
* Corresponding write performed by {@link #writeSummaryToParcel(Parcel, boolean)}.
|
||||
*/
|
||||
private void readSummaryFromParcel(Parcel in, boolean overwriteAvailability) {
|
||||
final int size = in.readInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final int bucket = in.readInt();
|
||||
final int numWrittenEntries = in.readInt();
|
||||
for (int entry = 0; entry < numWrittenEntries; entry++) {
|
||||
final int index = in.readInt();
|
||||
final long energyUJ = in.readLong();
|
||||
if (overwriteAvailability) {
|
||||
mAccumulatedEnergiesMicroJoules[bucket] = energyUJ;
|
||||
mAccumulatedEnergiesMicroJoules[index] = energyUJ;
|
||||
} else {
|
||||
setValueIfSupported(bucket, energyUJ);
|
||||
setValueIfSupported(index, energyUJ);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,52 +166,90 @@ public class MeasuredEnergyStats {
|
||||
/**
|
||||
* Write to summary parcel.
|
||||
* Note: Measured subsystem availability may be different when the summary parcel is read.
|
||||
*
|
||||
* Corresponding read performed by {@link #readSummaryFromParcel(Parcel, boolean)}.
|
||||
*/
|
||||
private void writeSummaryToParcel(Parcel out, boolean skipZero) {
|
||||
final int sizePos = out.dataPosition();
|
||||
final int posOfNumWrittenEntries = out.dataPosition();
|
||||
out.writeInt(0);
|
||||
int size = 0;
|
||||
// Write only the supported buckets with non-zero energy.
|
||||
for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
|
||||
final long energy = mAccumulatedEnergiesMicroJoules[i];
|
||||
int numWrittenEntries = 0;
|
||||
// Write only the supported buckets (with non-zero energy, if applicable).
|
||||
for (int index = 0; index < mAccumulatedEnergiesMicroJoules.length; index++) {
|
||||
final long energy = mAccumulatedEnergiesMicroJoules[index];
|
||||
if (energy < 0) continue;
|
||||
if (energy == 0 && skipZero) continue;
|
||||
|
||||
out.writeInt(i);
|
||||
out.writeLong(mAccumulatedEnergiesMicroJoules[i]);
|
||||
size++;
|
||||
out.writeInt(index);
|
||||
out.writeLong(mAccumulatedEnergiesMicroJoules[index]);
|
||||
numWrittenEntries++;
|
||||
}
|
||||
final int currPos = out.dataPosition();
|
||||
out.setDataPosition(sizePos);
|
||||
out.writeInt(size);
|
||||
out.setDataPosition(posOfNumWrittenEntries);
|
||||
out.writeInt(numWrittenEntries);
|
||||
out.setDataPosition(currPos);
|
||||
}
|
||||
|
||||
/** Updates the given bucket with the given energy iff accumulate is true. */
|
||||
public void updateBucket(@EnergyBucket int bucket, long energyDeltaUJ, boolean accumulate) {
|
||||
/** Get number of possible buckets, including both standard and custom ones. */
|
||||
private int getNumberOfIndices() {
|
||||
return mAccumulatedEnergiesMicroJoules.length;
|
||||
}
|
||||
|
||||
// TODO: Get rid of the 'accumulate' boolean. It's always true.
|
||||
/** Updates the given standard energy bucket with the given energy if accumulate is true. */
|
||||
public void updateStandardBucket(@StandardEnergyBucket int bucket, long energyDeltaUJ,
|
||||
boolean accumulate) {
|
||||
checkValidStandardBucket(bucket);
|
||||
updateEntry(bucket, energyDeltaUJ, accumulate);
|
||||
}
|
||||
|
||||
/** Updates the given custom energy bucket with the given energy if accumulate is true. */
|
||||
public void updateCustomBucket(int customBucket, long energyDeltaUJ, boolean accumulate) {
|
||||
if (!isValidCustomBucket(customBucket)) {
|
||||
Slog.e(TAG, "Attempted to update invalid custom bucket " + customBucket);
|
||||
return;
|
||||
}
|
||||
final int index = customBucketToIndex(customBucket);
|
||||
updateEntry(index, energyDeltaUJ, accumulate);
|
||||
}
|
||||
|
||||
/** Updates the given index with the given energy if accumulate is true. */
|
||||
private void updateEntry(int index, long energyDeltaUJ, boolean accumulate) {
|
||||
if (accumulate) {
|
||||
if (mAccumulatedEnergiesMicroJoules[bucket] >= 0L) {
|
||||
mAccumulatedEnergiesMicroJoules[bucket] += energyDeltaUJ;
|
||||
if (mAccumulatedEnergiesMicroJoules[index] >= 0L) {
|
||||
mAccumulatedEnergiesMicroJoules[index] += energyDeltaUJ;
|
||||
} else {
|
||||
Slog.wtf(TAG, "Attempting to add " + energyDeltaUJ + " to unavailable bucket "
|
||||
+ ENERGY_BUCKET_NAMES[bucket] + " whose value was "
|
||||
+ mAccumulatedEnergiesMicroJoules[bucket]);
|
||||
+ getBucketName(index) + " whose value was "
|
||||
+ mAccumulatedEnergiesMicroJoules[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return accumulated energy (in microjoules) for the given energy bucket since last reset.
|
||||
* Returns {@link BatteryStats#ENERGY_DATA_UNAVAILABLE} if this energy data is unavailable.
|
||||
* Return accumulated energy (in microjoules) for a standard energy bucket since last reset.
|
||||
* Returns {@link android.os.BatteryStats#ENERGY_DATA_UNAVAILABLE} if this data is unavailable.
|
||||
* @throws IllegalArgumentException if no such {@link StandardEnergyBucket}.
|
||||
*/
|
||||
public long getAccumulatedBucketEnergy(@EnergyBucket int bucket) {
|
||||
public long getAccumulatedStandardBucketEnergy(@StandardEnergyBucket int bucket) {
|
||||
checkValidStandardBucket(bucket);
|
||||
return mAccumulatedEnergiesMicroJoules[bucket];
|
||||
}
|
||||
|
||||
/**
|
||||
* Map {@link MeasuredEnergySubsystem} and device state to a Display {@link EnergyBucket}.
|
||||
* Return accumulated energy (in microjoules) for the a custom energy bucket since last reset.
|
||||
* Returns {@link android.os.BatteryStats#ENERGY_DATA_UNAVAILABLE} if this data is unavailable.
|
||||
*/
|
||||
public static @EnergyBucket int getDisplayEnergyBucket(int screenState) {
|
||||
public long getAccumulatedCustomBucketEnergy(int customBucket) {
|
||||
if (!isValidCustomBucket(customBucket)) {
|
||||
return ENERGY_DATA_UNAVAILABLE;
|
||||
}
|
||||
return mAccumulatedEnergiesMicroJoules[customBucketToIndex(customBucket)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Map {@link MeasuredEnergySubsystem} and device state to Display {@link StandardEnergyBucket}.
|
||||
*/
|
||||
public static @StandardEnergyBucket int getDisplayEnergyBucket(int screenState) {
|
||||
if (Display.isOnState(screenState)) {
|
||||
return ENERGY_BUCKET_SCREEN_ON;
|
||||
}
|
||||
@@ -204,15 +262,20 @@ public class MeasuredEnergyStats {
|
||||
/**
|
||||
* Create a MeasuredEnergyStats object from a summary parcel.
|
||||
*
|
||||
* Corresponding write performed by
|
||||
* {@link #writeSummaryToParcel(MeasuredEnergyStats, Parcel, boolean)}.
|
||||
*
|
||||
* @return a new MeasuredEnergyStats object as described.
|
||||
* Returns null if the parcel indicates there is no data to populate.
|
||||
*/
|
||||
public static @Nullable MeasuredEnergyStats createAndReadSummaryFromParcel(Parcel in) {
|
||||
final int arraySize = in.readInt();
|
||||
// Check if any MeasuredEnergyStats exists on the parcel
|
||||
if (in.readInt() == 0) return null;
|
||||
if (arraySize == 0) return null;
|
||||
|
||||
final MeasuredEnergyStats stats =
|
||||
new MeasuredEnergyStats(new boolean[NUMBER_ENERGY_BUCKETS]);
|
||||
final int numCustomBuckets = arraySize - NUMBER_STANDARD_ENERGY_BUCKETS;
|
||||
final MeasuredEnergyStats stats = new MeasuredEnergyStats(
|
||||
new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], numCustomBuckets);
|
||||
stats.readSummaryFromParcel(in, true);
|
||||
return stats;
|
||||
}
|
||||
@@ -221,6 +284,12 @@ public class MeasuredEnergyStats {
|
||||
* Create a MeasuredEnergyStats using the template to determine which buckets are supported,
|
||||
* and populate this new object from the given parcel.
|
||||
*
|
||||
* The parcel must be consistent with the template in terms of the number of
|
||||
* possible (not necessarily supported) standard and custom buckets.
|
||||
*
|
||||
* Corresponding write performed by
|
||||
* {@link #writeSummaryToParcel(MeasuredEnergyStats, Parcel, boolean)}.
|
||||
*
|
||||
* @return a new MeasuredEnergyStats object as described.
|
||||
* Returns null if the stats contain no non-0 information (such as if template is null
|
||||
* or if the parcel indicates there is no data to populate).
|
||||
@@ -229,12 +298,22 @@ public class MeasuredEnergyStats {
|
||||
*/
|
||||
public static @Nullable MeasuredEnergyStats createAndReadSummaryFromParcel(Parcel in,
|
||||
@Nullable MeasuredEnergyStats template) {
|
||||
final int arraySize = in.readInt();
|
||||
// Check if any MeasuredEnergyStats exists on the parcel
|
||||
if (in.readInt() == 0) return null;
|
||||
if (arraySize == 0) return null;
|
||||
|
||||
if (template == null) {
|
||||
// Nothing supported now. Create placeholder object just to consume the parcel data.
|
||||
final MeasuredEnergyStats mes = new MeasuredEnergyStats();
|
||||
// Nothing supported anymore. Create placeholder object just to consume the parcel data.
|
||||
final MeasuredEnergyStats mes = new MeasuredEnergyStats(arraySize);
|
||||
mes.readSummaryFromParcel(in, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (arraySize != template.getNumberOfIndices()) {
|
||||
Slog.wtf(TAG, "Size of MeasuredEnergyStats parcel (" + arraySize
|
||||
+ ") does not match template (" + template.getNumberOfIndices() + ").");
|
||||
// Something is horribly wrong. Just consume the parcel and return null.
|
||||
final MeasuredEnergyStats mes = new MeasuredEnergyStats(arraySize);
|
||||
mes.readSummaryFromParcel(in, false);
|
||||
return null;
|
||||
}
|
||||
@@ -251,14 +330,17 @@ public class MeasuredEnergyStats {
|
||||
|
||||
/** Returns true iff any of the buckets are supported and non-zero. */
|
||||
private boolean containsInterestingData() {
|
||||
for (int bucket = 0; bucket < NUMBER_ENERGY_BUCKETS; bucket++) {
|
||||
if (mAccumulatedEnergiesMicroJoules[bucket] > 0) return true;
|
||||
for (int index = 0; index < mAccumulatedEnergiesMicroJoules.length; index++) {
|
||||
if (mAccumulatedEnergiesMicroJoules[index] > 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a MeasuredEnergyStats to a parcel. If the stats is null, just write a 0.
|
||||
*
|
||||
* Corresponding read performed by {@link #createAndReadSummaryFromParcel(Parcel)}
|
||||
* and {@link #createAndReadSummaryFromParcel(Parcel, MeasuredEnergyStats)}.
|
||||
*/
|
||||
public static void writeSummaryToParcel(@Nullable MeasuredEnergyStats stats,
|
||||
Parcel dest, boolean skipZero) {
|
||||
@@ -266,14 +348,15 @@ public class MeasuredEnergyStats {
|
||||
dest.writeInt(0);
|
||||
return;
|
||||
}
|
||||
dest.writeInt(1);
|
||||
dest.writeInt(stats.getNumberOfIndices());
|
||||
stats.writeSummaryToParcel(dest, skipZero);
|
||||
}
|
||||
|
||||
/** Reset accumulated energy. */
|
||||
private void reset() {
|
||||
for (int bucket = 0; bucket < NUMBER_ENERGY_BUCKETS; bucket++) {
|
||||
setValueIfSupported(bucket, 0L);
|
||||
final int numIndices = getNumberOfIndices();
|
||||
for (int index = 0; index < numIndices; index++) {
|
||||
setValueIfSupported(index, 0L);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,33 +365,93 @@ public class MeasuredEnergyStats {
|
||||
if (stats != null) stats.reset();
|
||||
}
|
||||
|
||||
/** If the bucket is AVAILABLE, overwrite its value; otherwise leave it as UNAVAILABLE. */
|
||||
private void setValueIfSupported(@EnergyBucket int bucket, long value) {
|
||||
if (mAccumulatedEnergiesMicroJoules[bucket] != ENERGY_DATA_UNAVAILABLE) {
|
||||
mAccumulatedEnergiesMicroJoules[bucket] = value;
|
||||
/** If the index is AVAILABLE, overwrite its value; otherwise leave it as UNAVAILABLE. */
|
||||
private void setValueIfSupported(int index, long value) {
|
||||
if (mAccumulatedEnergiesMicroJoules[index] != ENERGY_DATA_UNAVAILABLE) {
|
||||
mAccumulatedEnergiesMicroJoules[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if measuring the energy of the given bucket is supported by this device. */
|
||||
public boolean isEnergyBucketSupported(@EnergyBucket int bucket) {
|
||||
return mAccumulatedEnergiesMicroJoules[bucket] != ENERGY_DATA_UNAVAILABLE;
|
||||
/**
|
||||
* Check if measuring the energy of the given bucket is supported by this device.
|
||||
* @throws IllegalArgumentException if not a valid {@link StandardEnergyBucket}.
|
||||
*/
|
||||
public boolean isStandardBucketSupported(@StandardEnergyBucket int bucket) {
|
||||
checkValidStandardBucket(bucket);
|
||||
return isIndexSupported(bucket);
|
||||
}
|
||||
|
||||
private boolean isIndexSupported(int index) {
|
||||
return mAccumulatedEnergiesMicroJoules[index] != ENERGY_DATA_UNAVAILABLE;
|
||||
}
|
||||
|
||||
/** Check if the supported energy buckets are precisely those given. */
|
||||
public boolean isSupportEqualTo(
|
||||
@NonNull boolean[] queriedStandardBuckets, int numCustomBuckets) {
|
||||
|
||||
final int numBuckets = getNumberOfIndices();
|
||||
// TODO(b/178504428): Detect whether custom buckets have changed qualitatively, not just
|
||||
// quantitatively, and treat as mismatch if so.
|
||||
if (numBuckets != NUMBER_STANDARD_ENERGY_BUCKETS + numCustomBuckets) {
|
||||
return false;
|
||||
}
|
||||
for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_ENERGY_BUCKETS; stdBucket++) {
|
||||
if (isStandardBucketSupported(stdBucket) != queriedStandardBuckets[stdBucket]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Dump debug data. */
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.println("Accumulated energy since last reset (microjoules):");
|
||||
pw.print(" ");
|
||||
for (int bucket = 0; bucket < NUMBER_ENERGY_BUCKETS; bucket++) {
|
||||
pw.print(ENERGY_BUCKET_NAMES[bucket]);
|
||||
for (int index = 0; index < mAccumulatedEnergiesMicroJoules.length; index++) {
|
||||
pw.print(getBucketName(index));
|
||||
pw.print(" : ");
|
||||
pw.print(mAccumulatedEnergiesMicroJoules[bucket]);
|
||||
if (!isEnergyBucketSupported(bucket)) {
|
||||
pw.print(mAccumulatedEnergiesMicroJoules[index]);
|
||||
if (!isIndexSupported(index)) {
|
||||
pw.print(" (unsupported)");
|
||||
}
|
||||
if (bucket != NUMBER_ENERGY_BUCKETS - 1) {
|
||||
if (index != mAccumulatedEnergiesMicroJoules.length - 1) {
|
||||
pw.print(", ");
|
||||
}
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the index is a standard bucket, returns its name; otherwise returns its prefixed custom
|
||||
* bucket number.
|
||||
*/
|
||||
private static String getBucketName(int index) {
|
||||
if (isValidStandardBucket(index)) {
|
||||
return DebugUtils.valueToString(MeasuredEnergyStats.class, "ENERGY_BUCKET_", index);
|
||||
}
|
||||
return "CUSTOM_" + indexToCustomBucket(index);
|
||||
}
|
||||
|
||||
private static int customBucketToIndex(int customBucket) {
|
||||
return customBucket + NUMBER_STANDARD_ENERGY_BUCKETS;
|
||||
}
|
||||
|
||||
private static int indexToCustomBucket(int index) {
|
||||
return index - NUMBER_STANDARD_ENERGY_BUCKETS;
|
||||
}
|
||||
|
||||
private static void checkValidStandardBucket(@StandardEnergyBucket int bucket) {
|
||||
if (!isValidStandardBucket(bucket)) {
|
||||
throw new IllegalArgumentException("Illegal StandardEnergyBucket " + bucket);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValidStandardBucket(@StandardEnergyBucket int bucket) {
|
||||
return bucket >= 0 && bucket < NUMBER_STANDARD_ENERGY_BUCKETS;
|
||||
}
|
||||
|
||||
private boolean isValidCustomBucket(int customBucket) {
|
||||
return customBucket >= 0
|
||||
&& customBucketToIndex(customBucket) < mAccumulatedEnergiesMicroJoules.length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,9 +47,10 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
|
||||
|
||||
setExternalStatsSyncLocked(new DummyExternalStatsSync());
|
||||
|
||||
final boolean[] supportedBuckets = new boolean[MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS];
|
||||
Arrays.fill(supportedBuckets, true);
|
||||
mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedBuckets);
|
||||
final boolean[] supportedStandardBuckets
|
||||
= new boolean[MeasuredEnergyStats.NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
Arrays.fill(supportedStandardBuckets, true);
|
||||
mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedStandardBuckets, 2);
|
||||
|
||||
// A no-op handler.
|
||||
mHandler = new Handler(Looper.getMainLooper()) {
|
||||
|
||||
@@ -21,10 +21,11 @@ import static android.os.BatteryStats.ENERGY_DATA_UNAVAILABLE;
|
||||
import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE;
|
||||
import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON;
|
||||
import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_OTHER;
|
||||
import static com.android.internal.power.MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS;
|
||||
import static com.android.internal.power.MeasuredEnergyStats.NUMBER_STANDARD_ENERGY_BUCKETS;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.os.Parcel;
|
||||
@@ -47,60 +48,77 @@ public class MeasuredEnergyStatsTest {
|
||||
|
||||
@Test
|
||||
public void testConstruction() {
|
||||
final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int numCustomBuckets = 2;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
|
||||
final MeasuredEnergyStats stats = new MeasuredEnergyStats(supportedEnergyBuckets);
|
||||
final MeasuredEnergyStats stats
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
|
||||
for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
|
||||
if (supportedEnergyBuckets[i]) {
|
||||
assertTrue(stats.isEnergyBucketSupported(i));
|
||||
assertEquals(0L, stats.getAccumulatedBucketEnergy(i));
|
||||
for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
|
||||
if (supportedStandardBuckets[i]) {
|
||||
assertTrue(stats.isStandardBucketSupported(i));
|
||||
assertEquals(0L, stats.getAccumulatedStandardBucketEnergy(i));
|
||||
} else {
|
||||
assertFalse(stats.isEnergyBucketSupported(i));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE, stats.getAccumulatedBucketEnergy(i));
|
||||
assertFalse(stats.isStandardBucketSupported(i));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketEnergy(i));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < numCustomBuckets; i++) {
|
||||
assertEquals(0L, stats.getAccumulatedCustomBucketEnergy(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromTemplate() {
|
||||
final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int numCustomBuckets = 2;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
|
||||
final MeasuredEnergyStats stats = new MeasuredEnergyStats(supportedEnergyBuckets);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
final MeasuredEnergyStats stats
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
stats.updateCustomBucket(0, 50, true);
|
||||
stats.updateCustomBucket(1, 60, true);
|
||||
|
||||
final MeasuredEnergyStats newStats = MeasuredEnergyStats.createFromTemplate(stats);
|
||||
|
||||
for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
|
||||
if (supportedEnergyBuckets[i]) {
|
||||
assertTrue(newStats.isEnergyBucketSupported(i));
|
||||
assertEquals(0, newStats.getAccumulatedBucketEnergy(i));
|
||||
for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
|
||||
if (supportedStandardBuckets[i]) {
|
||||
assertTrue(newStats.isStandardBucketSupported(i));
|
||||
assertEquals(0L, newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
} else {
|
||||
assertFalse(newStats.isEnergyBucketSupported(i));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE, newStats.getAccumulatedBucketEnergy(i));
|
||||
assertFalse(newStats.isStandardBucketSupported(i));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE,
|
||||
newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < numCustomBuckets; i++) {
|
||||
assertEquals(0L, newStats.getAccumulatedCustomBucketEnergy(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadWriteParcel() {
|
||||
final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int numCustomBuckets = 2;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
|
||||
final MeasuredEnergyStats stats = new MeasuredEnergyStats(supportedEnergyBuckets);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
final MeasuredEnergyStats stats
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
stats.updateCustomBucket(0, 50, true);
|
||||
stats.updateCustomBucket(1, 60, true);
|
||||
|
||||
final Parcel parcel = Parcel.obtain();
|
||||
stats.writeToParcel(parcel);
|
||||
@@ -108,94 +126,127 @@ public class MeasuredEnergyStatsTest {
|
||||
parcel.setDataPosition(0);
|
||||
MeasuredEnergyStats newStats = new MeasuredEnergyStats(parcel);
|
||||
|
||||
for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
|
||||
assertEquals(stats.getAccumulatedBucketEnergy(i),
|
||||
newStats.getAccumulatedBucketEnergy(i));
|
||||
for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
|
||||
assertEquals(stats.getAccumulatedStandardBucketEnergy(i),
|
||||
newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
}
|
||||
for (int i = 0; i < numCustomBuckets; i++) {
|
||||
assertEquals(stats.getAccumulatedCustomBucketEnergy(i),
|
||||
newStats.getAccumulatedCustomBucketEnergy(i));
|
||||
}
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE,
|
||||
newStats.getAccumulatedCustomBucketEnergy(numCustomBuckets + 1));
|
||||
parcel.recycle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndReadSummaryFromParcel() {
|
||||
final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int numCustomBuckets = 2;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
|
||||
final MeasuredEnergyStats stats = new MeasuredEnergyStats(supportedEnergyBuckets);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
final MeasuredEnergyStats stats
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
stats.updateCustomBucket(0, 50, true);
|
||||
stats.updateCustomBucket(1, 60, true);
|
||||
|
||||
final Parcel parcel = Parcel.obtain();
|
||||
MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
|
||||
parcel.setDataPosition(0);
|
||||
MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel);
|
||||
|
||||
for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
|
||||
assertEquals(stats.isEnergyBucketSupported(i),
|
||||
newStats.isEnergyBucketSupported(i));
|
||||
assertEquals(stats.getAccumulatedBucketEnergy(i),
|
||||
newStats.getAccumulatedBucketEnergy(i));
|
||||
for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
|
||||
assertEquals(stats.isStandardBucketSupported(i),
|
||||
newStats.isStandardBucketSupported(i));
|
||||
assertEquals(stats.getAccumulatedStandardBucketEnergy(i),
|
||||
newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
}
|
||||
for (int i = 0; i < numCustomBuckets; i++) {
|
||||
assertEquals(stats.getAccumulatedCustomBucketEnergy(i),
|
||||
newStats.getAccumulatedCustomBucketEnergy(i));
|
||||
}
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE,
|
||||
newStats.getAccumulatedCustomBucketEnergy(numCustomBuckets + 1));
|
||||
parcel.recycle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndReadSummaryFromParcel_existingTemplate() {
|
||||
final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int numCustomBuckets = 2;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
|
||||
final MeasuredEnergyStats template = new MeasuredEnergyStats(supportedEnergyBuckets);
|
||||
template.updateBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
template.updateBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
template.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
final MeasuredEnergyStats template
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
template.updateCustomBucket(0, 50, true);
|
||||
|
||||
final MeasuredEnergyStats stats = MeasuredEnergyStats.createFromTemplate(template);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 200, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 7, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 63, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 7, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 63, true);
|
||||
stats.updateCustomBucket(0, 315, true);
|
||||
stats.updateCustomBucket(1, 316, true);
|
||||
|
||||
final Parcel parcel = Parcel.obtain();
|
||||
MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
|
||||
|
||||
final boolean[] newSupportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
|
||||
newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = true; // switched from false to true
|
||||
newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_OTHER] = false; // switched true to false
|
||||
final MeasuredEnergyStats newTemplate = new MeasuredEnergyStats(newSupportedEnergyBuckets);
|
||||
final boolean[] newsupportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
newsupportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
newsupportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = true; // switched false > true
|
||||
newsupportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = false; // switched true > false
|
||||
final MeasuredEnergyStats newTemplate
|
||||
= new MeasuredEnergyStats(newsupportedStandardBuckets, numCustomBuckets);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
final MeasuredEnergyStats newStats =
|
||||
MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel, newTemplate);
|
||||
|
||||
for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
|
||||
if (!newSupportedEnergyBuckets[i]) {
|
||||
assertFalse(newStats.isEnergyBucketSupported(i));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE, newStats.getAccumulatedBucketEnergy(i));
|
||||
} else if (!supportedEnergyBuckets[i]) {
|
||||
assertTrue(newStats.isEnergyBucketSupported(i));
|
||||
assertEquals(0L, newStats.getAccumulatedBucketEnergy(i));
|
||||
for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
|
||||
if (!newsupportedStandardBuckets[i]) {
|
||||
assertFalse(newStats.isStandardBucketSupported(i));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE,
|
||||
newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
} else if (!supportedStandardBuckets[i]) {
|
||||
assertTrue(newStats.isStandardBucketSupported(i));
|
||||
assertEquals(0L, newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
} else {
|
||||
assertTrue(newStats.isEnergyBucketSupported(i));
|
||||
assertEquals(stats.getAccumulatedBucketEnergy(i),
|
||||
newStats.getAccumulatedBucketEnergy(i));
|
||||
assertTrue(newStats.isStandardBucketSupported(i));
|
||||
assertEquals(stats.getAccumulatedStandardBucketEnergy(i),
|
||||
newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < numCustomBuckets; i++) {
|
||||
assertEquals(stats.getAccumulatedCustomBucketEnergy(i),
|
||||
newStats.getAccumulatedCustomBucketEnergy(i));
|
||||
}
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE,
|
||||
newStats.getAccumulatedCustomBucketEnergy(numCustomBuckets + 1));
|
||||
parcel.recycle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndReadSummaryFromParcel_skipZero() {
|
||||
final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
|
||||
Arrays.fill(supportedEnergyBuckets, true);
|
||||
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int numCustomBuckets = 2;
|
||||
Arrays.fill(supportedStandardBuckets, true);
|
||||
|
||||
final MeasuredEnergyStats stats = new MeasuredEnergyStats(supportedEnergyBuckets);
|
||||
// Accumulate energy in one bucket, the rest should be zero
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 200, true);
|
||||
final MeasuredEnergyStats stats
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
// Accumulate energy in one bucket and one custom bucket, the rest should be zero
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200, true);
|
||||
stats.updateCustomBucket(1, 60, true);
|
||||
|
||||
// Let's try parcelling with including zeros
|
||||
final Parcel includeZerosParcel = Parcel.obtain();
|
||||
MeasuredEnergyStats.writeSummaryToParcel(stats, includeZerosParcel, false);
|
||||
includeZerosParcel.setDataPosition(0);
|
||||
@@ -203,90 +254,180 @@ public class MeasuredEnergyStatsTest {
|
||||
MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(
|
||||
includeZerosParcel);
|
||||
|
||||
for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
|
||||
for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
|
||||
if (i == ENERGY_BUCKET_SCREEN_ON) {
|
||||
assertEquals(stats.isEnergyBucketSupported(i),
|
||||
newStats.isEnergyBucketSupported(i));
|
||||
assertEquals(stats.getAccumulatedBucketEnergy(i),
|
||||
newStats.getAccumulatedBucketEnergy(i));
|
||||
assertEquals(stats.isStandardBucketSupported(i),
|
||||
newStats.isStandardBucketSupported(i));
|
||||
assertEquals(stats.getAccumulatedStandardBucketEnergy(i),
|
||||
newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
} else {
|
||||
assertTrue(newStats.isEnergyBucketSupported(i));
|
||||
assertEquals(0L, newStats.getAccumulatedBucketEnergy(i));
|
||||
assertTrue(newStats.isStandardBucketSupported(i));
|
||||
assertEquals(0L, newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
}
|
||||
}
|
||||
assertEquals(0L, newStats.getAccumulatedCustomBucketEnergy(0));
|
||||
assertEquals(stats.getAccumulatedCustomBucketEnergy(1),
|
||||
newStats.getAccumulatedCustomBucketEnergy(1));
|
||||
includeZerosParcel.recycle();
|
||||
|
||||
// Now let's try parcelling with skipping zeros
|
||||
final Parcel skipZerosParcel = Parcel.obtain();
|
||||
MeasuredEnergyStats.writeSummaryToParcel(stats, skipZerosParcel, true);
|
||||
skipZerosParcel.setDataPosition(0);
|
||||
|
||||
newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(skipZerosParcel);
|
||||
|
||||
for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
|
||||
for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
|
||||
if (i == ENERGY_BUCKET_SCREEN_ON) {
|
||||
assertEquals(stats.isEnergyBucketSupported(i),
|
||||
newStats.isEnergyBucketSupported(i));
|
||||
assertEquals(stats.getAccumulatedBucketEnergy(i),
|
||||
newStats.getAccumulatedBucketEnergy(i));
|
||||
assertEquals(stats.isStandardBucketSupported(i),
|
||||
newStats.isStandardBucketSupported(i));
|
||||
assertEquals(stats.getAccumulatedStandardBucketEnergy(i),
|
||||
newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
} else {
|
||||
assertFalse(newStats.isEnergyBucketSupported(i));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE, newStats.getAccumulatedBucketEnergy(i));
|
||||
assertFalse(newStats.isStandardBucketSupported(i));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE,
|
||||
newStats.getAccumulatedStandardBucketEnergy(i));
|
||||
}
|
||||
}
|
||||
assertEquals(0L, newStats.getAccumulatedCustomBucketEnergy(0));
|
||||
assertEquals(stats.getAccumulatedCustomBucketEnergy(1),
|
||||
newStats.getAccumulatedCustomBucketEnergy(1));
|
||||
skipZerosParcel.recycle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndReadSummaryFromParcel_nullTemplate() {
|
||||
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int numCustomBuckets = 2;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
|
||||
final MeasuredEnergyStats stats
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
stats.updateCustomBucket(0, 50, true);
|
||||
stats.updateCustomBucket(1, 60, true);
|
||||
|
||||
final Parcel parcel = Parcel.obtain();
|
||||
MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
MeasuredEnergyStats newStats
|
||||
= MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel, null);
|
||||
assertNull(newStats);
|
||||
parcel.recycle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndReadSummaryFromParcel_boring() {
|
||||
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int numCustomBuckets = 2;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
|
||||
final MeasuredEnergyStats template
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
template.updateCustomBucket(0, 50, true);
|
||||
|
||||
final MeasuredEnergyStats stats = MeasuredEnergyStats.createFromTemplate(template);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 0L, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 7L, true);
|
||||
|
||||
final Parcel parcel = Parcel.obtain();
|
||||
MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
|
||||
|
||||
final boolean[] newSupportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
newSupportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
newSupportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = true; // switched false > true
|
||||
newSupportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = false; // switched true > false
|
||||
final MeasuredEnergyStats newTemplate
|
||||
= new MeasuredEnergyStats(newSupportedStandardBuckets, numCustomBuckets);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
final MeasuredEnergyStats newStats =
|
||||
MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel, newTemplate);
|
||||
// The only non-0 entry in stats is no longer supported, so now there's no interesting data.
|
||||
assertNull(newStats);
|
||||
assertEquals("Parcel was not properly consumed", 0, parcel.dataAvail());
|
||||
parcel.recycle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateBucket() {
|
||||
final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int numCustomBuckets = 2;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
|
||||
final MeasuredEnergyStats stats = new MeasuredEnergyStats(supportedEnergyBuckets);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_DOZE, 30, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
final MeasuredEnergyStats stats
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_DOZE, 30, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
|
||||
assertEquals(15, stats.getAccumulatedBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
|
||||
stats.updateCustomBucket(0, 50, true);
|
||||
stats.updateCustomBucket(1, 60, true);
|
||||
stats.updateCustomBucket(0, 3, true);
|
||||
|
||||
assertEquals(15, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE,
|
||||
stats.getAccumulatedBucketEnergy(ENERGY_BUCKET_SCREEN_DOZE));
|
||||
assertEquals(40, stats.getAccumulatedBucketEnergy(ENERGY_BUCKET_SCREEN_OTHER));
|
||||
stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_DOZE));
|
||||
assertEquals(40, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_OTHER));
|
||||
assertEquals(50 + 3, stats.getAccumulatedCustomBucketEnergy(0));
|
||||
assertEquals(60, stats.getAccumulatedCustomBucketEnergy(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReset() {
|
||||
final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int numCustomBuckets = 2;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
|
||||
supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true;
|
||||
|
||||
final MeasuredEnergyStats stats = new MeasuredEnergyStats(supportedEnergyBuckets);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
final MeasuredEnergyStats stats
|
||||
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
|
||||
stats.updateCustomBucket(0, 50, true);
|
||||
stats.updateCustomBucket(1, 60, true);
|
||||
|
||||
MeasuredEnergyStats.resetIfNotNull(stats);
|
||||
// All energy should be reset to 0
|
||||
for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
|
||||
if (supportedEnergyBuckets[i]) {
|
||||
assertTrue(stats.isEnergyBucketSupported(i));
|
||||
assertEquals(0, stats.getAccumulatedBucketEnergy(i));
|
||||
for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) {
|
||||
if (supportedStandardBuckets[i]) {
|
||||
assertTrue(stats.isStandardBucketSupported(i));
|
||||
assertEquals(0, stats.getAccumulatedStandardBucketEnergy(i));
|
||||
} else {
|
||||
assertFalse(stats.isEnergyBucketSupported(i));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE, stats.getAccumulatedBucketEnergy(i));
|
||||
assertFalse(stats.isStandardBucketSupported(i));
|
||||
assertEquals(ENERGY_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketEnergy(i));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < numCustomBuckets; i++) {
|
||||
assertEquals(0, stats.getAccumulatedCustomBucketEnergy(i));
|
||||
}
|
||||
|
||||
// Values should increase as usual.
|
||||
stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 70, true);
|
||||
assertEquals(70L, stats.getAccumulatedBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
|
||||
stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 70, true);
|
||||
assertEquals(70L, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
|
||||
|
||||
stats.updateCustomBucket(1, 12, true);
|
||||
assertEquals(12L, stats.getAccumulatedCustomBucketEnergy(1));
|
||||
}
|
||||
|
||||
/** Test that states are mapped to the expected energy buckets. Beware of mapping changes. */
|
||||
@Test
|
||||
public void testEnergyBucketMapping() {
|
||||
public void testStandardBucketMapping() {
|
||||
int exp;
|
||||
|
||||
exp = ENERGY_BUCKET_SCREEN_ON;
|
||||
|
||||
@@ -207,12 +207,13 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
|
||||
if (mPowerStatsInternal != null) {
|
||||
populateEnergyConsumerSubsystemMapsLocked();
|
||||
final MeasuredEnergyArray initialMeasuredEnergies = getEnergyConsumptionData();
|
||||
final boolean[] supportedBuckets = getSupportedEnergyBuckets(
|
||||
initialMeasuredEnergies);
|
||||
mMeasuredEnergySnapshot = initialMeasuredEnergies == null
|
||||
? null : new MeasuredEnergySnapshot(initialMeasuredEnergies);
|
||||
final boolean[] supportedStdBuckets
|
||||
= getSupportedEnergyBuckets(initialMeasuredEnergies);
|
||||
final int numCustomBuckets = 0; // TODO: Get this from initialMeasuredEnergies
|
||||
synchronized (mStats) {
|
||||
mStats.initMeasuredEnergyStatsLocked(supportedBuckets);
|
||||
mStats.initMeasuredEnergyStatsLocked(supportedStdBuckets, numCustomBuckets);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -740,15 +741,16 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
|
||||
|
||||
/**
|
||||
* Map the {@link MeasuredEnergyArray.MeasuredEnergySubsystem}s in the given energyArray to
|
||||
* their corresponding {@link MeasuredEnergyStats.EnergyBucket}s.
|
||||
* their corresponding {@link MeasuredEnergyStats.StandardEnergyBucket}s.
|
||||
* Does not include custom energy buckets (which are always, by definition, supported).
|
||||
*
|
||||
* @return array with true for index i if energy bucket i is supported.
|
||||
* @return array with true for index i if standard energy bucket i is supported.
|
||||
*/
|
||||
private static @Nullable boolean[] getSupportedEnergyBuckets(MeasuredEnergyArray energyArray) {
|
||||
if (energyArray == null) {
|
||||
return null;
|
||||
}
|
||||
final boolean[] buckets = new boolean[MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS];
|
||||
final boolean[] buckets = new boolean[MeasuredEnergyStats.NUMBER_STANDARD_ENERGY_BUCKETS];
|
||||
final int size = energyArray.size();
|
||||
for (int energyIdx = 0; energyIdx < size; energyIdx++) {
|
||||
switch (energyArray.getSubsystem(energyIdx)) {
|
||||
|
||||
Reference in New Issue
Block a user