blob: ab22e3e3f94cbabc15a7ba238970f7ff23427b5a [file] [log] [blame]
/*
* Copyright (C) 2015 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.server.power.stats;
import android.location.GnssSignalQuality;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.UidBatteryConsumer;
import android.util.SparseArray;
import com.android.internal.os.PowerProfile;
/**
* Estimates the amount of power consumed by the GNSS (e.g. GPS).
*/
public class GnssPowerCalculator extends PowerCalculator {
private final double mAveragePowerGnssOn;
private final double[] mAveragePowerPerSignalQuality;
public GnssPowerCalculator(PowerProfile profile) {
mAveragePowerGnssOn = profile.getAveragePowerOrDefault(PowerProfile.POWER_GPS_ON, -1);
mAveragePowerPerSignalQuality =
new double[GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS];
for (int i = 0; i < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; i++) {
mAveragePowerPerSignalQuality[i] = profile.getAveragePower(
PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i);
}
}
@Override
public boolean isPowerComponentSupported(@BatteryConsumer.PowerComponent int powerComponent) {
return powerComponent == BatteryConsumer.POWER_COMPONENT_GNSS;
}
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
double appsPowerMah = 0;
final double averageGnssPowerMa = getAverageGnssPower(batteryStats, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED);
final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
builder.getUidBatteryConsumerBuilders();
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
final long consumptionUC =
app.getBatteryStatsUid().getGnssEnergyConsumptionUC();
final int powerModel = getPowerModel(consumptionUC, query);
final double powerMah = calculateApp(app, app.getBatteryStatsUid(), powerModel,
rawRealtimeUs, averageGnssPowerMa, consumptionUC);
if (!app.isVirtualUid()) {
appsPowerMah += powerMah;
}
}
final long consumptionUC = batteryStats.getGnssEnergyConsumptionUC();
final int powerModel = getPowerModel(consumptionUC, query);
double powerMah;
if (powerModel == BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION) {
powerMah = uCtoMah(consumptionUC);
} else {
powerMah = appsPowerMah;
}
builder.getAggregateBatteryConsumerBuilder(
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, powerMah, powerModel);
builder.getAggregateBatteryConsumerBuilder(
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, appsPowerMah, powerModel);
}
private double calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
@BatteryConsumer.PowerModel int powerModel, long rawRealtimeUs,
double averageGnssPowerMa, long consumedEnergyUC) {
final long durationMs = computeDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
final double powerMah;
switch (powerModel) {
case BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION:
powerMah = uCtoMah(consumedEnergyUC);
break;
case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
default:
powerMah = computePower(durationMs, averageGnssPowerMa);
}
app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_GNSS, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, powerMah, powerModel);
return powerMah;
}
private long computeDuration(BatteryStats.Uid u, long rawRealtimeUs, int statsType) {
final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
final BatteryStats.Uid.Sensor sensor = sensorStats.get(BatteryStats.Uid.Sensor.GPS);
if (sensor == null) {
return 0;
}
final BatteryStats.Timer timer = sensor.getSensorTime();
return timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
}
private double computePower(long sensorTime, double averageGnssPowerMa) {
return (sensorTime * averageGnssPowerMa) / (1000 * 60 * 60);
}
private double getAverageGnssPower(BatteryStats stats, long rawRealtimeUs, int statsType) {
double averagePower = mAveragePowerGnssOn;
if (averagePower != -1) {
return averagePower;
}
averagePower = 0;
long totalTime = 0;
double totalPower = 0;
for (int i = 0; i < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; i++) {
long timePerLevel = stats.getGpsSignalQualityTime(i, rawRealtimeUs, statsType);
totalTime += timePerLevel;
totalPower += mAveragePowerPerSignalQuality[i] * timePerLevel;
}
if (totalTime != 0) {
averagePower = totalPower / totalTime;
}
return averagePower;
}
}