summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dmitri Plotnikov <dplotnikov@google.com> 2021-02-14 05:08:35 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-02-14 05:08:35 +0000
commitca9dfbe54ebf02d9596d8aa696a2e14e5d97c9ec (patch)
tree8cc2c88780e060328635442179cc730fe8c1a0fd
parentd77bb6a44b00661359f1746a2f6878483e5e64fb (diff)
parent248ade5460b0a935e5055ad6b8bbe5cdcfc8d3aa (diff)
Merge "Convert WakelockPowerCalculator to work with BatteryUsageStats" into sc-dev
-rw-r--r--core/java/android/os/BatteryConsumer.java4
-rw-r--r--core/java/com/android/internal/os/WakelockPowerCalculator.java120
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java1
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java76
5 files changed, 175 insertions, 33 deletions
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index ce1a16da9e14..bf229e0b24df 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -47,6 +47,7 @@ public abstract class BatteryConsumer {
POWER_COMPONENT_SYSTEM_SERVICES,
POWER_COMPONENT_SENSORS,
POWER_COMPONENT_GNSS,
+ POWER_COMPONENT_WAKELOCK,
POWER_COMPONENT_SCREEN,
POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
})
@@ -65,6 +66,7 @@ public abstract class BatteryConsumer {
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_WAKELOCK = 12;
public static final int POWER_COMPONENT_SCREEN = 13;
// Power that is re-attributed to other battery consumers. For example, for System Server
// this represents the power attributed to apps requesting system services.
@@ -92,6 +94,7 @@ public abstract class BatteryConsumer {
TIME_COMPONENT_MOBILE_RADIO,
TIME_COMPONENT_SENSORS,
TIME_COMPONENT_GNSS,
+ TIME_COMPONENT_WAKELOCK,
TIME_COMPONENT_SCREEN,
})
@Retention(RetentionPolicy.SOURCE)
@@ -109,6 +112,7 @@ public abstract class BatteryConsumer {
public static final int TIME_COMPONENT_MOBILE_RADIO = 8;
public static final int TIME_COMPONENT_SENSORS = 9;
public static final int TIME_COMPONENT_GNSS = 10;
+ public static final int TIME_COMPONENT_WAKELOCK = 12;
public static final int TIME_COMPONENT_SCREEN = 13;
public static final int TIME_COMPONENT_COUNT = 14;
diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java
index 3f68597dc1cc..0f4767b859a3 100644
--- a/core/java/com/android/internal/os/WakelockPowerCalculator.java
+++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java
@@ -15,7 +15,12 @@
*/
package com.android.internal.os;
+import android.os.BatteryConsumer;
import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
@@ -26,39 +31,93 @@ import java.util.List;
public class WakelockPowerCalculator extends PowerCalculator {
private static final String TAG = "WakelockPowerCalculator";
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
- private final double mPowerWakelock;
- private long mTotalAppWakelockTimeMs = 0;
+ private final UsageBasedPowerEstimator mPowerEstimator;
+
+ private static class PowerAndDuration {
+ public long durationMs;
+ public double powerMah;
+ }
public WakelockPowerCalculator(PowerProfile profile) {
- mPowerWakelock = profile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
+ mPowerEstimator = new UsageBasedPowerEstimator(
+ profile.getAveragePower(PowerProfile.POWER_CPU_IDLE));
}
@Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
+ public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+ final PowerAndDuration result = new PowerAndDuration();
+ UidBatteryConsumer.Builder osBatteryConsumer = null;
+ double osPowerMah = 0;
+ long osDurationMs = 0;
+ long totalAppDurationMs = 0;
+ final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
+ builder.getUidBatteryConsumerBuilders();
+ for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
+ final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+ calculateApp(result, app.getBatteryStatsUid(), rawRealtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED);
+ app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK, result.durationMs)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);
+ totalAppDurationMs += result.durationMs;
+
+ if (app.getUid() == Process.ROOT_UID) {
+ osBatteryConsumer = app;
+ osDurationMs = result.durationMs;
+ osPowerMah = result.powerMah;
+ }
+ }
// The device has probably been awake for longer than the screen on
// time and application wake lock time would account for. Assign
// this remainder to the OS, if possible.
+ if (osBatteryConsumer != null) {
+ calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs,
+ BatteryStats.STATS_SINCE_CHARGED, osPowerMah, osDurationMs, totalAppDurationMs);
+ osBatteryConsumer.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK,
+ result.durationMs)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);
+ }
+ }
+
+ @Override
+ public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
+ long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
+ final PowerAndDuration result = new PowerAndDuration();
BatterySipper osSipper = null;
+ double osPowerMah = 0;
+ long osDurationMs = 0;
+ long totalAppDurationMs = 0;
for (int i = sippers.size() - 1; i >= 0; i--) {
- BatterySipper app = sippers.get(i);
- if (app.getUid() == 0) {
- osSipper = app;
- break;
+ final BatterySipper app = sippers.get(i);
+ if (app.drainType == BatterySipper.DrainType.APP) {
+ calculateApp(result, app.uidObj, rawRealtimeUs, statsType);
+ app.wakeLockTimeMs = result.durationMs;
+ app.wakeLockPowerMah = result.powerMah;
+ totalAppDurationMs += result.durationMs;
+
+ if (app.getUid() == Process.ROOT_UID) {
+ osSipper = app;
+ osPowerMah = result.powerMah;
+ osDurationMs = result.durationMs;
+ }
}
}
+ // The device has probably been awake for longer than the screen on
+ // time and application wake lock time would account for. Assign
+ // this remainder to the OS, if possible.
if (osSipper != null) {
- calculateRemaining(osSipper, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
+ calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs, statsType,
+ osPowerMah, osDurationMs, totalAppDurationMs);
+ osSipper.wakeLockTimeMs = result.durationMs;
+ osSipper.wakeLockPowerMah = result.powerMah;
osSipper.sumPower();
}
}
- @Override
- protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
+ private void calculateApp(PowerAndDuration result, BatteryStats.Uid u, long rawRealtimeUs,
+ int statsType) {
long wakeLockTimeUs = 0;
final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
u.getWakelockStats();
@@ -73,34 +132,29 @@ public class WakelockPowerCalculator extends PowerCalculator {
wakeLockTimeUs += timer.getTotalTimeLocked(rawRealtimeUs, statsType);
}
}
- app.wakeLockTimeMs = wakeLockTimeUs / 1000; // convert to millis
- mTotalAppWakelockTimeMs += app.wakeLockTimeMs;
+ result.durationMs = wakeLockTimeUs / 1000; // convert to millis
// Add cost of holding a wake lock.
- app.wakeLockPowerMah = (app.wakeLockTimeMs * mPowerWakelock) / (1000 * 60 * 60);
- if (DEBUG && app.wakeLockPowerMah != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": wake " + app.wakeLockTimeMs
- + " power=" + formatCharge(app.wakeLockPowerMah));
+ result.powerMah = mPowerEstimator.calculatePower(result.durationMs);
+ if (DEBUG && result.powerMah != 0) {
+ Log.d(TAG, "UID " + u.getUid() + ": wake " + result.durationMs
+ + " power=" + formatCharge(result.powerMah));
}
}
- private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- long wakeTimeMillis = stats.getBatteryUptime(rawUptimeUs) / 1000;
- wakeTimeMillis -= mTotalAppWakelockTimeMs
- + (stats.getScreenOnTime(rawRealtimeUs, statsType) / 1000);
+ private void calculateRemaining(PowerAndDuration result, BatteryStats stats, long rawRealtimeUs,
+ long rawUptimeUs, int statsType, double osPowerMah, long osDurationMs,
+ long totalAppDurationMs) {
+ final long wakeTimeMillis = stats.getBatteryUptime(rawUptimeUs) / 1000
+ - stats.getScreenOnTime(rawRealtimeUs, statsType) / 1000
+ - totalAppDurationMs;
if (wakeTimeMillis > 0) {
- final double power = (wakeTimeMillis * mPowerWakelock) / (1000 * 60 * 60);
+ final double power = mPowerEstimator.calculatePower(wakeTimeMillis);
if (DEBUG) {
Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power " + formatCharge(power));
}
- app.wakeLockTimeMs += wakeTimeMillis;
- app.wakeLockPowerMah += power;
+ result.durationMs = osDurationMs + wakeTimeMillis;
+ result.powerMah = osPowerMah + power;
}
}
-
- @Override
- public void reset() {
- mTotalAppWakelockTimeMs = 0;
- }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 0fac4f79686a..2e6e0de8d0c2 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -68,6 +68,7 @@ import org.junit.runners.Suite;
SystemServicePowerCalculatorTest.class,
UserPowerCalculatorTest.class,
VideoPowerCalculatorTest.class,
+ WakelockPowerCalculatorTest.class,
com.android.internal.power.MeasuredEnergyStatsTest.class
})
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
index 0ddc4c0035ce..5edd58fb3eb9 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -49,6 +49,7 @@ public class BatteryUsageStatsRule implements TestRule {
};
private BatteryUsageStats mBatteryUsageStats;
+ private boolean mScreenOn;
public BatteryUsageStatsRule() {
Context context = InstrumentationRegistry.getContext();
@@ -97,6 +98,11 @@ public class BatteryUsageStatsRule implements TestRule {
return this;
}
+ public BatteryUsageStatsRule startWithScreenOn(boolean screenOn) {
+ mScreenOn = screenOn;
+ return this;
+ }
+
public void setNetworkStats(NetworkStats networkStats) {
mBatteryStats.setNetworkStats(networkStats);
}
@@ -115,6 +121,7 @@ public class BatteryUsageStatsRule implements TestRule {
private void noteOnBattery() {
mBatteryStats.setOnBatteryInternal(true);
mBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
+ mBatteryStats.getOnBatteryScreenOffTimeBase().setRunning(!mScreenOn, 0, 0);
}
public PowerProfile getPowerProfile() {
diff --git a/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java
new file mode 100644
index 000000000000..4f71b438c6fa
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 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 com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
+import android.os.WorkSource;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WakelockPowerCalculatorTest {
+ private static final double PRECISION = 0.00001;
+
+ private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+ private static final int APP_PID = 3145;
+
+ @Rule
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+ .setAveragePower(PowerProfile.POWER_CPU_IDLE, 360.0);
+
+ @Test
+ public void testTimerBasedModel() {
+ mStatsRule.getUidStats(Process.ROOT_UID);
+
+ BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+
+ batteryStats.noteStartWakeFromSourceLocked(new WorkSource(APP_UID), APP_PID, "awake", "",
+ BatteryStats.WAKE_TYPE_PARTIAL, true, 1000, 1000);
+ batteryStats.noteStopWakeFromSourceLocked(new WorkSource(APP_UID), APP_PID, "awake", "",
+ BatteryStats.WAKE_TYPE_PARTIAL, 2000, 2000);
+
+ mStatsRule.setTime(10_000_000, 6_000_000);
+
+ WakelockPowerCalculator calculator =
+ new WakelockPowerCalculator(mStatsRule.getPowerProfile());
+
+ mStatsRule.apply(calculator);
+
+ UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK))
+ .isEqualTo(1000);
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK))
+ .isWithin(PRECISION).of(0.1);
+
+ UidBatteryConsumer osConsumer = mStatsRule.getUidBatteryConsumer(Process.ROOT_UID);
+ assertThat(osConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK))
+ .isEqualTo(5000);
+ assertThat(osConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK))
+ .isWithin(PRECISION).of(0.5);
+ }
+}