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

Commit bded2c13 authored by Benjamin Schwartz's avatar Benjamin Schwartz Committed by Android (Google) Code Review
Browse files

Merge "Introduce PowerStatsInternal and replace PowerStatsHalWrapper usage"

parents 4a1ca0c2 605ac95a
Loading
Loading
Loading
Loading
+46 −36
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.internal.os;
import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
import static com.android.internal.power.MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -103,7 +105,6 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeRead
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
import com.android.internal.power.MeasuredEnergyArray;
import com.android.internal.power.MeasuredEnergyStats;
import com.android.internal.power.MeasuredEnergyStats.EnergyBucket;
import com.android.internal.util.ArrayUtils;
@@ -370,14 +371,6 @@ public class BatteryStatsImpl extends BatteryStats {
         * @param railStats
         */
        void fillRailDataStats(RailStats railStats);
        /**
         * Function to get energy consumption data
         *
         * @return an array of measured energy (in microjoules) since boot, will be null if
         * measured energy data is unavailable
         */
        @Nullable
        MeasuredEnergyArray getEnergyConsumptionData();
    }
    public static abstract class UserInfoProvider {
@@ -10704,15 +10697,13 @@ public class BatteryStatsImpl extends BatteryStats {
    }
    public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb,
            MeasuredEnergyRetriever energyStatsCb, boolean[] supportedEnergyBuckets,
            UserInfoProvider userInfoProvider) {
        this(new SystemClocks(), systemDir, handler, cb, energyStatsCb, supportedEnergyBuckets,
                userInfoProvider);
            MeasuredEnergyRetriever energyStatsCb, UserInfoProvider userInfoProvider) {
        this(new SystemClocks(), systemDir, handler, cb, energyStatsCb, userInfoProvider);
    }
    private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
            PlatformIdleStateCallback cb, MeasuredEnergyRetriever energyStatsCb,
            boolean[] supportedEnergyBuckets, UserInfoProvider userInfoProvider) {
            UserInfoProvider userInfoProvider) {
        init(clocks);
        if (systemDir == null) {
@@ -10818,10 +10809,6 @@ public class BatteryStatsImpl extends BatteryStats {
        // Notify statsd that the system is initially not in doze.
        mDeviceIdleMode = DEVICE_IDLE_MODE_OFF;
        FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode);
        mGlobalMeasuredEnergyStats = supportedEnergyBuckets == null ? null :
                new MeasuredEnergyStats(supportedEnergyBuckets);
        mScreenStateAtLastEnergyMeasurement = mScreenState;
    }
    @UnsupportedAppUsage
@@ -12502,21 +12489,6 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }
    /**
     * Get energy consumed (in microjoules) by a set of subsystems from the {@link
     * MeasuredEnergyRetriever}, if available.
     *
     * @return a SparseLongArray that maps consumer id to energy consumed. Returns null if data is
     * unavailable.
     */
    @Nullable
    public MeasuredEnergyArray getEnergyConsumptionDataLocked() {
        if (mMeasuredEnergyRetriever == null) {
            return null;
        }
        return mMeasuredEnergyRetriever.getEnergyConsumptionData();
    }
    /**
     * Read and distribute kernel wake lock use across apps.
     */
