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:
Dmitri Plotnikov
2021-06-02 19:45:37 -07:00
parent f7e7d084ee
commit c24fb81627
5 changed files with 171 additions and 2 deletions

View File

@@ -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.

View File

@@ -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.

View File

@@ -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();

View File

@@ -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;
}
}
}

View File

@@ -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();