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
|
||||
private final int[] mUserIds;
|
||||
private final long mMaxStatsAgeMs;
|
||||
private long mFromTimestamp;
|
||||
private long mToTimestamp;
|
||||
|
||||
private BatteryUsageStatsQuery(@NonNull Builder builder) {
|
||||
mFlags = builder.mFlags;
|
||||
mUserIds = builder.mUserIds != null ? builder.mUserIds.toArray()
|
||||
: new int[]{UserHandle.USER_ALL};
|
||||
mMaxStatsAgeMs = builder.mMaxStatsAgeMs;
|
||||
mFromTimestamp = builder.mFromTimestamp;
|
||||
mToTimestamp = builder.mToTimestamp;
|
||||
}
|
||||
|
||||
@BatteryUsageStatsFlags
|
||||
@@ -112,11 +116,30 @@ public final class BatteryUsageStatsQuery implements Parcelable {
|
||||
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) {
|
||||
mFlags = in.readInt();
|
||||
mUserIds = new int[in.readInt()];
|
||||
in.readIntArray(mUserIds);
|
||||
mMaxStatsAgeMs = in.readLong();
|
||||
mFromTimestamp = in.readLong();
|
||||
mToTimestamp = in.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,6 +148,8 @@ public final class BatteryUsageStatsQuery implements Parcelable {
|
||||
dest.writeInt(mUserIds.length);
|
||||
dest.writeIntArray(mUserIds);
|
||||
dest.writeLong(mMaxStatsAgeMs);
|
||||
dest.writeLong(mFromTimestamp);
|
||||
dest.writeLong(mToTimestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,6 +178,8 @@ public final class BatteryUsageStatsQuery implements Parcelable {
|
||||
private int mFlags;
|
||||
private IntArray mUserIds;
|
||||
private long mMaxStatsAgeMs = DEFAULT_MAX_STATS_AGE_MS;
|
||||
private long mFromTimestamp;
|
||||
private long mToTimestamp;
|
||||
|
||||
/**
|
||||
* Builds a read-only BatteryUsageStatsQuery object.
|
||||
@@ -203,6 +230,17 @@ public final class BatteryUsageStatsQuery implements Parcelable {
|
||||
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
|
||||
* 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,
|
||||
* keeping a separate account of threads receiving incoming binder calls.
|
||||
|
||||
@@ -38,14 +38,24 @@ import java.util.Map;
|
||||
public class BatteryUsageStatsProvider {
|
||||
private final Context mContext;
|
||||
private final BatteryStats mStats;
|
||||
private final BatteryUsageStatsStore mBatteryUsageStatsStore;
|
||||
private final PowerProfile mPowerProfile;
|
||||
private final Object mLock = new Object();
|
||||
private List<PowerCalculator> mPowerCalculators;
|
||||
|
||||
public BatteryUsageStatsProvider(Context context, BatteryStats stats) {
|
||||
this(context, stats, null);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public BatteryUsageStatsProvider(Context context, BatteryStats stats,
|
||||
BatteryUsageStatsStore batteryUsageStatsStore) {
|
||||
mContext = context;
|
||||
mStats = stats;
|
||||
mPowerProfile = new PowerProfile(mContext);
|
||||
mBatteryUsageStatsStore = batteryUsageStatsStore;
|
||||
mPowerProfile = stats instanceof BatteryStatsImpl
|
||||
? ((BatteryStatsImpl) stats).getPowerProfile()
|
||||
: new PowerProfile(context);
|
||||
}
|
||||
|
||||
private List<PowerCalculator> getPowerCalculators() {
|
||||
@@ -126,6 +136,15 @@ public class BatteryUsageStatsProvider {
|
||||
|
||||
private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query,
|
||||
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 uptimeUs = uptimeMillis() * 1000;
|
||||
|
||||
@@ -209,6 +228,25 @@ public class BatteryUsageStatsProvider {
|
||||
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() {
|
||||
if (mStats instanceof BatteryStatsImpl) {
|
||||
return ((BatteryStatsImpl) mStats).mClocks.elapsedRealtime();
|
||||
|
||||
@@ -20,10 +20,14 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.BatteryConsumer;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.BatteryUsageStats;
|
||||
import android.os.BatteryUsageStatsQuery;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Parcel;
|
||||
import android.os.Process;
|
||||
import android.os.UidBatteryConsumer;
|
||||
@@ -36,6 +40,7 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@@ -45,7 +50,8 @@ public class BatteryUsageStatsProviderTest {
|
||||
private static final long MINUTE_IN_MS = 60 * 1000;
|
||||
|
||||
@Rule
|
||||
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(12345);
|
||||
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(12345)
|
||||
.setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0);
|
||||
|
||||
@Test
|
||||
public void test_getBatteryUsageStats() {
|
||||
@@ -187,4 +193,84 @@ public class BatteryUsageStatsProviderTest {
|
||||
mStatsRule.setTime(11500, 0);
|
||||
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 org.mockito.Mockito.mock;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.BatteryUsageStats;
|
||||
@@ -56,6 +58,7 @@ public class BatteryUsageStatsStoreTest {
|
||||
mMockClocks.currentTime = 123;
|
||||
mBatteryStats = new MockBatteryStatsImpl(mMockClocks);
|
||||
mBatteryStats.setNoAutoReset(true);
|
||||
mBatteryStats.setPowerProfile(mock(PowerProfile.class));
|
||||
|
||||
Context context = InstrumentationRegistry.getContext();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user