Add battery history to BatteryStatsUsage

Bug: 173745486
Test: atest FrameworksCoreTests:com.android.internal.os.BatteryUsageStatsProviderTest
Change-Id: Icfd9e49b68f1be99312c88ac889b06aa669367ef
This commit is contained in:
Dmitri Plotnikov
2021-02-24 13:51:31 -08:00
parent cda90b4cf5
commit 20720fa188
5 changed files with 184 additions and 4 deletions

View File

@@ -20,6 +20,9 @@ import android.annotation.NonNull;
import android.util.Range;
import android.util.SparseArray;
import com.android.internal.os.BatteryStatsHistory;
import com.android.internal.os.BatteryStatsHistoryIterator;
import java.util.ArrayList;
import java.util.List;
@@ -37,12 +40,16 @@ public final class BatteryUsageStats implements Parcelable {
private final ArrayList<UidBatteryConsumer> mUidBatteryConsumers;
private final ArrayList<SystemBatteryConsumer> mSystemBatteryConsumers;
private final ArrayList<UserBatteryConsumer> mUserBatteryConsumers;
private final Parcel mHistoryBuffer;
private final List<BatteryStats.HistoryTag> mHistoryTagPool;
private BatteryUsageStats(@NonNull Builder builder) {
mStatsStartRealtimeMs = builder.mStatsStartRealtimeMs;
mDischargePercentage = builder.mDischargePercentage;
mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah;
mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
mHistoryBuffer = builder.mHistoryBuffer;
mHistoryTagPool = builder.mHistoryTagPool;
double totalPower = 0;
@@ -125,6 +132,19 @@ public final class BatteryUsageStats implements Parcelable {
return mUserBatteryConsumers;
}
/**
* Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s.
*/
@NonNull
public BatteryStatsHistoryIterator iterateBatteryStatsHistory() {
if (mHistoryBuffer == null) {
throw new IllegalStateException(
"Battery history was not requested in the BatteryUsageStatsQuery");
}
return new BatteryStatsHistoryIterator(new BatteryStatsHistory(mHistoryBuffer),
mHistoryTagPool);
}
@Override
public int describeContents() {
return 0;
@@ -142,6 +162,29 @@ public final class BatteryUsageStats implements Parcelable {
source.readParcelableList(mSystemBatteryConsumers, getClass().getClassLoader());
mUserBatteryConsumers = new ArrayList<>();
source.readParcelableList(mUserBatteryConsumers, getClass().getClassLoader());
if (source.readBoolean()) {
mHistoryBuffer = Parcel.obtain();
mHistoryBuffer.setDataSize(0);
mHistoryBuffer.setDataPosition(0);
int historyBufferSize = source.readInt();
int curPos = source.dataPosition();
mHistoryBuffer.appendFrom(source, curPos, historyBufferSize);
source.setDataPosition(curPos + historyBufferSize);
int historyTagCount = source.readInt();
mHistoryTagPool = new ArrayList<>(historyTagCount);
for (int i = 0; i < historyTagCount; i++) {
BatteryStats.HistoryTag tag = new BatteryStats.HistoryTag();
tag.string = source.readString();
tag.uid = source.readInt();
tag.poolIdx = source.readInt();
mHistoryTagPool.add(tag);
}
} else {
mHistoryBuffer = null;
mHistoryTagPool = null;
}
}
@Override
@@ -154,6 +197,23 @@ public final class BatteryUsageStats implements Parcelable {
dest.writeParcelableList(mUidBatteryConsumers, flags);
dest.writeParcelableList(mSystemBatteryConsumers, flags);
dest.writeParcelableList(mUserBatteryConsumers, flags);
if (mHistoryBuffer != null) {
dest.writeBoolean(true);
final int historyBufferSize = mHistoryBuffer.dataSize();
dest.writeInt(historyBufferSize);
dest.appendFrom(mHistoryBuffer, 0, historyBufferSize);
dest.writeInt(mHistoryTagPool.size());
for (int i = mHistoryTagPool.size() - 1; i >= 0; i--) {
final BatteryStats.HistoryTag tag = mHistoryTagPool.get(i);
dest.writeString(tag.string);
dest.writeInt(tag.uid);
dest.writeInt(tag.poolIdx);
}
} else {
dest.writeBoolean(false);
}
}
@NonNull
@@ -183,6 +243,8 @@ public final class BatteryUsageStats implements Parcelable {
new SparseArray<>();
private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =
new SparseArray<>();
private Parcel mHistoryBuffer;
private List<BatteryStats.HistoryTag> mHistoryTagPool;
public Builder(int customPowerComponentCount, int customTimeComponentCount) {
mCustomPowerComponentCount = customPowerComponentCount;
@@ -226,6 +288,17 @@ public final class BatteryUsageStats implements Parcelable {
return this;
}
/**
* Sets the parceled recent history.
*/
@NonNull
public Builder setBatteryHistory(Parcel historyBuffer,
List<BatteryStats.HistoryTag> historyTagPool) {
mHistoryBuffer = historyBuffer;
mHistoryTagPool = historyTagPool;
return this;
}
/**
* Creates or returns a exiting UidBatteryConsumer, which represents battery attribution
* data for an individual UID.

View File

@@ -40,6 +40,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
*/
@IntDef(flag = true, prefix = { "FLAG_BATTERY_USAGE_STATS_" }, value = {
FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL,
FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface BatteryUsageStatsFlags {}
@@ -53,6 +54,12 @@ public final class BatteryUsageStatsQuery implements Parcelable {
*/
public static final int FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL = 1;
/**
* Indicates that battery history should be included in the BatteryUsageStats.
* @hide
*/
public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY = 2;
private final int mFlags;
@NonNull
private final int[] mUserIds;
@@ -146,10 +153,10 @@ public final class BatteryUsageStatsQuery implements Parcelable {
}
/**
* Sets flags to modify the behavior of {@link BatteryStatsManager#getBatteryUsageStats}.
* Requests that battery history be included in the BatteryUsageStats.
*/
public Builder setFlags(@BatteryUsageStatsFlags int flags) {
mFlags = flags;
public Builder includeBatteryHistory() {
mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY;
return this;
}

View File

@@ -36,7 +36,7 @@ public class BatteryStatsHistoryIterator {
private final String[] mReadHistoryStrings;
private final int[] mReadHistoryUids;
BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history,
public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history,
@NonNull List<BatteryStats.HistoryTag> historyTagPool) {
mBatteryStatsHistory = history;

View File

@@ -30,6 +30,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Uses accumulated battery stats data and PowerCalculators to produce power
@@ -152,6 +153,20 @@ public class BatteryUsageStatsProvider {
query);
}
if ((query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) {
ArrayList<BatteryStats.HistoryTag> tags = new ArrayList<>(
mStats.mHistoryTagPool.size());
for (Map.Entry<BatteryStats.HistoryTag, Integer> entry :
mStats.mHistoryTagPool.entrySet()) {
final BatteryStats.HistoryTag tag = entry.getKey();
tag.poolIdx = entry.getValue();
tags.add(tag);
}
batteryUsageStatsBuilder.setBatteryHistory(mStats.mHistoryBuffer, tags);
}
return batteryUsageStatsBuilder.build();
}

View File

@@ -20,8 +20,11 @@ import static com.google.common.truth.Truth.assertThat;
import android.app.ActivityManager;
import android.content.Context;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Parcel;
import android.os.Process;
import android.os.UidBatteryConsumer;
@@ -73,4 +76,86 @@ public class BatteryUsageStatsProviderTest {
assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
.isEqualTo(10 * MINUTE_IN_MS);
}
@Test
public void testWriteAndReadHistory() {
MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
batteryStats.setRecordAllHistoryLocked(true);
batteryStats.forceRecordAllHistory();
batteryStats.setNoAutoReset(true);
batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
/* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
1_000_000, 1_000_000);
batteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000);
batteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000);
Context context = InstrumentationRegistry.getContext();
BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, batteryStats);
final BatteryUsageStats batteryUsageStats =
provider.getBatteryUsageStats(
new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build());
Parcel in = Parcel.obtain();
batteryUsageStats.writeToParcel(in, 0);
final byte[] bytes = in.marshall();
Parcel out = Parcel.obtain();
out.unmarshall(bytes, 0, bytes.length);
out.setDataPosition(0);
BatteryUsageStats unparceled = BatteryUsageStats.CREATOR.createFromParcel(out);
final BatteryStatsHistoryIterator iterator =
unparceled.iterateBatteryStatsHistory();
BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
assertThat(iterator.next(item)).isTrue();
assertHistoryItem(item,
BatteryStats.HistoryItem.CMD_RESET, BatteryStats.HistoryItem.EVENT_NONE,
null, 0, 3_600_000, 90, 1_000_000);
assertThat(iterator.next(item)).isTrue();
assertHistoryItem(item,
BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
null, 0, 3_600_000, 90, 1_000_000);
assertThat(iterator.next(item)).isTrue();
assertHistoryItem(item,
BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
null, 0, 3_600_000, 90, 2_000_000);
assertThat(iterator.next(item)).isTrue();
assertHistoryItem(item,
BatteryStats.HistoryItem.CMD_UPDATE,
BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START,
"foo", APP_UID, 3_600_000, 90, 3_000_000);
assertThat(iterator.next(item)).isTrue();
assertHistoryItem(item,
BatteryStats.HistoryItem.CMD_UPDATE,
BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH,
"foo", APP_UID, 3_600_000, 90, 3_001_000);
assertThat(iterator.next(item)).isFalse();
}
private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode,
String tag, int uid, int batteryChargeUah, int batteryLevel, long elapsedTimeMs) {
assertThat(item.cmd).isEqualTo(command);
assertThat(item.eventCode).isEqualTo(eventCode);
if (tag == null) {
assertThat(item.eventTag).isNull();
} else {
assertThat(item.eventTag.string).isEqualTo(tag);
assertThat(item.eventTag.uid).isEqualTo(uid);
}
assertThat(item.batteryChargeUah).isEqualTo(batteryChargeUah);
assertThat(item.batteryLevel).isEqualTo(batteryLevel);
assertThat(item.time).isEqualTo(elapsedTimeMs);
}
}