@@ -14240,6 +14212,40 @@ public class BatteryStatsImpl extends BatteryStats {
        mConstants.startObserving(context.getContentResolver());
        registerUsbStateReceiver(context);
    }
    /**
     * Initialize the measured energy stats data structures.
     *
     * @param supportedEnergyBuckets boolean array indicating which buckets are currently supported
     */
    @GuardedBy("this")
    public void initMeasuredEnergyStatsLocked(boolean[] supportedEnergyBuckets) {
        boolean supportedBucketMismatch = false;
        mScreenStateAtLastEnergyMeasurement = mScreenState;
        if (supportedEnergyBuckets == null) {
            if (mGlobalMeasuredEnergyStats != null) {
                // Measured energy buckets no longer supported, wipe out the existing data.
                supportedBucketMismatch = true;
            }
        } else if (mGlobalMeasuredEnergyStats == null) {
            mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedEnergyBuckets);
            return;
        } else {
            for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
                if (mGlobalMeasuredEnergyStats.isEnergyBucketSupported(i)
                        != supportedEnergyBuckets[i]) {
                    supportedBucketMismatch = true;
                    break;
                }
            }
        }
        if (supportedBucketMismatch) {
            // Supported energy buckets changed since last boot.
            // Existing data is no longer reliable.
            resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime());
        }
    }
    @VisibleForTesting
    public final class Constants extends ContentObserver {
@@ -14919,7 +14925,11 @@ public class BatteryStatsImpl extends BatteryStats {
        mNextMaxDailyDeadlineMs = in.readLong();
        mBatteryTimeToFullSeconds = in.readLong();
        MeasuredEnergyStats.readSummaryFromParcel(mGlobalMeasuredEnergyStats, in);
        /**
         * WARNING: Supported buckets may have changed across boots. Bucket mismatch is handled
         *          later when {@link #initMeasuredEnergyStatsLocked} is called.
         */
        mGlobalMeasuredEnergyStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(in);
        mStartCount++;
@@ -15417,7 +15427,7 @@ public class BatteryStatsImpl extends BatteryStats {
        out.writeLong(mNextMaxDailyDeadlineMs);
        out.writeLong(mBatteryTimeToFullSeconds);
        MeasuredEnergyStats.writeSummaryToParcel(mGlobalMeasuredEnergyStats, out);
        MeasuredEnergyStats.writeSummaryToParcel(mGlobalMeasuredEnergyStats, out, false);
        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
        mScreenDozeTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -15742,7 +15752,7 @@ public class BatteryStatsImpl extends BatteryStats {
                out.writeInt(0);
            }
            MeasuredEnergyStats.writeSummaryToParcel(u.mUidMeasuredEnergyStats, out);
            MeasuredEnergyStats.writeSummaryToParcel(u.mUidMeasuredEnergyStats, out, true);
            final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap();
            int NW = wakeStats.size();
+23 −15
Original line number Diff line number Diff line
@@ -130,27 +130,32 @@ public class MeasuredEnergyStats {
     * Note: {@link com.android.internal.os.BatteryStatsImpl#VERSION} must be updated if summary
     *       parceling changes.
     */
    private void readSummaryFromParcel(Parcel in) {
    private void readSummaryFromParcel(Parcel in, boolean overwriteAvailability) {
        final int size = in.readInt();
        for (int i = 0; i < size; i++) {
            final int bucket = in.readInt();
            final long energyUJ = in.readLong();
            if (overwriteAvailability) {
                mAccumulatedEnergiesMicroJoules[bucket] = energyUJ;
            } else {
                setValueIfSupported(bucket, energyUJ);
            }
        }
    }

    /**
     * Write to summary parcel.
     * Note: Measured subsystem availability may be different when the summary parcel is read.
     */
    private void writeSummaryToParcel(Parcel out) {
    private void writeSummaryToParcel(Parcel out, boolean skipZero) {
        final int sizePos = out.dataPosition();
        out.writeInt(0);
        int size = 0;
        // Write only the supported buckets with non-zero energy.
        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
            final long energy = mAccumulatedEnergiesMicroJoules[i];
            if (energy <= 0) continue;
            if (energy < 0) continue;
            if (energy == 0 && skipZero) continue;

            out.writeInt(i);
            out.writeLong(mAccumulatedEnergiesMicroJoules[i]);
@@ -197,16 +202,19 @@ public class MeasuredEnergyStats {
    }

    /**
     * Populate a MeasuredEnergyStats from a parcel. If the stats is null, consume and
     * ignore the parcelled data.
     * Create a MeasuredEnergyStats object from a summary parcel.
     *
     * @return a new MeasuredEnergyStats object as described.
     *         Returns null if the parcel indicates there is no data to populate.
     */
    public static void readSummaryFromParcel(@Nullable MeasuredEnergyStats stats, Parcel in) {
    public static @Nullable MeasuredEnergyStats createAndReadSummaryFromParcel(Parcel in) {
        // Check if any MeasuredEnergyStats exists on the parcel
        if (in.readInt() == 0) return;
        if (in.readInt() == 0) return null;

        // If stats is null, create a placeholder MeasuredEnergyStats to consume the parcel data
        final MeasuredEnergyStats mes = stats != null ? stats : new MeasuredEnergyStats();
        mes.readSummaryFromParcel(in);
        final MeasuredEnergyStats stats =
                new MeasuredEnergyStats(new boolean[NUMBER_ENERGY_BUCKETS]);
        stats.readSummaryFromParcel(in, true);
        return stats;
    }

    /**
@@ -227,12 +235,12 @@ public class MeasuredEnergyStats {
        if (template == null) {
            // Nothing supported now. Create placeholder object just to consume the parcel data.
            final MeasuredEnergyStats mes = new MeasuredEnergyStats();
            mes.readSummaryFromParcel(in);
            mes.readSummaryFromParcel(in, false);
            return null;
        }

        final MeasuredEnergyStats stats = createFromTemplate(template);
        stats.readSummaryFromParcel(in);
        stats.readSummaryFromParcel(in, false);
        if (stats.containsInterestingData()) {
            return stats;
        } else {
@@ -253,13 +261,13 @@ public class MeasuredEnergyStats {
     * Write a MeasuredEnergyStats to a parcel. If the stats is null, just write a 0.
     */
    public static void writeSummaryToParcel(@Nullable MeasuredEnergyStats stats,
            Parcel dest) {
            Parcel dest, boolean skipZero) {
        if (stats == null) {
            dest.writeInt(0);
            return;
        }
        dest.writeInt(1);
        stats.writeSummaryToParcel(dest);
        stats.writeSummaryToParcel(dest, skipZero);
    }

    /** Reset accumulated energy. */
+60 −23
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import androidx.test.filters.SmallTest;

import org.junit.Test;

import java.util.Arrays;

/**
 * Test class for {@link MeasuredEnergyStats}.
 *
@@ -114,7 +116,7 @@ public class MeasuredEnergyStatsTest {
    }

    @Test
    public void testReadWriteSummaryParcel() {
    public void testCreateAndReadSummaryFromParcel() {
        final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
        supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
        supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
@@ -126,35 +128,21 @@ public class MeasuredEnergyStatsTest {
        stats.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);

        final Parcel parcel = Parcel.obtain();
        MeasuredEnergyStats.writeSummaryToParcel(stats, parcel);


        final boolean[] newSupportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
        newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
        newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = true; // switched from false to true
        newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_OTHER] = false; // switched true to false
        MeasuredEnergyStats newStats = new MeasuredEnergyStats(newSupportedEnergyBuckets);
        MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
        parcel.setDataPosition(0);
        MeasuredEnergyStats.readSummaryFromParcel(newStats, parcel);
        MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel);

        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
            if (!newSupportedEnergyBuckets[i]) {
                assertFalse(newStats.isEnergyBucketSupported(i));
                assertEquals(ENERGY_DATA_UNAVAILABLE, newStats.getAccumulatedBucketEnergy(i));
            } else if (!supportedEnergyBuckets[i]) {
                assertTrue(newStats.isEnergyBucketSupported(i));
                assertEquals(0L, newStats.getAccumulatedBucketEnergy(i));
            } else {
                assertTrue(newStats.isEnergyBucketSupported(i));
            assertEquals(stats.isEnergyBucketSupported(i),
                    newStats.isEnergyBucketSupported(i));
            assertEquals(stats.getAccumulatedBucketEnergy(i),
                    newStats.getAccumulatedBucketEnergy(i));
        }
        }
        parcel.recycle();
    }

    @Test
    public void testCreateAndReadSummaryFromParcel() {
    public void testCreateAndReadSummaryFromParcel_existingTemplate() {
        final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
        supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
        supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
@@ -171,7 +159,7 @@ public class MeasuredEnergyStatsTest {
        stats.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 63, true);

        final Parcel parcel = Parcel.obtain();
        MeasuredEnergyStats.writeSummaryToParcel(stats, parcel);
        MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);

        final boolean[] newSupportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
        newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
@@ -199,6 +187,55 @@ public class MeasuredEnergyStatsTest {
        parcel.recycle();
    }

    @Test
    public void testCreateAndReadSummaryFromParcel_skipZero() {
        final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
        Arrays.fill(supportedEnergyBuckets, true);

        final MeasuredEnergyStats stats = new MeasuredEnergyStats(supportedEnergyBuckets);
        // Accumulate energy in one bucket, the rest should be zero
        stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 200, true);

        final Parcel includeZerosParcel = Parcel.obtain();
        MeasuredEnergyStats.writeSummaryToParcel(stats, includeZerosParcel, false);
        includeZerosParcel.setDataPosition(0);

        MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(
                includeZerosParcel);

        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
            if (i == ENERGY_BUCKET_SCREEN_ON) {
                assertEquals(stats.isEnergyBucketSupported(i),
                        newStats.isEnergyBucketSupported(i));
                assertEquals(stats.getAccumulatedBucketEnergy(i),
                        newStats.getAccumulatedBucketEnergy(i));
            } else {
                assertTrue(newStats.isEnergyBucketSupported(i));
                assertEquals(0L, newStats.getAccumulatedBucketEnergy(i));
            }
        }
        includeZerosParcel.recycle();

        final Parcel skipZerosParcel = Parcel.obtain();
        MeasuredEnergyStats.writeSummaryToParcel(stats, skipZerosParcel, true);
        skipZerosParcel.setDataPosition(0);

        newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(skipZerosParcel);

        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
            if (i == ENERGY_BUCKET_SCREEN_ON) {
                assertEquals(stats.isEnergyBucketSupported(i),
                        newStats.isEnergyBucketSupported(i));
                assertEquals(stats.getAccumulatedBucketEnergy(i),
                        newStats.getAccumulatedBucketEnergy(i));
            } else {
                assertFalse(newStats.isEnergyBucketSupported(i));
                assertEquals(ENERGY_DATA_UNAVAILABLE, newStats.getAccumulatedBucketEnergy(i));
            }
        }
        skipZerosParcel.recycle();
    }

    @Test
    public void testUpdateBucket() {
        final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
+42 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.power;

import android.hardware.power.stats.EnergyConsumerId;
import android.hardware.power.stats.EnergyConsumerResult;

import java.util.concurrent.CompletableFuture;

/**
 * Power stats local system service interface.
 *
 * @hide Only for use within Android OS.
 */
public abstract class PowerStatsInternal {
    /**
     * Returns a CompletableFuture that will get an {@link EnergyConsumerResult} array for the
     * available requested energy consumers (power models).
     *
     * @param energyConsumerIds Array of {@link EnergyConsumerId} for which energy consumed is being
     *                          requested.
     *
     * @return A Future containing a list of {@link EnergyConsumerResult} objects containing energy
     *         consumer results for all listed {@link EnergyConsumerId}.
     */
    public abstract CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync(
            @EnergyConsumerId int[] energyConsumerIds);
}
+112 −27

File changed.

Preview size limit exceeded, changes collapsed.

Loading