Merge "Making PowerMonitor API public" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 36cdd7f..6c0fccc 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -33094,6 +33094,22 @@
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 @@
}
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[]);
diff --git a/core/java/android/os/PowerMonitor.java b/core/java/android/os/PowerMonitor.java
index 5fb0df7..8c5f2cd 100644
--- a/core/java/android/os/PowerMonitor.java
+++ b/core/java/android/os/PowerMonitor.java
@@ -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.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 @@
* 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 @@
* 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 @@
* @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
diff --git a/core/java/android/os/PowerMonitorReadings.java b/core/java/android/os/PowerMonitorReadings.java
index e767059..bb677d5 100644
--- a/core/java/android/os/PowerMonitorReadings.java
+++ b/core/java/android/os/PowerMonitorReadings.java
@@ -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 @@
/**
* 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 @@
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 @@
* 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 @@
/**
* 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 @@
if (i != 0) {
sb.append(", ");
}
- sb.append(mPowerMonitors[i].name)
+ sb.append(mPowerMonitors[i].getName())
.append(" = ").append(mEnergyUws[i])
.append(" (").append(mTimestampsMs[i]).append(')');
}
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index dfc43f4..2d53341 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -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.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 @@
}
/**
- * 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.
+ * 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.
*
- * @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()}
- *
- * @param handler optional Handler to deliver the callback. If not supplied, the callback
- * may be invoked on an arbitrary thread.
+ * @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 @@
}
}
- /**
- * 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 @@
* 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) {
diff --git a/core/tests/coretests/src/android/os/health/SystemHealthManagerTest.java b/core/tests/coretests/src/android/os/health/SystemHealthManagerTest.java
deleted file mode 100644
index e1f9523..0000000
--- a/core/tests/coretests/src/android/os/health/SystemHealthManagerTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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);
- }
- }
-}
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
index d61bebc..add806f 100644
--- a/services/core/java/com/android/server/power/stats/flags.aconfig
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -1,6 +1,13 @@
package: "com.android.server.power.optimization"
flag {
+ name: "power_monitor_api"
+ namespace: "power_optimization"
+ description: "Feature flag for ODPM API"
+ bug: "295027807"
+}
+
+flag {
name: "streamlined_battery_stats"
namespace: "power_optimization"
description: "Feature flag for streamlined battery stats"
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index 5609f69..77290fd 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -694,7 +694,7 @@
Log.d(TAG, String.format(Locale.ENGLISH,
"Monitor=%s timestamp=%d energy=%d"
+ " uid=%d noise=%.1f%% returned=%d",
- state.powerMonitor.name,
+ state.powerMonitor.getName(),
state.timestampMs,
state.energyUws,
callingUid,
@@ -728,7 +728,7 @@
}
for (PowerMonitorState powerMonitorState : powerMonitorStates) {
- if (powerMonitorState.powerMonitor.type
+ if (powerMonitorState.powerMonitor.getType()
== PowerMonitor.POWER_MONITOR_TYPE_CONSUMER) {
for (EnergyConsumerResult energyConsumerResult : energyConsumerResults) {
if (energyConsumerResult.id == powerMonitorState.id) {
@@ -754,7 +754,7 @@
}
for (PowerMonitorState powerMonitorState : powerMonitorStates) {
- if (powerMonitorState.powerMonitor.type
+ if (powerMonitorState.powerMonitor.getType()
== PowerMonitor.POWER_MONITOR_TYPE_MEASUREMENT) {
for (EnergyMeasurement energyMeasurement : energyMeasurements) {
if (energyMeasurement.id == powerMonitorState.id) {
@@ -773,7 +773,7 @@
@PowerMonitor.PowerMonitorType int type) {
int count = 0;
for (PowerMonitorState monitorState : powerMonitorStates) {
- if (monitorState.powerMonitor.type == type) {
+ if (monitorState.powerMonitor.getType() == type) {
count++;
}
}
@@ -785,7 +785,7 @@
int[] ids = new int[count];
int index = 0;
for (PowerMonitorState monitorState : powerMonitorStates) {
- if (monitorState.powerMonitor.type == type) {
+ if (monitorState.powerMonitor.getType() == type) {
ids[index++] = monitorState.id;
}
}
diff --git a/services/tests/powerstatstests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/powerstatstests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index 2ffe4aa..df46054 100644
--- a/services/tests/powerstatstests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -1079,7 +1079,7 @@
GetSupportedPowerMonitorsResult result = new GetSupportedPowerMonitorsResult();
mService.getSupportedPowerMonitorsImpl(result);
assertThat(result.powerMonitors).isNotNull();
- assertThat(Arrays.stream(result.powerMonitors).map(pm -> pm.name).toList())
+ assertThat(Arrays.stream(result.powerMonitors).map(PowerMonitor::getName).toList())
.containsAtLeast(
"energyconsumer0",
"BLUETOOTH/1",
@@ -1130,7 +1130,7 @@
mService.getSupportedPowerMonitorsImpl(supportedPowerMonitorsResult);
Map<String, PowerMonitor> map =
Arrays.stream(supportedPowerMonitorsResult.powerMonitors)
- .collect(Collectors.toMap(pm -> pm.name, pm -> pm));
+ .collect(Collectors.toMap(PowerMonitor::getName, pm -> pm));
PowerMonitor consumer1 = map.get("energyconsumer0");
PowerMonitor consumer2 = map.get("BLUETOOTH/1");
PowerMonitor measurement1 = map.get("[channelname0]:channelsubsystem0");
@@ -1196,6 +1196,6 @@
supportedPowerMonitorsResult = new GetSupportedPowerMonitorsResult();
mService.getSupportedPowerMonitorsImpl(supportedPowerMonitorsResult);
assertThat(Arrays.stream(supportedPowerMonitorsResult.powerMonitors)
- .map(pm -> pm.name).toList()).contains("energyconsumer0");
+ .map(PowerMonitor::getName).toList()).contains("energyconsumer0");
}
}