diff options
| author | 2023-01-13 10:19:48 +0000 | |
|---|---|---|
| committer | 2023-01-13 10:19:48 +0000 | |
| commit | ddefe02fb0700601405a844e6488f754e6919a2a (patch) | |
| tree | e645aa825441aa42f67887e9cb63c7a1708f3636 | |
| parent | 41e9b2fb88ce616519ab661e989b25c76e12bdd4 (diff) | |
| parent | 853fd9ba9230d19de4df1a78bc0d011b8f1032e7 (diff) | |
Merge changes from topic "bscamera3"
* changes:
Add per-UID measured camera stats
Add measured camera stats to BatteryUsageStats
Collect camera power consumption into BatteryStats
10 files changed, 277 insertions, 26 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 34aa7efb2d3b..547d406751f9 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -1142,6 +1142,16 @@ public abstract class BatteryStats { @BatteryConsumer.ProcessState int processState); + + /** + * Returns the battery consumption (in microcoulombs) of UID's camera usage, derived from + * on-device power measurement data. + * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. + * + * {@hide} + */ + public abstract long getCameraEnergyConsumptionUC(); + /** * Returns the battery consumption (in microcoulombs) used by this uid for each * {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer @@ -2921,6 +2931,15 @@ public abstract class BatteryStats { public abstract long getWifiEnergyConsumptionUC(); /** + * Returns the battery consumption (in microcoulombs) of camera, derived from on + * device power measurement data. + * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. + * + * {@hide} + */ + public abstract long getCameraEnergyConsumptionUC(); + + /** * Returns the battery consumption (in microcoulombs) that each * {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}) consumed. diff --git a/core/java/com/android/internal/power/EnergyConsumerStats.java b/core/java/com/android/internal/power/EnergyConsumerStats.java index 325df576f10a..8cf17cdaab83 100644 --- a/core/java/com/android/internal/power/EnergyConsumerStats.java +++ b/core/java/com/android/internal/power/EnergyConsumerStats.java @@ -58,7 +58,8 @@ public class EnergyConsumerStats { public static final int POWER_BUCKET_BLUETOOTH = 5; public static final int POWER_BUCKET_GNSS = 6; public static final int POWER_BUCKET_MOBILE_RADIO = 7; - public static final int NUMBER_STANDARD_POWER_BUCKETS = 8; // Buckets above this are custom. + public static final int POWER_BUCKET_CAMERA = 8; + public static final int NUMBER_STANDARD_POWER_BUCKETS = 9; // Buckets above this are custom. @IntDef(prefix = {"POWER_BUCKET_"}, value = { POWER_BUCKET_UNKNOWN, @@ -70,6 +71,7 @@ public class EnergyConsumerStats { POWER_BUCKET_BLUETOOTH, POWER_BUCKET_GNSS, POWER_BUCKET_MOBILE_RADIO, + POWER_BUCKET_CAMERA, }) @Retention(RetentionPolicy.SOURCE) public @interface StandardPowerBucket { diff --git a/services/core/Android.bp b/services/core/Android.bp index 17b6f5da0fb6..ec09acd39d44 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -170,7 +170,7 @@ java_library_static { "android.hardware.ir-V1-java", "android.hardware.rebootescrow-V1-java", "android.hardware.soundtrigger-V2.3-java", - "android.hardware.power.stats-V1-java", + "android.hardware.power.stats-V2-java", "android.hardware.power-V4-java", "android.hidl.manager-V1.2-java", "icu4j_calendar_astronomer", diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java index 60dbbddf8b2c..3fcb08a58000 100644 --- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java @@ -710,6 +710,11 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat if (gnssChargeUC != EnergyConsumerSnapshot.UNAVAILABLE) { mStats.updateGnssEnergyConsumerStatsLocked(gnssChargeUC, elapsedRealtime); } + + final long cameraChargeUC = energyConsumerDeltas.cameraChargeUC; + if (cameraChargeUC != EnergyConsumerSnapshot.UNAVAILABLE) { + mStats.updateCameraEnergyConsumerStatsLocked(cameraChargeUC, elapsedRealtime); + } } // Inform mStats about each applicable custom energy bucket. if (energyConsumerDeltas != null @@ -904,6 +909,9 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat case EnergyConsumerType.WIFI: buckets[EnergyConsumerStats.POWER_BUCKET_WIFI] = true; break; + case EnergyConsumerType.CAMERA: + buckets[EnergyConsumerStats.POWER_BUCKET_CAMERA] = true; + break; } } return buckets; @@ -955,6 +963,9 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat if ((flags & UPDATE_WIFI) != 0) { addEnergyConsumerIdLocked(energyConsumerIds, EnergyConsumerType.WIFI); } + if ((flags & UPDATE_CAMERA) != 0) { + addEnergyConsumerIdLocked(energyConsumerIds, EnergyConsumerType.CAMERA); + } if (energyConsumerIds.size() == 0) { return null; diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java index c559436b4a8d..d622fd717611 100644 --- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java @@ -178,7 +178,7 @@ public class BatteryStatsImpl extends BatteryStats { // TODO: remove "tcp" from network methods, since we measure total stats. // Current on-disk Parcel version. Must be updated when the format of the parcelable changes - public static final int VERSION = 210; + public static final int VERSION = 211; // The maximum number of names wakelocks we will keep track of // per uid; once the limit is reached, we batch the remaining wakelocks @@ -649,10 +649,12 @@ public class BatteryStatsImpl extends BatteryStats { int UPDATE_BT = 0x08; int UPDATE_RPM = 0x10; int UPDATE_DISPLAY = 0x20; - int RESET = 0x40; + int UPDATE_CAMERA = 0x40; + int RESET = 0x80; int UPDATE_ALL = - UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM | UPDATE_DISPLAY; + UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM | UPDATE_DISPLAY + | UPDATE_CAMERA; int UPDATE_ON_PROC_STATE_CHANGE = UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT; @@ -665,6 +667,7 @@ public class BatteryStatsImpl extends BatteryStats { UPDATE_BT, UPDATE_RPM, UPDATE_DISPLAY, + UPDATE_CAMERA, UPDATE_ALL, }) @Retention(RetentionPolicy.SOURCE) @@ -6244,6 +6247,8 @@ public class BatteryStatsImpl extends BatteryStats { } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteCameraTurnedOnLocked(elapsedRealtimeMs); + + scheduleSyncExternalStatsLocked("camera-on", ExternalStatsSync.UPDATE_CAMERA); } @GuardedBy("this") @@ -6259,6 +6264,8 @@ public class BatteryStatsImpl extends BatteryStats { } getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) .noteCameraTurnedOffLocked(elapsedRealtimeMs); + + scheduleSyncExternalStatsLocked("camera-off", ExternalStatsSync.UPDATE_CAMERA); } @GuardedBy("this") @@ -6273,6 +6280,8 @@ public class BatteryStatsImpl extends BatteryStats { uid.noteResetCameraLocked(elapsedRealtimeMs); } } + + scheduleSyncExternalStatsLocked("camera-reset", ExternalStatsSync.UPDATE_CAMERA); } @GuardedBy("this") @@ -7414,6 +7423,12 @@ public class BatteryStatsImpl extends BatteryStats { return getPowerBucketConsumptionUC(EnergyConsumerStats.POWER_BUCKET_WIFI); } + @GuardedBy("this") + @Override + public long getCameraEnergyConsumptionUC() { + return getPowerBucketConsumptionUC(EnergyConsumerStats.POWER_BUCKET_CAMERA); + } + /** * Returns the consumption (in microcoulombs) that the given standard power bucket consumed. * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable @@ -8427,6 +8442,12 @@ public class BatteryStatsImpl extends BatteryStats { processState); } + @GuardedBy("mBsi") + @Override + public long getCameraEnergyConsumptionUC() { + return getEnergyConsumptionUC(EnergyConsumerStats.POWER_BUCKET_CAMERA); + } + /** * Gets the minimum of the uid's foreground activity time and its PROCESS_STATE_TOP time * since last marked. Also sets the mark time for both these timers. @@ -8477,6 +8498,20 @@ public class BatteryStatsImpl extends BatteryStats { return gnssTimeUs; } + /** + * Gets the uid's time spent using the camera since last marked. Also sets the mark time for + * the camera timer. + */ + private long markCameraTimeUs(long elapsedRealtimeMs) { + final StopwatchTimer timer = mCameraTurnedOnTimer; + if (timer == null) { + return 0; + } + final long cameraTimeUs = timer.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000); + timer.setMark(elapsedRealtimeMs); + return cameraTimeUs; + } + public StopwatchTimer createAudioTurnedOnTimerLocked() { if (mAudioTurnedOnTimer == null) { mAudioTurnedOnTimer = new StopwatchTimer(mBsi.mClock, Uid.this, AUDIO_TURNED_ON, @@ -12902,6 +12937,53 @@ public class BatteryStatsImpl extends BatteryStats { } /** + * Accumulate camera charge consumption and distribute it to the correct state and the apps. + * + * @param chargeUC amount of charge (microcoulombs) used by the camera since this was last + * called. + */ + @GuardedBy("this") + public void updateCameraEnergyConsumerStatsLocked(long chargeUC, long elapsedRealtimeMs) { + if (DEBUG_ENERGY) Slog.d(TAG, "Updating camera stats: " + chargeUC); + if (mGlobalEnergyConsumerStats == null) { + return; + } + + if (!mOnBatteryInternal || chargeUC <= 0) { + // There's nothing further to update. + return; + } + + if (mIgnoreNextExternalStats) { + // Although under ordinary resets we won't get here, and typically a new sync will + // happen right after the reset, strictly speaking we need to set all mark times to now. + final int uidStatsSize = mUidStats.size(); + for (int i = 0; i < uidStatsSize; i++) { + final Uid uid = mUidStats.valueAt(i); + uid.markCameraTimeUs(elapsedRealtimeMs); + } + return; + } + + mGlobalEnergyConsumerStats.updateStandardBucket( + EnergyConsumerStats.POWER_BUCKET_CAMERA, chargeUC); + + // Collect the per uid time since mark so that we can normalize power. + final SparseDoubleArray cameraTimeUsArray = new SparseDoubleArray(); + + // Note: Iterating over all UIDs may be suboptimal. + final int uidStatsSize = mUidStats.size(); + for (int i = 0; i < uidStatsSize; i++) { + final Uid uid = mUidStats.valueAt(i); + final long cameraTimeUs = uid.markCameraTimeUs(elapsedRealtimeMs); + if (cameraTimeUs == 0) continue; + cameraTimeUsArray.put(uid.getUid(), (double) cameraTimeUs); + } + distributeEnergyToUidsLocked(EnergyConsumerStats.POWER_BUCKET_CAMERA, chargeUC, + cameraTimeUsArray, 0, elapsedRealtimeMs); + } + + /** * Accumulate Custom power bucket charge, globally and for each app. * * @param totalChargeUC charge (microcoulombs) used for this bucket since this was last called. diff --git a/services/core/java/com/android/server/power/stats/CameraPowerCalculator.java b/services/core/java/com/android/server/power/stats/CameraPowerCalculator.java index 16892034b1be..89991bf8e4e1 100644 --- a/services/core/java/com/android/server/power/stats/CameraPowerCalculator.java +++ b/services/core/java/com/android/server/power/stats/CameraPowerCalculator.java @@ -48,27 +48,44 @@ public class CameraPowerCalculator extends PowerCalculator { long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query); - final long durationMs = batteryStats.getCameraOnTime(rawRealtimeUs, - BatteryStats.STATS_SINCE_CHARGED) / 1000; - final double powerMah = mPowerEstimator.calculatePower(durationMs); + long consumptionUc = batteryStats.getCameraEnergyConsumptionUC(); + int powerModel = getPowerModel(consumptionUc, query); + long durationMs = + batteryStats.getCameraOnTime( + rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED) / 1000; + double powerMah; + if (powerModel == BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION) { + powerMah = uCtoMah(consumptionUc); + } else { + powerMah = mPowerEstimator.calculatePower(durationMs); + } + builder.getAggregateBatteryConsumerBuilder( - BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs) - .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah); + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah, powerModel); builder.getAggregateBatteryConsumerBuilder( - BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs) - .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah); + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah, powerModel); } @Override protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { - final long durationMs = + long consumptionUc = app.getBatteryStatsUid().getCameraEnergyConsumptionUC(); + int powerModel = getPowerModel(consumptionUc, query); + long durationMs = mPowerEstimator.calculateDuration(u.getCameraTurnedOnTimer(), rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); - final double powerMah = mPowerEstimator.calculatePower(durationMs); + double powerMah; + if (powerModel == BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION) { + powerMah = uCtoMah(consumptionUc); + } else { + powerMah = mPowerEstimator.calculatePower(durationMs); + } + app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA, durationMs) - .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah); + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah, powerModel); } } diff --git a/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java b/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java index 18595cad7741..939a08ba0b6a 100644 --- a/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java +++ b/services/core/java/com/android/server/power/stats/EnergyConsumerSnapshot.java @@ -123,6 +123,9 @@ public class EnergyConsumerSnapshot { /** The chargeUC for {@link EnergyConsumerType#WIFI}. */ public long wifiChargeUC = UNAVAILABLE; + /** The chargeUC for {@link EnergyConsumerType#CAMERA}. */ + public long cameraChargeUC = UNAVAILABLE; + /** Map of {@link EnergyConsumerType#OTHER} ordinals to their total chargeUC. */ public @Nullable long[] otherTotalChargeUC = null; @@ -256,6 +259,10 @@ public class EnergyConsumerSnapshot { output.wifiChargeUC = deltaChargeUC; break; + case EnergyConsumerType.CAMERA: + output.cameraChargeUC = deltaChargeUC; + break; + case EnergyConsumerType.OTHER: if (output.otherTotalChargeUC == null) { output.otherTotalChargeUC = new long[mNumOtherOrdinals]; @@ -458,6 +465,9 @@ public class EnergyConsumerSnapshot { case EnergyConsumerType.WIFI: chargeUC[i] = delta.wifiChargeUC; break; + case EnergyConsumerType.CAMERA: + chargeUC[i] = delta.cameraChargeUC; + break; case EnergyConsumerType.OTHER: if (delta.otherTotalChargeUC != null) { chargeUC[i] = delta.otherTotalChargeUC[energyConsumer.ordinal]; diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java index 2ebe21505bd9..cff4cc72de52 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java @@ -18,6 +18,7 @@ package com.android.server.power.stats; import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL; import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_BT; +import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_CAMERA; import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU; import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_DISPLAY; import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO; @@ -104,6 +105,11 @@ public class BatteryExternalStatsWorkerTest { tempAllIds.add(gnssId); mPowerStatsInternal.incrementEnergyConsumption(gnssId, 787878); + final int cameraId = + mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.CAMERA, 0, "camera"); + tempAllIds.add(cameraId); + mPowerStatsInternal.incrementEnergyConsumption(cameraId, 901234); + final int mobileRadioId = mPowerStatsInternal.addEnergyConsumer( EnergyConsumerType.MOBILE_RADIO, 0, "mobile_radio"); tempAllIds.add(mobileRadioId); @@ -171,6 +177,12 @@ public class BatteryExternalStatsWorkerTest { Arrays.sort(receivedCpuIds); assertArrayEquals(cpuClusterIds, receivedCpuIds); + final EnergyConsumerResult[] cameraResults = + mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_CAMERA).getNow(null); + // Results should only have the camera energy consumer + assertEquals(1, cameraResults.length); + assertEquals(cameraId, cameraResults[0].id); + final EnergyConsumerResult[] allResults = mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_ALL).getNow(null); // All energy consumer results should be available diff --git a/services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java b/services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java index e4ab21b0e938..5fce32f0598a 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java @@ -36,41 +36,113 @@ import org.junit.runner.RunWith; public class CameraPowerCalculatorTest { private static final double PRECISION = 0.00001; - private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; + private static final int APP1_UID = Process.FIRST_APPLICATION_UID + 42; + private static final int APP2_UID = Process.FIRST_APPLICATION_UID + 43; @Rule public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() - .setAveragePower(PowerProfile.POWER_CAMERA, 360.0); + .setAveragePower(PowerProfile.POWER_CAMERA, 360.0) + .initMeasuredEnergyStatsLocked(); @Test public void testTimerBasedModel() { BatteryStatsImpl stats = mStatsRule.getBatteryStats(); - stats.noteCameraOnLocked(APP_UID, 1000, 1000); - stats.noteCameraOffLocked(APP_UID, 2000, 2000); + synchronized (stats) { // To keep the GuardedBy check happy + stats.noteCameraOnLocked(APP1_UID, 1000, 1000); + stats.noteCameraOffLocked(APP1_UID, 2000, 2000); + stats.noteCameraOnLocked(APP2_UID, 3000, 3000); + stats.noteCameraOffLocked(APP2_UID, 5000, 5000); + } CameraPowerCalculator calculator = new CameraPowerCalculator(mStatsRule.getPowerProfile()); - mStatsRule.apply(calculator); + mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); - UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); - assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) + UidBatteryConsumer app1Consumer = mStatsRule.getUidBatteryConsumer(APP1_UID); + assertThat(app1Consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) .isEqualTo(1000); - assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) + assertThat(app1Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) .isWithin(PRECISION).of(0.1); + assertThat(app1Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + + UidBatteryConsumer app2Consumer = mStatsRule.getUidBatteryConsumer(APP2_UID); + assertThat(app2Consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(2000); + assertThat(app2Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isWithin(PRECISION).of(0.2); + assertThat(app2Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); assertThat(deviceBatteryConsumer .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) - .isEqualTo(1000); + .isEqualTo(3000); assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) - .isWithin(PRECISION).of(0.1); + .isWithin(PRECISION).of(0.3); + assertThat(deviceBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); final BatteryConsumer appsBatteryConsumer = mStatsRule.getAppsBatteryConsumer(); assertThat(appsBatteryConsumer .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(3000); + assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isWithin(PRECISION).of(0.3); + assertThat(appsBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + } + + @Test + public void testEnergyConsumptionBasedModel() { + BatteryStatsImpl stats = mStatsRule.getBatteryStats(); + synchronized (stats) { // To keep the GuardedBy check happy + stats.noteCameraOnLocked(APP1_UID, 1000, 1000); + stats.noteCameraOffLocked(APP1_UID, 2000, 2000); + stats.updateCameraEnergyConsumerStatsLocked(720_000, 2100); // 0.72C == 0.2mAh + stats.noteCameraOnLocked(APP2_UID, 3000, 3000); + stats.noteCameraOffLocked(APP2_UID, 5000, 5000); + stats.updateCameraEnergyConsumerStatsLocked(1_080_000, 5100); // 0.3mAh + } + + CameraPowerCalculator calculator = + new CameraPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + UidBatteryConsumer app1Consumer = mStatsRule.getUidBatteryConsumer(APP1_UID); + assertThat(app1Consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) .isEqualTo(1000); + assertThat(app1Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isWithin(PRECISION).of(0.2); + assertThat(app1Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION); + + UidBatteryConsumer app2Consumer = mStatsRule.getUidBatteryConsumer(APP2_UID); + assertThat(app2Consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(2000); + assertThat(app2Consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isWithin(PRECISION).of(0.3); + assertThat(app2Consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION); + + final BatteryConsumer deviceBatteryConsumer = mStatsRule.getDeviceBatteryConsumer(); + assertThat(deviceBatteryConsumer + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(3000); + assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isWithin(PRECISION).of(0.5); + assertThat(deviceBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION); + + final BatteryConsumer appsBatteryConsumer = mStatsRule.getAppsBatteryConsumer(); + assertThat(appsBatteryConsumer + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(3000); assertThat(appsBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) - .isWithin(PRECISION).of(0.1); + .isWithin(PRECISION).of(0.5); + assertThat(appsBatteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION); } } diff --git a/services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java b/services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java index 558f39629d81..28f4799656b7 100644 --- a/services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java +++ b/services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java @@ -248,6 +248,32 @@ public final class EnergyConsumerSnapshotTest { assertThat(details.toString()).isEqualTo("DISPLAY=2667 HPU=3200000 GPU=0 IPU &_=0"); } + @Test + public void testUpdateAndGetDelta_updatesCameraCharge() { + EnergyConsumer cameraConsumer = + createEnergyConsumer(7, 0, EnergyConsumerType.CAMERA, "CAMERA"); + final EnergyConsumerSnapshot snapshot = + new EnergyConsumerSnapshot(createIdToConsumerMap(cameraConsumer)); + + // An initial result with only one energy consumer + EnergyConsumerResult[] result0 = new EnergyConsumerResult[]{ + createEnergyConsumerResult(cameraConsumer.id, 60_000, null, null), + }; + snapshot.updateAndGetDelta(result0, VOLTAGE_1); + + // A subsequent result + EnergyConsumerResult[] result1 = new EnergyConsumerResult[]{ + createEnergyConsumerResult(cameraConsumer.id, 90_000, null, null), + }; + EnergyConsumerDeltaData delta = snapshot.updateAndGetDelta(result1, VOLTAGE_1); + + // Verify that the delta between the two results is reported. + BatteryStats.EnergyConsumerDetails details = snapshot.getEnergyConsumerDetails(delta); + assertThat(details.consumers).hasLength(1); + long expectedDeltaUC = calculateChargeConsumedUC(60_000, VOLTAGE_1, 90_000, VOLTAGE_1); + assertThat(details.chargeUC[0]).isEqualTo(expectedDeltaUC); + } + private static EnergyConsumer createEnergyConsumer(int id, int ord, byte type, String name) { final EnergyConsumer ec = new EnergyConsumer(); ec.id = id; |