summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/os/BatteryConsumer.java91
-rw-r--r--core/java/android/os/BatteryUsageStats.java68
-rw-r--r--core/java/android/os/PowerComponents.java57
3 files changed, 197 insertions, 19 deletions
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index edb30b0f26ca..da94d74e5ae8 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -18,6 +18,8 @@ package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.proto.ProtoOutputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -59,27 +61,32 @@ public abstract class BatteryConsumer {
public static @interface PowerComponent {
}
- public static final int POWER_COMPONENT_SCREEN = 0;
- public static final int POWER_COMPONENT_CPU = 1;
- public static final int POWER_COMPONENT_BLUETOOTH = 2;
- public static final int POWER_COMPONENT_CAMERA = 3;
- public static final int POWER_COMPONENT_AUDIO = 4;
- public static final int POWER_COMPONENT_VIDEO = 5;
- public static final int POWER_COMPONENT_FLASHLIGHT = 6;
- public static final int POWER_COMPONENT_SYSTEM_SERVICES = 7;
- public static final int POWER_COMPONENT_MOBILE_RADIO = 8;
- public static final int POWER_COMPONENT_SENSORS = 9;
- public static final int POWER_COMPONENT_GNSS = 10;
- public static final int POWER_COMPONENT_WIFI = 11;
- public static final int POWER_COMPONENT_WAKELOCK = 12;
- public static final int POWER_COMPONENT_MEMORY = 13;
- public static final int POWER_COMPONENT_PHONE = 14;
- public static final int POWER_COMPONENT_AMBIENT_DISPLAY = 15;
- public static final int POWER_COMPONENT_IDLE = 16;
+ public static final int POWER_COMPONENT_SCREEN = OsProtoEnums.POWER_COMPONENT_SCREEN; // 0
+ public static final int POWER_COMPONENT_CPU = OsProtoEnums.POWER_COMPONENT_CPU; // 1
+ public static final int POWER_COMPONENT_BLUETOOTH = OsProtoEnums.POWER_COMPONENT_BLUETOOTH; // 2
+ public static final int POWER_COMPONENT_CAMERA = OsProtoEnums.POWER_COMPONENT_CAMERA; // 3
+ public static final int POWER_COMPONENT_AUDIO = OsProtoEnums.POWER_COMPONENT_AUDIO; // 4
+ public static final int POWER_COMPONENT_VIDEO = OsProtoEnums.POWER_COMPONENT_VIDEO; // 5
+ public static final int POWER_COMPONENT_FLASHLIGHT =
+ OsProtoEnums.POWER_COMPONENT_FLASHLIGHT; // 6
+ public static final int POWER_COMPONENT_SYSTEM_SERVICES =
+ OsProtoEnums.POWER_COMPONENT_SYSTEM_SERVICES; // 7
+ public static final int POWER_COMPONENT_MOBILE_RADIO =
+ OsProtoEnums.POWER_COMPONENT_MOBILE_RADIO; // 8
+ public static final int POWER_COMPONENT_SENSORS = OsProtoEnums.POWER_COMPONENT_SENSORS; // 9
+ public static final int POWER_COMPONENT_GNSS = OsProtoEnums.POWER_COMPONENT_GNSS; // 10
+ public static final int POWER_COMPONENT_WIFI = OsProtoEnums.POWER_COMPONENT_WIFI; // 11
+ public static final int POWER_COMPONENT_WAKELOCK = OsProtoEnums.POWER_COMPONENT_WAKELOCK; // 12
+ public static final int POWER_COMPONENT_MEMORY = OsProtoEnums.POWER_COMPONENT_MEMORY; // 13
+ public static final int POWER_COMPONENT_PHONE = OsProtoEnums.POWER_COMPONENT_PHONE; // 14
+ public static final int POWER_COMPONENT_AMBIENT_DISPLAY =
+ OsProtoEnums.POWER_COMPONENT_AMBIENT_DISPLAY; // 15
+ public static final int POWER_COMPONENT_IDLE = OsProtoEnums.POWER_COMPONENT_IDLE; // 16
// Power that is re-attributed to other battery consumers. For example, for System Server
// this represents the power attributed to apps requesting system services.
// The value should be negative or zero.
- public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS = 17;
+ public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS =
+ OsProtoEnums.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS; // 17
public static final int POWER_COMPONENT_COUNT = 18;
@@ -263,6 +270,54 @@ public abstract class BatteryConsumer {
*/
public abstract void dump(PrintWriter pw, boolean skipEmptyComponents);
+ /** Returns whether there are any atoms.proto BATTERY_CONSUMER_DATA data to write to a proto. */
+ boolean hasStatsProtoData() {
+ return writeStatsProtoImpl(null, /* Irrelevant fieldId: */ 0);
+ }
+
+ /** Writes the atoms.proto BATTERY_CONSUMER_DATA for this BatteryConsumer to the given proto. */
+ void writeStatsProto(@NonNull ProtoOutputStream proto, long fieldId) {
+ writeStatsProtoImpl(proto, fieldId);
+ }
+
+ /**
+ * Returns whether there are any atoms.proto BATTERY_CONSUMER_DATA data to write to a proto,
+ * and writes it to the given proto if it is non-null.
+ */
+ private boolean writeStatsProtoImpl(@Nullable ProtoOutputStream proto, long fieldId) {
+ final long totalConsumedPowerDeciCoulombs = convertMahToDeciCoulombs(getConsumedPower());
+
+ if (totalConsumedPowerDeciCoulombs == 0) {
+ // NOTE: Strictly speaking we should also check !mPowerComponents.hasStatsProtoData().
+ // However, that call is a bit expensive (a for loop). And the only way that
+ // totalConsumedPower can be 0 while mPowerComponents.hasStatsProtoData() is true is
+ // if POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS (which is the only negative
+ // allowed) happens to exactly equal the sum of all other components, which
+ // can't really happen in practice.
+ // So we'll just adopt the rule "if total==0, don't write any details".
+ // If negative values are used for other things in the future, this can be revisited.
+ return false;
+ }
+ if (proto == null) {
+ // We're just asked whether there is data, not to actually write it. And there is.
+ return true;
+ }
+
+ final long token = proto.start(fieldId);
+ proto.write(
+ BatteryUsageStatsAtomsProto.BatteryConsumerData.TOTAL_CONSUMED_POWER_DECI_COULOMBS,
+ totalConsumedPowerDeciCoulombs);
+ mPowerComponents.writeStatsProto(proto);
+ proto.end(token);
+
+ return true;
+ }
+
+ /** Converts charge from milliamp hours (mAh) to decicoulombs (dC). */
+ static long convertMahToDeciCoulombs(double powerMah) {
+ return (long) (powerMah * (10 * 3600 / 1000) + 0.5);
+ }
+
protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
final PowerComponents.Builder mPowerComponentsBuilder;
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 8f366636ed9f..370052d47d16 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.util.Range;
import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.os.BatteryStatsHistory;
import com.android.internal.os.BatteryStatsHistoryIterator;
@@ -184,7 +185,8 @@ public final class BatteryUsageStats implements Parcelable {
/**
* Portion of battery charge drained since BatteryStats reset (e.g. due to being fully
- * charged), as percentage of the full charge in the range [0:100]
+ * charged), as percentage of the full charge in the range [0:100]. May exceed 100 if
+ * the device repeatedly charged and discharged prior to the reset.
*/
public int getDischargePercentage() {
return mDischargePercentage;
@@ -365,6 +367,70 @@ public final class BatteryUsageStats implements Parcelable {
}
};
+ /** Returns a proto (as used for atoms.proto) corresponding to this BatteryUsageStats. */
+ public byte[] getStatsProto(long sessionEndTimestampMs) {
+
+ final long sessionStartMillis = getStatsStartTimestamp();
+ // TODO(b/187223764): Use the getStatsEndTimestamp() instead, once that is added.
+ final long sessionEndMillis = sessionEndTimestampMs;
+ final long sessionDurationMillis = sessionEndTimestampMs - getStatsStartTimestamp();
+
+ final BatteryConsumer deviceBatteryConsumer = getAggregateBatteryConsumer(
+ AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
+
+ final int sessionDischargePercentage = getDischargePercentage();
+
+ final ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(BatteryUsageStatsAtomsProto.SESSION_START_MILLIS, sessionStartMillis);
+ proto.write(BatteryUsageStatsAtomsProto.SESSION_END_MILLIS, sessionEndMillis);
+ proto.write(BatteryUsageStatsAtomsProto.SESSION_DURATION_MILLIS, sessionDurationMillis);
+ deviceBatteryConsumer.writeStatsProto(proto,
+ BatteryUsageStatsAtomsProto.DEVICE_BATTERY_CONSUMER);
+ writeUidBatteryConsumersProto(proto);
+ proto.write(BatteryUsageStatsAtomsProto.SESSION_DISCHARGE_PERCENTAGE,
+ sessionDischargePercentage);
+ return proto.getBytes();
+ }
+
+ /**
+ * Writes the UidBatteryConsumers data, held by this BatteryUsageStats, to the proto (as used
+ * for atoms.proto).
+ */
+ private void writeUidBatteryConsumersProto(ProtoOutputStream proto) {
+ final List<UidBatteryConsumer> consumers = getUidBatteryConsumers();
+
+ // TODO: Sort the list by power consumption. If during the for, proto.getRawSize() > 45kb,
+ // truncate the remainder of the list.
+ final int size = consumers.size();
+ for (int i = 0; i < size; i++) {
+ final UidBatteryConsumer consumer = consumers.get(i);
+
+ final long fgMs = consumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND);
+ final long bgMs = consumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND);
+ final boolean hasBaseData = consumer.hasStatsProtoData();
+
+ if (fgMs == 0 && bgMs == 0 && !hasBaseData) {
+ continue;
+ }
+
+ final long token = proto.start(BatteryUsageStatsAtomsProto.UID_BATTERY_CONSUMERS);
+ proto.write(
+ BatteryUsageStatsAtomsProto.UidBatteryConsumer.UID,
+ consumer.getUid());
+ if (hasBaseData) {
+ consumer.writeStatsProto(proto,
+ BatteryUsageStatsAtomsProto.UidBatteryConsumer.BATTERY_CONSUMER_DATA);
+ }
+ proto.write(
+ BatteryUsageStatsAtomsProto.UidBatteryConsumer.TIME_IN_FOREGROUND_MILLIS,
+ fgMs);
+ proto.write(
+ BatteryUsageStatsAtomsProto.UidBatteryConsumer.TIME_IN_BACKGROUND_MILLIS,
+ bgMs);
+ proto.end(token);
+ }
+ }
+
/**
* Prints the stats in a human-readable format.
*/
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 964f1b681866..a90ed20d54fc 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -15,7 +15,11 @@
*/
package android.os;
+import static android.os.BatteryConsumer.convertMahToDeciCoulombs;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.os.PowerCalculator;
@@ -237,6 +241,59 @@ class PowerComponents {
}
}
+ /** Returns whether there are any atoms.proto POWER_COMPONENTS data to write to a proto. */
+ boolean hasStatsProtoData() {
+ return writeStatsProtoImpl(null);
+ }
+
+ /** Writes all atoms.proto POWER_COMPONENTS for this PowerComponents to the given proto. */
+ void writeStatsProto(@NonNull ProtoOutputStream proto) {
+ writeStatsProtoImpl(proto);
+ }
+
+ /**
+ * Returns whether there are any atoms.proto POWER_COMPONENTS data to write to a proto,
+ * and writes it to the given proto if it is non-null.
+ */
+ private boolean writeStatsProtoImpl(@Nullable ProtoOutputStream proto) {
+ boolean interestingData = false;
+
+ for (int idx = 0; idx < mPowerComponentsMah.length; idx++) {
+ final int componentId = idx < BatteryConsumer.POWER_COMPONENT_COUNT ?
+ idx : idx - CUSTOM_POWER_COMPONENT_OFFSET;
+ final long powerDeciCoulombs = convertMahToDeciCoulombs(mPowerComponentsMah[idx]);
+ final long durationMs = mUsageDurationsMs[idx];
+
+ if (powerDeciCoulombs == 0 && durationMs == 0) {
+ // No interesting data. Make sure not to even write the COMPONENT int.
+ continue;
+ }
+
+ interestingData = true;
+ if (proto == null) {
+ // We're just asked whether there is data, not to actually write it. And there is.
+ return true;
+ }
+
+ final long token =
+ proto.start(BatteryUsageStatsAtomsProto.BatteryConsumerData.POWER_COMPONENTS);
+ proto.write(
+ BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage
+ .COMPONENT,
+ componentId);
+ proto.write(
+ BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage
+ .POWER_DECI_COULOMBS,
+ powerDeciCoulombs);
+ proto.write(
+ BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage
+ .DURATION_MILLIS,
+ durationMs);
+ proto.end(token);
+ }
+ return interestingData;
+ }
+
/**
* Builder for PowerComponents.
*/