diff options
9 files changed, 186 insertions, 26 deletions
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java index 5b6291e4523f..5abc6d4f76b1 100644 --- a/core/java/com/android/internal/os/BatterySipper.java +++ b/core/java/com/android/internal/os/BatterySipper.java @@ -73,14 +73,16 @@ public class BatterySipper implements Comparable<BatterySipper> { public double usagePowerMah; // Subsystem usage times. + public long audioTimeMs; + public long bluetoothRunningTimeMs; + public long cameraTimeMs; + public long cpuFgTimeMs; public long cpuTimeMs; + public long flashlightTimeMs; public long gpsTimeMs; - public long wifiRunningTimeMs; - public long cpuFgTimeMs; + public long videoTimeMs; public long wakeLockTimeMs; - public long cameraTimeMs; - public long flashlightTimeMs; - public long bluetoothRunningTimeMs; + public long wifiRunningTimeMs; public long mobileRxPackets; public long mobileTxPackets; @@ -102,15 +104,17 @@ public class BatterySipper implements Comparable<BatterySipper> { // Measured in mAh (milli-ampere per hour). // These are included when summed. - public double wifiPowerMah; + public double audioPowerMah; + public double bluetoothPowerMah; + public double cameraPowerMah; public double cpuPowerMah; - public double wakeLockPowerMah; - public double mobileRadioPowerMah; + public double flashlightPowerMah; public double gpsPowerMah; + public double mobileRadioPowerMah; public double sensorPowerMah; - public double cameraPowerMah; - public double flashlightPowerMah; - public double bluetoothPowerMah; + public double videoPowerMah; + public double wakeLockPowerMah; + public double wifiPowerMah; public enum DrainType { AMBIENT_DISPLAY, @@ -177,10 +181,12 @@ public class BatterySipper implements Comparable<BatterySipper> { totalPowerMah += other.totalPowerMah; usageTimeMs += other.usageTimeMs; usagePowerMah += other.usagePowerMah; + audioTimeMs += other.audioTimeMs; cpuTimeMs += other.cpuTimeMs; gpsTimeMs += other.gpsTimeMs; wifiRunningTimeMs += other.wifiRunningTimeMs; cpuFgTimeMs += other.cpuFgTimeMs; + videoTimeMs += other.videoTimeMs; wakeLockTimeMs += other.wakeLockTimeMs; cameraTimeMs += other.cameraTimeMs; flashlightTimeMs += other.flashlightTimeMs; @@ -197,6 +203,7 @@ public class BatterySipper implements Comparable<BatterySipper> { wifiTxBytes += other.wifiTxBytes; btRxBytes += other.btRxBytes; btTxBytes += other.btTxBytes; + audioPowerMah += other.audioPowerMah; wifiPowerMah += other.wifiPowerMah; gpsPowerMah += other.gpsPowerMah; cpuPowerMah += other.cpuPowerMah; @@ -207,6 +214,7 @@ public class BatterySipper implements Comparable<BatterySipper> { flashlightPowerMah += other.flashlightPowerMah; bluetoothPowerMah += other.bluetoothPowerMah; screenPowerMah += other.screenPowerMah; + videoPowerMah += other.videoPowerMah; proportionalSmearMah += other.proportionalSmearMah; totalSmearedPowerMah += other.totalSmearedPowerMah; } @@ -220,7 +228,7 @@ public class BatterySipper implements Comparable<BatterySipper> { public double sumPower() { totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah + - flashlightPowerMah + bluetoothPowerMah; + flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah; totalSmearedPowerMah = totalPowerMah + screenPowerMah + proportionalSmearMah; return totalPowerMah; diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index a76cf0a2ddc5..1e5bd1894843 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -136,6 +136,7 @@ public class BatteryStatsHelper { PowerCalculator mCameraPowerCalculator; PowerCalculator mFlashlightPowerCalculator; PowerCalculator mMemoryPowerCalculator; + PowerCalculator mMediaPowerCalculator; boolean mHasWifiPowerReporting = false; boolean mHasBluetoothPowerReporting = false; @@ -424,6 +425,11 @@ public class BatteryStatsHelper { } mFlashlightPowerCalculator.reset(); + if (mMediaPowerCalculator == null) { + mMediaPowerCalculator = new MediaPowerCalculator(mPowerProfile); + } + mMediaPowerCalculator.reset(); + mStatsType = statsType; mRawUptimeUs = rawUptimeUs; mRawRealtimeUs = rawRealtimeUs; @@ -560,6 +566,7 @@ public class BatteryStatsHelper { mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType); mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType); + mMediaPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType); final double totalPower = app.sumPower(); if (DEBUG && totalPower != 0) { diff --git a/core/java/com/android/internal/os/MediaPowerCalculator.java b/core/java/com/android/internal/os/MediaPowerCalculator.java new file mode 100644 index 000000000000..a35c1341905b --- /dev/null +++ b/core/java/com/android/internal/os/MediaPowerCalculator.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 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 android.os.BatteryStats; + +/** + * A {@link PowerCalculator} to calculate power consumed by audio and video hardware. + * + * Also see {@link PowerProfile#POWER_AUDIO} and {@link PowerProfile#POWER_VIDEO}. + */ +public class MediaPowerCalculator extends PowerCalculator { + private static final int MS_IN_HR = 1000 * 60 * 60; + private final double mAudioAveragePowerMa; + private final double mVideoAveragePowerMa; + + public MediaPowerCalculator(PowerProfile profile) { + mAudioAveragePowerMa = profile.getAveragePower(PowerProfile.POWER_AUDIO); + mVideoAveragePowerMa = profile.getAveragePower(PowerProfile.POWER_VIDEO); + } + + @Override + public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, + long rawUptimeUs, int statsType) { + // Calculate audio power usage, an estimate based on the average power routed to different + // components like speaker, bluetooth, usb-c, earphone, etc. + final BatteryStats.Timer audioTimer = u.getAudioTurnedOnTimer(); + if (audioTimer == null) { + app.audioTimeMs = 0; + app.audioPowerMah = 0; + } else { + final long totalTime = audioTimer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000; + app.audioTimeMs = totalTime; + app.audioPowerMah = (totalTime * mAudioAveragePowerMa) / MS_IN_HR; + } + + // Calculate video power usage. + final BatteryStats.Timer videoTimer = u.getVideoTurnedOnTimer(); + if (videoTimer == null) { + app.videoTimeMs = 0; + app.videoPowerMah = 0; + } else { + final long totalTime = videoTimer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000; + app.videoTimeMs = totalTime; + app.videoPowerMah = (totalTime * mVideoAveragePowerMa) / MS_IN_HR; + } + } +} diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index 747d633ea1c3..344c772554ae 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -43,12 +43,12 @@ public class PowerProfile { */ public static final String POWER_NONE = "none"; - /** + /* * POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode. * POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should * be zero on devices that can go into full CPU power collapse even when a wake * lock is held. Otherwise, this is the power consumption in addition to - * POWER_CPU_SUSPEND due to a wake lock being held but with no CPU activity. + * POWER_CPU_SUSPEND due to a wake lock being held but with no CPU activity. * POWER_CPU_ACTIVE: Power consumption when CPU is running, excluding power consumed by clusters * and cores. * @@ -84,7 +84,6 @@ public class PowerProfile { // Updated power constants. These are not estimated, they are real world // currents and voltages for the underlying bluetooth and wifi controllers. // - public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle"; public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx"; public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx"; @@ -117,6 +116,7 @@ public class PowerProfile { /** * Power consumption when Bluetooth driver is on. + * * @deprecated */ @Deprecated @@ -124,6 +124,7 @@ public class PowerProfile { /** * Power consumption when Bluetooth driver is transmitting/receiving. + * * @deprecated */ @Deprecated @@ -131,6 +132,7 @@ public class PowerProfile { /** * Power consumption when Bluetooth driver gets an AT command. + * * @deprecated */ @Deprecated @@ -171,13 +173,13 @@ public class PowerProfile { * Power consumed by the audio hardware when playing back audio content. This is in addition * to the CPU power, probably due to a DSP and / or amplifier. */ - public static final String POWER_AUDIO = "dsp.audio"; + public static final String POWER_AUDIO = "audio"; /** * Power consumed by any media hardware when playing back video content. This is in addition * to the CPU power, probably due to a DSP. */ - public static final String POWER_VIDEO = "dsp.video"; + public static final String POWER_VIDEO = "video"; /** * Average power consumption when camera flashlight is on. @@ -409,6 +411,7 @@ public class PowerProfile { /** * Returns the number of memory bandwidth buckets defined in power_profile.xml, or a * default value if the subsystem has no recorded value. + * * @return the number of memory bandwidth buckets. */ public int getNumElements(String key) { @@ -423,7 +426,8 @@ public class PowerProfile { /** * Returns the average current in mA consumed by the subsystem, or the given * default value if the subsystem has no recorded value. - * @param type the subsystem type + * + * @param type the subsystem type * @param defaultValue the value to return if the subsystem has no recorded value. * @return the average current in milliAmps. */ @@ -439,19 +443,21 @@ public class PowerProfile { /** * Returns the average current in mA consumed by the subsystem + * * @param type the subsystem type * @return the average current in milliAmps. */ public double getAveragePower(String type) { return getAveragePowerOrDefault(type, 0); } - + /** * Returns the average current in mA consumed by the subsystem for the given level. - * @param type the subsystem type + * + * @param type the subsystem type * @param level the level of power at which the subsystem is running. For instance, the - * signal strength of the cell network between 0 and 4 (if there are 4 bars max.) - * If there is no data for multiple levels, the level is ignored. + * signal strength of the cell network between 0 and 4 (if there are 4 bars max.) + * If there is no data for multiple levels, the level is ignored. * @return the average current in milliAmps. */ public double getAveragePower(String type, int level) { @@ -474,6 +480,7 @@ public class PowerProfile { /** * Returns the battery capacity, if available, in milli Amp Hours. If not available, * it returns zero. + * * @return the battery capacity in mAh */ public double getBatteryCapacity() { diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml index bd0958dcf6c1..eff7c554e5ed 100644 --- a/core/res/res/xml/power_profile.xml +++ b/core/res/res/xml/power_profile.xml @@ -36,8 +36,8 @@ <item name="wifi.on">0.1</item> <!-- ~3mA --> <item name="wifi.active">0.1</item> <!-- WIFI data transfer, ~200mA --> <item name="wifi.scan">0.1</item> <!-- WIFI network scanning, ~100mA --> - <item name="dsp.audio">0.1</item> <!-- ~10mA --> - <item name="dsp.video">0.1</item> <!-- ~50mA --> + <item name="audio">0.1</item> <!-- ~10mA --> + <item name="video">0.1</item> <!-- ~50mA --> <item name="camera.flashlight">0.1</item> <!-- Avg. power for camera flash, ~160mA --> <item name="camera.avg">0.1</item> <!-- Avg. power use of camera in standard usecases, ~550mA --> <item name="gps.on">0.1</item> <!-- ~50mA --> diff --git a/core/res/res/xml/power_profile_test.xml b/core/res/res/xml/power_profile_test.xml index eb347325a5b6..6dc5c7e16681 100644 --- a/core/res/res/xml/power_profile_test.xml +++ b/core/res/res/xml/power_profile_test.xml @@ -96,8 +96,11 @@ minute. --> <item name="camera.avg">600</item> - <!-- Additional power used when audio decoding/encoding via DSP --> - <item name="dsp.audio">100</item> + <!-- Additional power used by the audio hardware, probably due to DSP --> + <item name="audio">100.0</item> + + <!-- Additional power used by the video hardware, probably due to DSP --> + <item name="video">150.0</item> <!-- ~50mA --> <!-- Additional power used when GPS is acquiring a signal --> <item name="gps.on">10</item> 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 98b7a3fde56a..f5fe80c0f6ae 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java @@ -44,6 +44,7 @@ import org.junit.runners.Suite; KernelUidCpuClusterTimeReaderTest.class, KernelWakelockReaderTest.class, LongSamplingCounterArrayTest.class, + PowerCalculatorTest.class, PowerProfileTest.class }) public class BatteryStatsTests { diff --git a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java new file mode 100644 index 000000000000..14d62e0b2f9c --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 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 org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.os.BatteryStats; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import junit.framework.TestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class PowerCalculatorTest extends TestCase { + private static final long US_IN_HR = 1000L * 1000L * 60L * 60L; + + @Mock + private PowerProfile mPowerProfile; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + /** Test {@link MediaPowerCalculator#calculateApp} */ + @Test + public void testMediaPowerCalculator() { + when(mPowerProfile.getAveragePower(PowerProfile.POWER_AUDIO)).thenReturn(12.0); + when(mPowerProfile.getAveragePower(PowerProfile.POWER_VIDEO)).thenReturn(25.0); + + BatteryStats.Uid u = mock(BatteryStats.Uid.class); + BatteryStats.Timer audioTimer = mock(BatteryStats.Timer.class); + when(u.getAudioTurnedOnTimer()).thenReturn(audioTimer); + when(audioTimer.getTotalTimeLocked(2L * US_IN_HR, 0)).thenReturn(2L * US_IN_HR); + BatteryStats.Timer videoTimer = mock(BatteryStats.Timer.class); + when(u.getVideoTurnedOnTimer()).thenReturn(videoTimer); + when(videoTimer.getTotalTimeLocked(2L * US_IN_HR, 0)).thenReturn(1L * US_IN_HR); + + MediaPowerCalculator mediaPowerCalculator = new MediaPowerCalculator(mPowerProfile); + BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, null, 0); + + mediaPowerCalculator.calculateApp(app, u, 2L * US_IN_HR, 2L * US_IN_HR, 0); + assertEquals(49.0, app.sumPower()); + } + + +} diff --git a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java index c7de99a0ade0..2853c965e871 100644 --- a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java +++ b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java @@ -54,6 +54,8 @@ public class PowerProfileTest extends TestCase { assertEquals(60.0, mProfile.getAveragePowerForCpuCore(1, 3)); assertEquals(3000.0, mProfile.getBatteryCapacity()); assertEquals(0.5, mProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY)); + assertEquals(100.0, mProfile.getAveragePower(PowerProfile.POWER_AUDIO)); + assertEquals(150.0, mProfile.getAveragePower(PowerProfile.POWER_VIDEO)); } } |