Include saved battery history buffers into BatteryUsageStats parcel

Bug: 209297031
Test: atest FrameworksCoreTests:BatteryUsageStatsTest FrameworksCoreTests:BatteryUsageStatsProviderTest
Change-Id: I369d863b6f6fd488030aa031cc465bef6ce99ab8
This commit is contained in:
Dmitri Plotnikov
2021-12-16 19:14:03 -08:00
parent 57af351290
commit e07408d447
5 changed files with 84 additions and 28 deletions

View File

@@ -135,7 +135,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
private final List<UidBatteryConsumer> mUidBatteryConsumers; private final List<UidBatteryConsumer> mUidBatteryConsumers;
private final List<UserBatteryConsumer> mUserBatteryConsumers; private final List<UserBatteryConsumer> mUserBatteryConsumers;
private final AggregateBatteryConsumer[] mAggregateBatteryConsumers; private final AggregateBatteryConsumer[] mAggregateBatteryConsumers;
private final Parcel mHistoryBuffer; private final BatteryStatsHistory mBatteryStatsHistory;
private CursorWindow mBatteryConsumersCursorWindow; private CursorWindow mBatteryConsumersCursorWindow;
private BatteryUsageStats(@NonNull Builder builder) { private BatteryUsageStats(@NonNull Builder builder) {
@@ -146,7 +146,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
mDischargePercentage = builder.mDischargePercentage; mDischargePercentage = builder.mDischargePercentage;
mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah; mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah;
mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah; mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
mHistoryBuffer = builder.mHistoryBuffer; mBatteryStatsHistory = builder.mBatteryStatsHistory;
mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs; mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs;
mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs; mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;
mCustomPowerComponentNames = builder.mCustomPowerComponentNames; mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
@@ -301,11 +301,11 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
*/ */
@NonNull @NonNull
public BatteryStatsHistoryIterator iterateBatteryStatsHistory() { public BatteryStatsHistoryIterator iterateBatteryStatsHistory() {
if (mHistoryBuffer == null) { if (mBatteryStatsHistory == null) {
throw new IllegalStateException( throw new IllegalStateException(
"Battery history was not requested in the BatteryUsageStatsQuery"); "Battery history was not requested in the BatteryUsageStatsQuery");
} }
return new BatteryStatsHistoryIterator(new BatteryStatsHistory(mHistoryBuffer)); return new BatteryStatsHistoryIterator(mBatteryStatsHistory);
} }
@Override @Override
@@ -363,12 +363,9 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
} }
if (source.readBoolean()) { if (source.readBoolean()) {
final byte[] historyBlob = source.readBlob(); mBatteryStatsHistory = BatteryStatsHistory.createFromBatteryUsageStatsParcel(source);
mHistoryBuffer = Parcel.obtain();
mHistoryBuffer.unmarshall(historyBlob, 0, historyBlob.length);
} else { } else {
mHistoryBuffer = null; mBatteryStatsHistory = null;
} }
} }
@@ -389,9 +386,9 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
mBatteryConsumersCursorWindow.writeToParcel(dest, flags); mBatteryConsumersCursorWindow.writeToParcel(dest, flags);
if (mHistoryBuffer != null) { if (mBatteryStatsHistory != null) {
dest.writeBoolean(true); dest.writeBoolean(true);
dest.writeBlob(mHistoryBuffer.marshall()); mBatteryStatsHistory.writeToBatteryUsageStatsParcel(dest);
} else { } else {
dest.writeBoolean(false); dest.writeBoolean(false);
} }
@@ -770,7 +767,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
new SparseArray<>(); new SparseArray<>();
private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders = private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =
new SparseArray<>(); new SparseArray<>();
private Parcel mHistoryBuffer; private BatteryStatsHistory mBatteryStatsHistory;
public Builder(@NonNull String[] customPowerComponentNames) { public Builder(@NonNull String[] customPowerComponentNames) {
this(customPowerComponentNames, false, false); this(customPowerComponentNames, false, false);
@@ -895,8 +892,8 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
* Sets the parceled recent history. * Sets the parceled recent history.
*/ */
@NonNull @NonNull
public Builder setBatteryHistory(Parcel historyBuffer) { public Builder setBatteryHistory(BatteryStatsHistory batteryStatsHistory) {
mHistoryBuffer = historyBuffer; mBatteryStatsHistory = batteryStatsHistory;
return this; return this;
} }

View File

@@ -160,6 +160,11 @@ public class BatteryStatsHistory {
mHistoryDir = null; mHistoryDir = null;
mHistoryBuffer = historyBuffer; mHistoryBuffer = historyBuffer;
} }
public File getHistoryDirectory() {
return mHistoryDir;
}
/** /**
* Set the active file that mHistoryBuffer is backed up into. * Set the active file that mHistoryBuffer is backed up into.
* *
@@ -375,12 +380,26 @@ public class BatteryStatsHistory {
} }
/** /**
* Read all history files and serialize into a big Parcel. This is to send history files to * Read all history files and serialize into a big Parcel.
* Settings app since Settings app can not access /data/system directory. * Checkin file calls this method.
* Checkin file also call this method. *
* @param out the output parcel * @param out the output parcel
*/ */
public void writeToParcel(Parcel out) { public void writeToParcel(Parcel out) {
writeToParcel(out, false /* useBlobs */);
}
/**
* This is for Settings app, when Settings app receives big history parcel, it call
* this method to parse it into list of parcels.
* @param out the output parcel
*/
public void writeToBatteryUsageStatsParcel(Parcel out) {
out.writeBlob(mHistoryBuffer.marshall());
writeToParcel(out, true /* useBlobs */);
}
private void writeToParcel(Parcel out, boolean useBlobs) {
final long start = SystemClock.uptimeMillis(); final long start = SystemClock.uptimeMillis();
out.writeInt(mFileNumbers.size() - 1); out.writeInt(mFileNumbers.size() - 1);
for(int i = 0; i < mFileNumbers.size() - 1; i++) { for(int i = 0; i < mFileNumbers.size() - 1; i++) {
@@ -391,7 +410,12 @@ public class BatteryStatsHistory {
} catch(Exception e) { } catch(Exception e) {
Slog.e(TAG, "Error reading file "+ file.getBaseFile().getPath(), e); Slog.e(TAG, "Error reading file "+ file.getBaseFile().getPath(), e);
} }
out.writeByteArray(raw); if (useBlobs) {
out.writeBlob(raw);
} else {
// Avoiding blobs in the check-in file for compatibility
out.writeByteArray(raw);
}
} }
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start)); Slog.d(TAG, "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start));
@@ -399,18 +423,36 @@ public class BatteryStatsHistory {
} }
/** /**
* This is for Settings app, when Settings app receives big history parcel, it call * Reads a BatteryStatsHistory from a parcel written with
* this method to parse it into list of parcels. * the {@link #writeToBatteryUsageStatsParcel} method.
* Checkin file also call this method. */
public static BatteryStatsHistory createFromBatteryUsageStatsParcel(Parcel in) {
final byte[] historyBlob = in.readBlob();
Parcel historyBuffer = Parcel.obtain();
historyBuffer.unmarshall(historyBlob, 0, historyBlob.length);
BatteryStatsHistory history = new BatteryStatsHistory(historyBuffer);
history.readFromParcel(in, true /* useBlobs */);
return history;
}
/**
* This is for the check-in file, which has all history files embedded.
*
* @param in the input parcel. * @param in the input parcel.
*/ */
public void readFromParcel(Parcel in) { public void readFromParcel(Parcel in) {
readFromParcel(in, false /* useBlobs */);
}
private void readFromParcel(Parcel in, boolean useBlobs) {
final long start = SystemClock.uptimeMillis(); final long start = SystemClock.uptimeMillis();
mHistoryParcels = new ArrayList<>(); mHistoryParcels = new ArrayList<>();
final int count = in.readInt(); final int count = in.readInt();
for(int i = 0; i < count; i++) { for(int i = 0; i < count; i++) {
byte[] temp = in.createByteArray(); byte[] temp = useBlobs ? in.readBlob() : in.createByteArray();
if (temp.length == 0) { if (temp == null || temp.length == 0) {
continue; continue;
} }
Parcel p = Parcel.obtain(); Parcel p = Parcel.obtain();

View File

@@ -30,6 +30,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -200,7 +201,13 @@ public class BatteryUsageStatsProvider {
Parcel historyBuffer = Parcel.obtain(); Parcel historyBuffer = Parcel.obtain();
historyBuffer.appendFrom(batteryStatsImpl.mHistoryBuffer, 0, historyBuffer.appendFrom(batteryStatsImpl.mHistoryBuffer, 0,
batteryStatsImpl.mHistoryBuffer.dataSize()); batteryStatsImpl.mHistoryBuffer.dataSize());
batteryUsageStatsBuilder.setBatteryHistory(historyBuffer);
final File systemDir =
batteryStatsImpl.mBatteryStatsHistory.getHistoryDirectory().getParentFile();
final BatteryStatsHistory batteryStatsHistory =
new BatteryStatsHistory(batteryStatsImpl, systemDir, historyBuffer);
batteryUsageStatsBuilder.setBatteryHistory(batteryStatsHistory);
} }
return batteryUsageStatsBuilder.build(); return batteryUsageStatsBuilder.build();

View File

@@ -39,6 +39,8 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
import libcore.testing.io.TestIoUtils;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -52,9 +54,12 @@ public class BatteryUsageStatsProviderTest {
private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
private static final long MINUTE_IN_MS = 60 * 1000; private static final long MINUTE_IN_MS = 60 * 1000;
private final File mHistoryDir =
TestIoUtils.createTemporaryDirectory(getClass().getSimpleName());
@Rule @Rule
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(12345) public final BatteryUsageStatsRule mStatsRule =
.setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0); new BatteryUsageStatsRule(12345, mHistoryDir)
.setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0);
@Test @Test
public void test_getBatteryUsageStats() { public void test_getBatteryUsageStats() {

View File

@@ -40,6 +40,7 @@ import org.junit.runner.Description;
import org.junit.runners.model.Statement; import org.junit.runners.model.Statement;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import java.io.File;
import java.util.Arrays; import java.util.Arrays;
public class BatteryUsageStatsRule implements TestRule { public class BatteryUsageStatsRule implements TestRule {
@@ -57,14 +58,18 @@ public class BatteryUsageStatsRule implements TestRule {
private boolean mScreenOn; private boolean mScreenOn;
public BatteryUsageStatsRule() { public BatteryUsageStatsRule() {
this(0); this(0, null);
} }
public BatteryUsageStatsRule(long currentTime) { public BatteryUsageStatsRule(long currentTime) {
this(currentTime, null);
}
public BatteryUsageStatsRule(long currentTime, File historyDir) {
Context context = InstrumentationRegistry.getContext(); Context context = InstrumentationRegistry.getContext();
mPowerProfile = spy(new PowerProfile(context, true /* forTest */)); mPowerProfile = spy(new PowerProfile(context, true /* forTest */));
mMockClock.currentTime = currentTime; mMockClock.currentTime = currentTime;
mBatteryStats = new MockBatteryStatsImpl(mMockClock); mBatteryStats = new MockBatteryStatsImpl(mMockClock, historyDir);
mBatteryStats.setPowerProfile(mPowerProfile); mBatteryStats.setPowerProfile(mPowerProfile);
mBatteryStats.onSystemReady(); mBatteryStats.onSystemReady();
} }