Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c6fb492 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Automerger Merge Worker
Browse files

Merge "Reduce size of BatteryUsageStats Parcel" into sc-dev am: 8b22190d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15020275

Change-Id: Iaca25ed1dfb3626aba7dee19684cc9471f468ef1
parents d40d9432 8b22190d
Loading
Loading
Loading
Loading
+26 −16
Original line number Diff line number Diff line
@@ -306,14 +306,23 @@ public final class BatteryUsageStats implements Parcelable {
                    AggregateBatteryConsumer.CREATOR.createFromParcel(source);
            mAggregateBatteryConsumers[i].setCustomPowerComponentNames(mCustomPowerComponentNames);
        }
        int uidCount = source.readInt();

        // UidBatteryConsumers are included as a blob to avoid a TransactionTooLargeException
        final Parcel blob = Parcel.obtain();
        final byte[] bytes = source.readBlob();
        blob.unmarshall(bytes, 0, bytes.length);
        blob.setDataPosition(0);

        final int uidCount = blob.readInt();
        mUidBatteryConsumers = new ArrayList<>(uidCount);
        for (int i = 0; i < uidCount; i++) {
            final UidBatteryConsumer consumer =
                    UidBatteryConsumer.CREATOR.createFromParcel(source);
                    UidBatteryConsumer.CREATOR.createFromParcel(blob);
            consumer.setCustomPowerComponentNames(mCustomPowerComponentNames);
            mUidBatteryConsumers.add(consumer);
        }
        blob.recycle();

        int userCount = source.readInt();
        mUserBatteryConsumers = new ArrayList<>(userCount);
        for (int i = 0; i < userCount; i++) {
@@ -323,14 +332,10 @@ public final class BatteryUsageStats implements Parcelable {
            mUserBatteryConsumers.add(consumer);
        }
        if (source.readBoolean()) {
            mHistoryBuffer = Parcel.obtain();
            mHistoryBuffer.setDataSize(0);
            mHistoryBuffer.setDataPosition(0);
            final byte[] historyBlob = source.readBlob();

            int historyBufferSize = source.readInt();
            int curPos = source.dataPosition();
            mHistoryBuffer.appendFrom(source, curPos, historyBufferSize);
            source.setDataPosition(curPos + historyBufferSize);
            mHistoryBuffer = Parcel.obtain();
            mHistoryBuffer.unmarshall(historyBlob, 0, historyBlob.length);

            int historyTagCount = source.readInt();
            mHistoryTagPool = new ArrayList<>(historyTagCount);
@@ -362,21 +367,26 @@ public final class BatteryUsageStats implements Parcelable {
        for (int i = 0; i < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; i++) {
            mAggregateBatteryConsumers[i].writeToParcel(dest, flags);
        }
        dest.writeInt(mUidBatteryConsumers.size());

        // UidBatteryConsumers are included as a blob, because each UidBatteryConsumer
        // takes > 300 bytes, so a typical number of UIDs in the system, 300 would result
        // in a 90 kB Parcel, which is not safe to pass in a binder transaction because
        // of the possibility of TransactionTooLargeException
        final Parcel blob = Parcel.obtain();
        blob.writeInt(mUidBatteryConsumers.size());
        for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) {
            mUidBatteryConsumers.get(i).writeToParcel(dest, flags);
            mUidBatteryConsumers.get(i).writeToParcel(blob, flags);
        }
        dest.writeBlob(blob.marshall());
        blob.recycle();

        dest.writeInt(mUserBatteryConsumers.size());
        for (int i = mUserBatteryConsumers.size() - 1; i >= 0; i--) {
            mUserBatteryConsumers.get(i).writeToParcel(dest, flags);
        }
        if (mHistoryBuffer != null) {
            dest.writeBoolean(true);

            final int historyBufferSize = mHistoryBuffer.dataSize();
            dest.writeInt(historyBufferSize);
            dest.appendFrom(mHistoryBuffer, 0, historyBufferSize);

            dest.writeBlob(mHistoryBuffer.marshall());
            dest.writeInt(mHistoryTagPool.size());
            for (int i = mHistoryTagPool.size() - 1; i >= 0; i--) {
                final BatteryStats.HistoryTag tag = mHistoryTagPool.get(i);
+47 −1
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.os.BatteryConsumer;
import android.os.BatteryUsageStats;
@@ -47,7 +49,9 @@ import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -64,13 +68,15 @@ public class BatteryUsageStatsTest {
    }

    @Test
    public void testParcelability() {
    public void testParcelability_smallNumberOfUids() {
        final BatteryUsageStats outBatteryUsageStats = buildBatteryUsageStats1(true).build();
        final Parcel outParcel = Parcel.obtain();
        outParcel.writeParcelable(outBatteryUsageStats, 0);
        final byte[] bytes = outParcel.marshall();
        outParcel.recycle();

        assertThat(bytes.length).isLessThan(2000);

        final Parcel inParcel = Parcel.obtain();
        inParcel.unmarshall(bytes, 0, bytes.length);
        inParcel.setDataPosition(0);
@@ -80,6 +86,46 @@ public class BatteryUsageStatsTest {
        assertBatteryUsageStats1(inBatteryUsageStats, true);
    }

    @Test
    public void testParcelability_largeNumberOfUids() {
        final BatteryUsageStats.Builder builder =
                new BatteryUsageStats.Builder(new String[0]);

        // Without the use of a blob, this BatteryUsageStats object would generate a Parcel
        // larger than 64 Kb
        final int uidCount = 200;
        for (int i = 0; i < uidCount; i++) {
            BatteryStatsImpl.Uid mockUid = mock(BatteryStatsImpl.Uid.class);
            when(mockUid.getUid()).thenReturn(i);
            builder.getOrCreateUidBatteryConsumerBuilder(mockUid)
                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, i * 100);
        }

        BatteryUsageStats outBatteryUsageStats = builder.build();

        final Parcel parcel = Parcel.obtain();
        parcel.writeParcelable(outBatteryUsageStats, 0);

        assertThat(parcel.dataSize()).isLessThan(2000);

        // This parcel cannot be marshaled because it contains a file descriptor.
        // Assuming that parcel marshaling works fine, let's just rewind the parcel.
        parcel.setDataPosition(0);

        final BatteryUsageStats inBatteryUsageStats =
                parcel.readParcelable(getClass().getClassLoader());
        parcel.recycle();

        assertThat(inBatteryUsageStats.getUidBatteryConsumers()).hasSize(uidCount);
        final Map<Integer, UidBatteryConsumer> consumersByUid =
                inBatteryUsageStats.getUidBatteryConsumers().stream().collect(
                        Collectors.toMap(UidBatteryConsumer::getUid, c -> c));
        for (int i = 0; i < uidCount; i++) {
            final UidBatteryConsumer uidBatteryConsumer = consumersByUid.get(i);
            assertThat(uidBatteryConsumer).isNotNull();
            assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(i * 100);
        }
    }

    @Test
    public void testDefaultSessionDuration() {