Add BatteryUsageStatsQuery parameters: time range
Bug: 187223764
Test: atest FrameworksCoreTests:BatteryUsageStatsProviderTest
Change-Id: If370360695a3f0327f07457abac1fd02164864e1
Merged-In: If370360695a3f0327f07457abac1fd02164864e1
(cherry picked from commit 6ea400b27c)
This commit is contained in:
@@ -72,12 +72,16 @@ public final class BatteryUsageStatsQuery implements Parcelable {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final int[] mUserIds;
|
private final int[] mUserIds;
|
||||||
private final long mMaxStatsAgeMs;
|
private final long mMaxStatsAgeMs;
|
||||||
|
private long mFromTimestamp;
|
||||||
|
private long mToTimestamp;
|
||||||
|
|
||||||
private BatteryUsageStatsQuery(@NonNull Builder builder) {
|
private BatteryUsageStatsQuery(@NonNull Builder builder) {
|
||||||
mFlags = builder.mFlags;
|
mFlags = builder.mFlags;
|
||||||
mUserIds = builder.mUserIds != null ? builder.mUserIds.toArray()
|
mUserIds = builder.mUserIds != null ? builder.mUserIds.toArray()
|
||||||
: new int[]{UserHandle.USER_ALL};
|
: new int[]{UserHandle.USER_ALL};
|
||||||
mMaxStatsAgeMs = builder.mMaxStatsAgeMs;
|
mMaxStatsAgeMs = builder.mMaxStatsAgeMs;
|
||||||
|
mFromTimestamp = builder.mFromTimestamp;
|
||||||
|
mToTimestamp = builder.mToTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@BatteryUsageStatsFlags
|
@BatteryUsageStatsFlags
|
||||||
@@ -112,11 +116,30 @@ public final class BatteryUsageStatsQuery implements Parcelable {
|
|||||||
return mMaxStatsAgeMs;
|
return mMaxStatsAgeMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the exclusive lower bound of the stored snapshot timestamps that should be included
|
||||||
|
* in the aggregation. Ignored if {@link #getToTimestamp()} is zero.
|
||||||
|
*/
|
||||||
|
public long getFromTimestamp() {
|
||||||
|
return mFromTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the inclusive upper bound of the stored snapshot timestamps that should
|
||||||
|
* be included in the aggregation. The default is to include only the current stats
|
||||||
|
* accumulated since the latest battery reset.
|
||||||
|
*/
|
||||||
|
public long getToTimestamp() {
|
||||||
|
return mToTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
private BatteryUsageStatsQuery(Parcel in) {
|
private BatteryUsageStatsQuery(Parcel in) {
|
||||||
mFlags = in.readInt();
|
mFlags = in.readInt();
|
||||||
mUserIds = new int[in.readInt()];
|
mUserIds = new int[in.readInt()];
|
||||||
in.readIntArray(mUserIds);
|
in.readIntArray(mUserIds);
|
||||||
mMaxStatsAgeMs = in.readLong();
|
mMaxStatsAgeMs = in.readLong();
|
||||||
|
mFromTimestamp = in.readLong();
|
||||||
|
mToTimestamp = in.readLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,6 +148,8 @@ public final class BatteryUsageStatsQuery implements Parcelable {
|
|||||||
dest.writeInt(mUserIds.length);
|
dest.writeInt(mUserIds.length);
|
||||||
dest.writeIntArray(mUserIds);
|
dest.writeIntArray(mUserIds);
|
||||||
dest.writeLong(mMaxStatsAgeMs);
|
dest.writeLong(mMaxStatsAgeMs);
|
||||||
|
dest.writeLong(mFromTimestamp);
|
||||||
|
dest.writeLong(mToTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -153,6 +178,8 @@ public final class BatteryUsageStatsQuery implements Parcelable {
|
|||||||
private int mFlags;
|
private int mFlags;
|
||||||
private IntArray mUserIds;
|
private IntArray mUserIds;
|
||||||
private long mMaxStatsAgeMs = DEFAULT_MAX_STATS_AGE_MS;
|
private long mMaxStatsAgeMs = DEFAULT_MAX_STATS_AGE_MS;
|
||||||
|
private long mFromTimestamp;
|
||||||
|
private long mToTimestamp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a read-only BatteryUsageStatsQuery object.
|
* Builds a read-only BatteryUsageStatsQuery object.
|
||||||
@@ -203,6 +230,17 @@ public final class BatteryUsageStatsQuery implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests to aggregate stored snapshots between the two supplied timestamps
|
||||||
|
* @param fromTimestamp Exclusive starting timestamp, as per System.currentTimeMillis()
|
||||||
|
* @param toTimestamp Inclusive ending timestamp, as per System.currentTimeMillis()
|
||||||
|
*/
|
||||||
|
public Builder aggregateSnapshots(long fromTimestamp, long toTimestamp) {
|
||||||
|
mFromTimestamp = fromTimestamp;
|
||||||
|
mToTimestamp = toTimestamp;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the client's tolerance for stale battery stats. The data may be up to
|
* Set the client's tolerance for stale battery stats. The data may be up to
|
||||||
* this many milliseconds out-of-date.
|
* this many milliseconds out-of-date.
|
||||||
|
|||||||
@@ -10749,6 +10749,10 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PowerProfile getPowerProfile() {
|
||||||
|
return mPowerProfile;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts tracking CPU time-in-state for threads of the system server process,
|
* Starts tracking CPU time-in-state for threads of the system server process,
|
||||||
* keeping a separate account of threads receiving incoming binder calls.
|
* keeping a separate account of threads receiving incoming binder calls.
|
||||||
|
|||||||
@@ -38,14 +38,24 @@ import java.util.Map;
|
|||||||
public class BatteryUsageStatsProvider {
|
public class BatteryUsageStatsProvider {
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final BatteryStats mStats;
|
private final BatteryStats mStats;
|
||||||
|
private final BatteryUsageStatsStore mBatteryUsageStatsStore;
|
||||||
private final PowerProfile mPowerProfile;
|
private final PowerProfile mPowerProfile;
|
||||||
private final Object mLock = new Object();
|
private final Object mLock = new Object();
|
||||||
private List<PowerCalculator> mPowerCalculators;
|
private List<PowerCalculator> mPowerCalculators;
|
||||||
|
|
||||||
public BatteryUsageStatsProvider(Context context, BatteryStats stats) {
|
public BatteryUsageStatsProvider(Context context, BatteryStats stats) {
|
||||||
|
this(context, stats, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public BatteryUsageStatsProvider(Context context, BatteryStats stats,
|
||||||
|
BatteryUsageStatsStore batteryUsageStatsStore) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mStats = stats;
|
mStats = stats;
|
||||||
mPowerProfile = new PowerProfile(mContext);
|
mBatteryUsageStatsStore = batteryUsageStatsStore;
|
||||||
|
mPowerProfile = stats instanceof BatteryStatsImpl
|
||||||
|
? ((BatteryStatsImpl) stats).getPowerProfile()
|
||||||
|
: new PowerProfile(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PowerCalculator> getPowerCalculators() {
|
private List<PowerCalculator> getPowerCalculators() {
|
||||||
@@ -126,6 +136,15 @@ public class BatteryUsageStatsProvider {
|
|||||||
|
|
||||||
private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query,
|
private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query,
|
||||||
long currentTimeMs) {
|
long currentTimeMs) {
|
||||||
|
if (query.getToTimestamp() == 0) {
|
||||||
|
return getCurrentBatteryUsageStats(query, currentTimeMs);
|
||||||
|
} else {
|
||||||
|
return getAggregatedBatteryUsageStats(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BatteryUsageStats getCurrentBatteryUsageStats(BatteryUsageStatsQuery query,
|
||||||
|
long currentTimeMs) {
|
||||||
final long realtimeUs = elapsedRealtime() * 1000;
|
final long realtimeUs = elapsedRealtime() * 1000;
|
||||||
final long uptimeUs = uptimeMillis() * 1000;
|
final long uptimeUs = uptimeMillis() * 1000;
|
||||||
|
|
||||||
@@ -209,6 +228,25 @@ public class BatteryUsageStatsProvider {
|
|||||||
BatteryStats.STATS_SINCE_CHARGED) / 1000;
|
BatteryStats.STATS_SINCE_CHARGED) / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BatteryUsageStats getAggregatedBatteryUsageStats(BatteryUsageStatsQuery query) {
|
||||||
|
final boolean includePowerModels = (query.getFlags()
|
||||||
|
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
|
||||||
|
|
||||||
|
final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
|
||||||
|
mStats.getCustomEnergyConsumerNames(), includePowerModels);
|
||||||
|
final long[] timestamps = mBatteryUsageStatsStore.listBatteryUsageStatsTimestamps();
|
||||||
|
for (long timestamp : timestamps) {
|
||||||
|
if (timestamp > query.getFromTimestamp() && timestamp <= query.getToTimestamp()) {
|
||||||
|
final BatteryUsageStats snapshot =
|
||||||
|
mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp);
|
||||||
|
if (snapshot != null) {
|
||||||
|
builder.add(snapshot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
private long elapsedRealtime() {
|
private long elapsedRealtime() {
|
||||||
if (mStats instanceof BatteryStatsImpl) {
|
if (mStats instanceof BatteryStatsImpl) {
|
||||||
return ((BatteryStatsImpl) mStats).mClocks.elapsedRealtime();
|
return ((BatteryStatsImpl) mStats).mClocks.elapsedRealtime();
|
||||||
|
|||||||
@@ -20,10 +20,14 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.BatteryConsumer;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.BatteryStats;
|
import android.os.BatteryStats;
|
||||||
import android.os.BatteryUsageStats;
|
import android.os.BatteryUsageStats;
|
||||||
import android.os.BatteryUsageStatsQuery;
|
import android.os.BatteryUsageStatsQuery;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.UidBatteryConsumer;
|
import android.os.UidBatteryConsumer;
|
||||||
@@ -36,6 +40,7 @@ import org.junit.Rule;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@@ -45,7 +50,8 @@ public class BatteryUsageStatsProviderTest {
|
|||||||
private static final long MINUTE_IN_MS = 60 * 1000;
|
private static final long MINUTE_IN_MS = 60 * 1000;
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(12345);
|
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(12345)
|
||||||
|
.setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_getBatteryUsageStats() {
|
public void test_getBatteryUsageStats() {
|
||||||
@@ -187,4 +193,84 @@ public class BatteryUsageStatsProviderTest {
|
|||||||
mStatsRule.setTime(11500, 0);
|
mStatsRule.setTime(11500, 0);
|
||||||
assertThat(provider.shouldUpdateStats(queries, 10000)).isTrue();
|
assertThat(provider.shouldUpdateStats(queries, 10000)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAggregateBatteryStats() {
|
||||||
|
Context context = InstrumentationRegistry.getContext();
|
||||||
|
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
|
||||||
|
mStatsRule.setCurrentTime(5 * MINUTE_IN_MS);
|
||||||
|
batteryStats.resetAllStatsCmdLocked();
|
||||||
|
|
||||||
|
BatteryUsageStatsStore batteryUsageStatsStore = new BatteryUsageStatsStore(context,
|
||||||
|
batteryStats, new File(context.getCacheDir(), "BatteryUsageStatsProviderTest"),
|
||||||
|
new TestHandler(), Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context,
|
||||||
|
batteryStats, batteryUsageStatsStore);
|
||||||
|
|
||||||
|
batteryStats.noteFlashlightOnLocked(APP_UID,
|
||||||
|
10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
|
||||||
|
batteryStats.noteFlashlightOffLocked(APP_UID,
|
||||||
|
20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
|
||||||
|
mStatsRule.setCurrentTime(25 * MINUTE_IN_MS);
|
||||||
|
batteryStats.resetAllStatsCmdLocked();
|
||||||
|
|
||||||
|
batteryStats.noteFlashlightOnLocked(APP_UID,
|
||||||
|
30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
|
||||||
|
batteryStats.noteFlashlightOffLocked(APP_UID,
|
||||||
|
50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS);
|
||||||
|
mStatsRule.setCurrentTime(55 * MINUTE_IN_MS);
|
||||||
|
batteryStats.resetAllStatsCmdLocked();
|
||||||
|
|
||||||
|
// This section should be ignored because the timestamp is out or range
|
||||||
|
batteryStats.noteFlashlightOnLocked(APP_UID,
|
||||||
|
60 * MINUTE_IN_MS, 60 * MINUTE_IN_MS);
|
||||||
|
batteryStats.noteFlashlightOffLocked(APP_UID,
|
||||||
|
70 * MINUTE_IN_MS, 70 * MINUTE_IN_MS);
|
||||||
|
mStatsRule.setCurrentTime(75 * MINUTE_IN_MS);
|
||||||
|
batteryStats.resetAllStatsCmdLocked();
|
||||||
|
|
||||||
|
// This section should be ignored because it represents the current stats session
|
||||||
|
batteryStats.noteFlashlightOnLocked(APP_UID,
|
||||||
|
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
|
||||||
|
batteryStats.noteFlashlightOffLocked(APP_UID,
|
||||||
|
90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS);
|
||||||
|
mStatsRule.setCurrentTime(95 * MINUTE_IN_MS);
|
||||||
|
|
||||||
|
// Include the first and the second snapshot, but not the third or current
|
||||||
|
BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder()
|
||||||
|
.aggregateSnapshots(20 * MINUTE_IN_MS, 60 * MINUTE_IN_MS)
|
||||||
|
.build();
|
||||||
|
final BatteryUsageStats stats = provider.getBatteryUsageStats(query);
|
||||||
|
|
||||||
|
assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS);
|
||||||
|
assertThat(stats.getStatsEndTimestamp()).isEqualTo(55 * MINUTE_IN_MS);
|
||||||
|
assertThat(stats.getAggregateBatteryConsumer(
|
||||||
|
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
|
||||||
|
.getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
|
||||||
|
.isWithin(0.0001)
|
||||||
|
.of(180.0); // 360 mA * 0.5 hours
|
||||||
|
assertThat(stats.getAggregateBatteryConsumer(
|
||||||
|
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
|
||||||
|
.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
|
||||||
|
.isEqualTo((10 + 20) * MINUTE_IN_MS);
|
||||||
|
final UidBatteryConsumer uidBatteryConsumer = stats.getUidBatteryConsumers().stream()
|
||||||
|
.filter(uid -> uid.getUid() == APP_UID).findFirst().get();
|
||||||
|
assertThat(uidBatteryConsumer
|
||||||
|
.getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
|
||||||
|
.isWithin(0.1)
|
||||||
|
.of(180.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TestHandler extends Handler {
|
||||||
|
TestHandler() {
|
||||||
|
super(Looper.getMainLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
|
||||||
|
msg.getCallback().run();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package com.android.internal.os;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.BatteryUsageStats;
|
import android.os.BatteryUsageStats;
|
||||||
@@ -56,6 +58,7 @@ public class BatteryUsageStatsStoreTest {
|
|||||||
mMockClocks.currentTime = 123;
|
mMockClocks.currentTime = 123;
|
||||||
mBatteryStats = new MockBatteryStatsImpl(mMockClocks);
|
mBatteryStats = new MockBatteryStatsImpl(mMockClocks);
|
||||||
mBatteryStats.setNoAutoReset(true);
|
mBatteryStats.setNoAutoReset(true);
|
||||||
|
mBatteryStats.setPowerProfile(mock(PowerProfile.class));
|
||||||
|
|
||||||
Context context = InstrumentationRegistry.getContext();
|
Context context = InstrumentationRegistry.getContext();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user