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

Commit b08d95b7 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Android (Google) Code Review
Browse files

Merge "Making PowerMonitor API public" into main

parents 842762bc d68742df
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -33094,6 +33094,22 @@ package android.os {
    method public void onStateChanged(boolean);
  }
  @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public final class PowerMonitor implements android.os.Parcelable {
    method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public int describeContents();
    method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") @NonNull public String getName();
    method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public int getType();
    method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void writeToParcel(@NonNull android.os.Parcel, int);
    field @FlaggedApi("com.android.server.power.optimization.power_monitor_api") @NonNull public static final android.os.Parcelable.Creator<android.os.PowerMonitor> CREATOR;
    field @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public static final int POWER_MONITOR_TYPE_CONSUMER = 0; // 0x0
    field @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public static final int POWER_MONITOR_TYPE_MEASUREMENT = 1; // 0x1
  }
  @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public final class PowerMonitorReadings {
    method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public long getConsumedEnergy(@NonNull android.os.PowerMonitor);
    method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public long getTimestamp(@NonNull android.os.PowerMonitor);
    field @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public static final int ENERGY_UNAVAILABLE = -1; // 0xffffffff
  }
  public class Process {
    ctor public Process();
    method public static final long getElapsedCpuTime();
@@ -33656,6 +33672,8 @@ package android.os.health {
  }
  public class SystemHealthManager {
    method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getPowerMonitorReadings(@NonNull java.util.List<android.os.PowerMonitor>, @Nullable android.os.Handler, @NonNull java.util.function.Consumer<android.os.PowerMonitorReadings>, @NonNull java.util.function.Consumer<java.lang.RuntimeException>);
    method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getSupportedPowerMonitors(@Nullable android.os.Handler, @NonNull java.util.function.Consumer<java.util.List<android.os.PowerMonitor>>);
    method public android.os.health.HealthStats takeMyUidSnapshot();
    method public android.os.health.HealthStats takeUidSnapshot(int);
    method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
+46 −15
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.os;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;

@@ -23,12 +24,19 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * A PowerMonitor represents either a Channel aka ODPM rail (on-device power monitor) or an
 * EnergyConsumer, as defined in
 * <a href="https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats">android.hardware.power.stats</a>
 *
 * @hide
 * A PowerMonitor represents either an ODPM rail (on-device power rail monitor) or a modeled
 * energy consumer.
 * <p/>
 * ODPM rail names are device-specific. No assumptions should be made about the names and
 * exact purpose of ODPM rails across different device models. A rail name may be something
 * like "S2S_VDD_G3D"; specific knowledge of the device hardware is required to interpret
 * the corresponding power monitor data.
 * <p/>
 * Energy consumer have more human-readable names, e.g. "GPU", "MODEM" etc. However, developers
 * must be extra cautious about using energy consumers across different device models,
 * as their exact implementations are also hardware dependent and are customized by OEMs.
 */
@FlaggedApi("com.android.server.power.optimization.power_monitor_api")
public final class PowerMonitor implements Parcelable {

    /**
@@ -36,9 +44,9 @@ public final class PowerMonitor implements Parcelable {
     * power rail measurement, or modeled in some fashion.  For example, an energy consumer may
     * represent a combination of multiple rails or a portion of a rail shared between subsystems,
     * e.g. WiFi and Bluetooth are often handled by the same chip, powered by a shared rail.
     * Some consumer names are standardized (see android.hardware.power.stats.EnergyConsumerType),
     * others are not.
     * Some consumer names are standardized, others are not.
     */
    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    public static final int POWER_MONITOR_TYPE_CONSUMER = 0;

    /**
@@ -46,6 +54,7 @@ public final class PowerMonitor implements Parcelable {
     * no assumptions can be made about the source of those measurements across different devices,
     * even if they have the same name.
     */
    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    public static final int POWER_MONITOR_TYPE_MEASUREMENT = 1;

    /** @hide */
@@ -64,38 +73,60 @@ public final class PowerMonitor implements Parcelable {
     * @hide
     */
    public final int index;

    @PowerMonitorType
    public final int type;
    private final int mType;
    @NonNull
    public final String name;
    private final String mName;

    /**
     * @hide
     */
    public PowerMonitor(int index, int type, @NonNull String name) {
        this.index = index;
        this.type = type;
        this.name = name;
        this.mType = type;
        this.mName = name;
    }

    /**
     * Returns the type of the power monitor.
     */
    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    @PowerMonitorType
    public int getType() {
        return mType;
    }

    /**
     * Returns the name of the power monitor, either a power rail or an energy consumer.
     */
    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    @NonNull
    public String getName() {
        return mName;
    }

    private PowerMonitor(Parcel in) {
        index = in.readInt();
        type = in.readInt();
        name = in.readString();
        mType = in.readInt();
        mName = in.readString8();
    }

    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(index);
        dest.writeInt(type);
        dest.writeString(name);
        dest.writeInt(mType);
        dest.writeString8(mName);
    }

    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    @Override
    public int describeContents() {
        return 0;
    }

    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    @NonNull
    public static final Creator<PowerMonitor> CREATOR = new Creator<>() {
        @Override
+8 −5
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.os;

import android.annotation.ElapsedRealtimeLong;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;

import java.util.Arrays;
@@ -24,10 +25,10 @@ import java.util.Comparator;

/**
 * A collection of energy measurements from Power Monitors.
 *
 * @hide
 */
@FlaggedApi("com.android.server.power.optimization.power_monitor_api")
public final class PowerMonitorReadings {
    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    public static final int ENERGY_UNAVAILABLE = -1;

    @NonNull
@@ -41,7 +42,7 @@ public final class PowerMonitorReadings {
            Comparator.comparingInt(pm -> pm.index);

    /**
     * @param powerMonitors array of power monitor (ODPM) rails, sorted by PowerMonitor.index
     * @param powerMonitors array of power monitor, sorted by PowerMonitor.index
     * @hide
     */
    public PowerMonitorReadings(@NonNull PowerMonitor[] powerMonitors,
@@ -56,7 +57,8 @@ public final class PowerMonitorReadings {
     * Does not persist across reboots.
     * Represents total energy: both on-battery and plugged-in.
     */
    public long getConsumedEnergyUws(@NonNull PowerMonitor powerMonitor) {
    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    public long getConsumedEnergy(@NonNull PowerMonitor powerMonitor) {
        int offset = Arrays.binarySearch(mPowerMonitors, powerMonitor, POWER_MONITOR_COMPARATOR);
        if (offset >= 0) {
            return mEnergyUws[offset];
@@ -67,6 +69,7 @@ public final class PowerMonitorReadings {
    /**
     * Elapsed realtime, in milliseconds, when the snapshot was taken.
     */
    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    @ElapsedRealtimeLong
    public long getTimestamp(@NonNull PowerMonitor powerMonitor) {
        int offset = Arrays.binarySearch(mPowerMonitors, powerMonitor, POWER_MONITOR_COMPARATOR);
@@ -84,7 +87,7 @@ public final class PowerMonitorReadings {
            if (i != 0) {
                sb.append(", ");
            }
            sb.append(mPowerMonitors[i].name)
            sb.append(mPowerMonitors[i].getName())
                    .append(" = ").append(mEnergyUws[i])
                    .append(" (").append(mTimestampsMs[i]).append(')');
        }
+8 −62
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.os.health;

import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
@@ -24,7 +25,6 @@ import android.content.Context;
import android.os.BatteryStats;
import android.os.Build;
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.IPowerStatsService;
import android.os.PowerMonitor;
@@ -157,39 +157,15 @@ public class SystemHealthManager {
    }

    /**
     * Returns a list of supported power monitors, which include raw ODPM rails and
     * modeled energy consumers.  If ODPM is unsupported by PowerStats HAL, this method returns
     * an empty array.
     *
     * @hide
     */
    @NonNull
    public List<PowerMonitor> getSupportedPowerMonitors() {
        synchronized (mPowerMonitorsLock) {
            if (mPowerMonitorsInfo != null) {
                return mPowerMonitorsInfo;
            }
        }
        ConditionVariable lock = new ConditionVariable();
        // Populate mPowerMonitorsInfo by side-effect
        getSupportedPowerMonitors(null, unused -> lock.open());
        lock.block();

        synchronized (mPowerMonitorsLock) {
            return mPowerMonitorsInfo;
        }
    }

    /**
     * Asynchronously retrieves a list of supported power monitors, see
     * {@link #getSupportedPowerMonitors()}
     * Asynchronously retrieves a list of supported  {@link PowerMonitor}'s, which include raw ODPM
     * (on-device power rail monitor) rails and modeled energy consumers.  If ODPM is unsupported
     * on this device this method delivers an empty list.
     *
     * @param handler  optional Handler to deliver the callback. If not supplied, the callback
     *                 may be invoked on an arbitrary thread.
     * @param onResult callback for the result
     *
     * @hide
     */
    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    public void getSupportedPowerMonitors(@Nullable Handler handler,
            @NonNull Consumer<List<PowerMonitor>> onResult) {
        final List<PowerMonitor> result;
@@ -229,35 +205,6 @@ public class SystemHealthManager {
        }
    }

    /**
     * Retrieves the accumulated power consumption reported by the specified power monitors.
     *
     * @param powerMonitors power monitors to be returned.
     *
     * @hide
     */
    @NonNull
    public PowerMonitorReadings getPowerMonitorReadings(@NonNull List<PowerMonitor> powerMonitors) {
        PowerMonitorReadings[] outReadings = new PowerMonitorReadings[1];
        RuntimeException[] outException = new RuntimeException[1];
        ConditionVariable lock = new ConditionVariable();
        getPowerMonitorReadings(powerMonitors, null,
                pms -> {
                    outReadings[0] = pms;
                    lock.open();
                },
                error -> {
                    outException[0] = error;
                    lock.open();
                }
        );
        lock.block();
        if (outException[0] != null) {
            throw outException[0];
        }
        return outReadings[0];
    }

    private static final Comparator<PowerMonitor> POWER_MONITOR_COMPARATOR =
            Comparator.comparingInt(pm -> pm.index);

@@ -270,9 +217,8 @@ public class SystemHealthManager {
     *                      may be invoked on an arbitrary thread.
     * @param onSuccess     callback for the result
     * @param onError       callback invoked in case of an error
     *
     * @hide
     */
    @FlaggedApi("com.android.server.power.optimization.power_monitor_api")
    public void getPowerMonitorReadings(@NonNull List<PowerMonitor> powerMonitors,
            @Nullable Handler handler, @NonNull Consumer<PowerMonitorReadings> onSuccess,
            @NonNull Consumer<RuntimeException> onError) {
+0 −126
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.os.health;

import static androidx.test.InstrumentationRegistry.getContext;

import static com.google.common.truth.Truth.assertThat;

import android.os.ConditionVariable;
import android.os.PowerMonitor;
import android.os.PowerMonitorReadings;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

public class SystemHealthManagerTest {
    private List<PowerMonitor> mPowerMonitorInfo;
    private PowerMonitorReadings mReadings;
    private RuntimeException mException;

    @Test
    public void getPowerMonitors() {
        SystemHealthManager shm = getContext().getSystemService(SystemHealthManager.class);
        List<PowerMonitor> powerMonitorInfo = shm.getSupportedPowerMonitors();
        assertThat(powerMonitorInfo).isNotNull();
        if (powerMonitorInfo.isEmpty()) {
            // This device does not support PowerStats HAL
            return;
        }

        PowerMonitor consumerMonitor = null;
        PowerMonitor measurementMonitor = null;
        for (PowerMonitor pmi : powerMonitorInfo) {
            if (pmi.type == PowerMonitor.POWER_MONITOR_TYPE_MEASUREMENT) {
                measurementMonitor = pmi;
            } else {
                consumerMonitor = pmi;
            }
        }

        List<PowerMonitor> selectedMonitors = new ArrayList<>();
        if (consumerMonitor != null) {
            selectedMonitors.add(consumerMonitor);
        }
        if (measurementMonitor != null) {
            selectedMonitors.add(measurementMonitor);
        }

        PowerMonitorReadings readings = shm.getPowerMonitorReadings(selectedMonitors);

        for (PowerMonitor monitor : selectedMonitors) {
            assertThat(readings.getConsumedEnergyUws(monitor)).isAtLeast(0);
            assertThat(readings.getTimestamp(monitor)).isGreaterThan(0);
        }
    }

    @Test
    public void getPowerMonitorsAsync() {
        SystemHealthManager shm = getContext().getSystemService(SystemHealthManager.class);
        ConditionVariable done = new ConditionVariable();
        shm.getSupportedPowerMonitors(null, pms -> {
            mPowerMonitorInfo = pms;
            done.open();
        });
        done.block();
        assertThat(mPowerMonitorInfo).isNotNull();
        if (mPowerMonitorInfo.isEmpty()) {
            // This device does not support PowerStats HAL
            return;
        }

        PowerMonitor consumerMonitor = null;
        PowerMonitor measurementMonitor = null;
        for (PowerMonitor pmi : mPowerMonitorInfo) {
            if (pmi.type == PowerMonitor.POWER_MONITOR_TYPE_MEASUREMENT) {
                measurementMonitor = pmi;
            } else {
                consumerMonitor = pmi;
            }
        }

        List<PowerMonitor> selectedMonitors = new ArrayList<>();
        if (consumerMonitor != null) {
            selectedMonitors.add(consumerMonitor);
        }
        if (measurementMonitor != null) {
            selectedMonitors.add(measurementMonitor);
        }

        done.close();
        shm.getPowerMonitorReadings(selectedMonitors, null,
                readings -> {
                    mReadings = readings;
                    done.open();
                },
                exception -> {
                    mException = exception;
                    done.open();
                }
        );
        done.block();

        assertThat(mException).isNull();

        for (PowerMonitor monitor : selectedMonitors) {
            assertThat(mReadings.getConsumedEnergyUws(monitor)).isAtLeast(0);
            assertThat(mReadings.getTimestamp(monitor)).isGreaterThan(0);
        }
    }
}
Loading