Merge changes from topic "bscamera3"

* changes:
  Add per-UID measured camera stats
  Add measured camera stats to BatteryUsageStats
  Collect camera power consumption into BatteryStats
This commit is contained in:
Milo Sredkov
2023-01-13 10:19:48 +00:00
committed by Android (Google) Code Review
10 changed files with 278 additions and 27 deletions

View File

@@ -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
@@ -2920,6 +2930,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

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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;

View File

@@ -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,
@@ -12901,6 +12936,53 @@ public class BatteryStatsImpl extends BatteryStats {
gnssTimeUsArray, 0, elapsedRealtimeMs);
}
/**
* 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.
*

View File

@@ -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);
}
}

View File

@@ -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];

View File

@@ -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

View File

@@ -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(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, 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.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(3000);
assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
.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 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))
.isWithin(PRECISION).of(0.1);
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(1000);
.isEqualTo(3000);
assertThat(deviceBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
.isWithin(PRECISION).of(0.1);
.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(1000);
.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);
}
}

View File

@@ -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;