1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.internal.os; 17 18 import android.annotation.NonNull; 19 import android.os.BatteryConsumer; 20 import android.os.BatteryStats; 21 import android.os.BatteryUsageStats; 22 import android.os.BatteryUsageStatsQuery; 23 import android.os.UidBatteryConsumer; 24 import android.os.UserHandle; 25 import android.util.SparseArray; 26 27 import java.io.PrintWriter; 28 import java.util.List; 29 import java.util.Locale; 30 31 /** 32 * Calculates power use of a device subsystem for an app. 33 */ 34 public abstract class PowerCalculator { 35 36 protected static final double MILLIAMPHOUR_PER_MICROCOULOMB = 1.0 / 1000.0 / 60.0 / 60.0; 37 38 /** 39 * Attributes the total amount of power used by this subsystem to various consumers such 40 * as apps. 41 * 42 * @param sippers A list of battery sippers that contains battery attribution data. 43 * The calculator may modify the list. 44 * @param batteryStats The recorded battery stats. 45 * @param rawRealtimeUs The raw system realtime in microseconds. 46 * @param rawUptimeUs The raw system uptime in microseconds. 47 * @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this 48 * can only be {@link BatteryStats#STATS_SINCE_CHARGED}, since 49 * {@link BatteryStats#STATS_CURRENT} and 50 * {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated. 51 * @param asUsers An array of users for which the attribution is requested. It may 52 * contain {@link UserHandle#USER_ALL} to indicate that the attribution 53 * should be performed for all users. 54 */ calculate(List<BatterySipper> sippers, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers)55 public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, 56 long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) { 57 for (int i = sippers.size() - 1; i >= 0; i--) { 58 final BatterySipper app = sippers.get(i); 59 if (app.drainType == BatterySipper.DrainType.APP) { 60 calculateApp(app, app.uidObj, rawRealtimeUs, rawUptimeUs, statsType); 61 } 62 } 63 } 64 65 /** 66 * Attributes the total amount of power used by this subsystem to various consumers such 67 * as apps. 68 * 69 * @param builder {@link BatteryUsageStats.Builder that contains a list of 70 * per-UID battery consumer builders for attribution data. 71 * The calculator may modify the builder and its constituent parts. 72 * @param batteryStats The recorded battery stats. 73 * @param rawRealtimeUs The raw system realtime in microseconds. 74 * @param rawUptimeUs The raw system uptime in microseconds. 75 * @param query The query parameters for the calculator. 76 */ calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query)77 public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, 78 long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { 79 final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders = 80 builder.getUidBatteryConsumerBuilders(); 81 for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { 82 final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); 83 calculateApp(app, app.getBatteryStatsUid(), rawRealtimeUs, rawUptimeUs, query); 84 } 85 } 86 87 /** 88 * Calculate the amount of power an app used for this subsystem. 89 * @param app The BatterySipper that represents the power use of an app. 90 * @param u The recorded stats for the app. 91 * @param rawRealtimeUs The raw system realtime in microseconds. 92 * @param rawUptimeUs The raw system uptime in microseconds. 93 * @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this can 94 * only be {@link BatteryStats#STATS_SINCE_CHARGED}, since 95 * {@link BatteryStats#STATS_CURRENT} and 96 * {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated. 97 */ calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, int statsType)98 protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, 99 long rawUptimeUs, int statsType) { 100 } 101 102 /** 103 * Calculate the amount of power an app used for this subsystem. 104 * @param app The UidBatteryConsumer.Builder that represents the power use of an app. 105 * @param u The recorded stats for the app. 106 * @param rawRealtimeUs The raw system realtime in microseconds. 107 * @param rawUptimeUs The raw system uptime in microseconds. 108 * @param query Power calculation parameters. 109 */ calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query)110 protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, 111 long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { 112 } 113 114 /** 115 * Reset any state maintained in this calculator. 116 */ reset()117 public void reset() { 118 } 119 getPowerModel( long measuredEnergyUC, @NonNull BatteryUsageStatsQuery query)120 protected static @BatteryConsumer.PowerModel int getPowerModel( 121 long measuredEnergyUC, @NonNull BatteryUsageStatsQuery query) { 122 if (measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE 123 && !query.shouldForceUsePowerProfileModel()) { 124 return BatteryConsumer.POWER_MODEL_MEASURED_ENERGY; 125 } 126 return BatteryConsumer.POWER_MODEL_POWER_PROFILE; 127 } 128 getPowerModel(long measuredEnergyUC)129 protected static @BatteryConsumer.PowerModel int getPowerModel(long measuredEnergyUC) { 130 return measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE 131 ? BatteryConsumer.POWER_MODEL_MEASURED_ENERGY 132 : BatteryConsumer.POWER_MODEL_POWER_PROFILE; 133 } 134 135 /** 136 * Returns either the measured energy converted to mAh or a usage-based estimate. 137 */ getMeasuredOrEstimatedPower(@atteryConsumer.PowerModel int powerModel, long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs)138 protected static double getMeasuredOrEstimatedPower(@BatteryConsumer.PowerModel int powerModel, 139 long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs) { 140 switch (powerModel) { 141 case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY: 142 return uCtoMah(measuredEnergyUC); 143 case BatteryConsumer.POWER_MODEL_POWER_PROFILE: 144 default: 145 return powerEstimator.calculatePower(durationMs); 146 } 147 } 148 149 /** 150 * Returns either the measured energy converted to mAh or a usage-based estimate. 151 */ getMeasuredOrEstimatedPower( long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs)152 protected static double getMeasuredOrEstimatedPower( 153 long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs) { 154 if (measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE) { 155 return uCtoMah(measuredEnergyUC); 156 } else { 157 return powerEstimator.calculatePower(durationMs); 158 } 159 } 160 161 /** 162 * Prints formatted amount of power in milli-amp-hours. 163 */ printPowerMah(PrintWriter pw, double powerMah)164 public static void printPowerMah(PrintWriter pw, double powerMah) { 165 pw.print(formatCharge(powerMah)); 166 } 167 168 /** 169 * Converts charge in mAh to string. 170 */ formatCharge(double power)171 public static String formatCharge(double power) { 172 if (power == 0) return "0"; 173 174 final String format; 175 if (power < .00001) { 176 format = "%.8f"; 177 } else if (power < .0001) { 178 format = "%.7f"; 179 } else if (power < .001) { 180 format = "%.6f"; 181 } else if (power < .01) { 182 format = "%.5f"; 183 } else if (power < .1) { 184 format = "%.4f"; 185 } else if (power < 1) { 186 format = "%.3f"; 187 } else if (power < 10) { 188 format = "%.2f"; 189 } else if (power < 100) { 190 format = "%.1f"; 191 } else { 192 format = "%.0f"; 193 } 194 195 // Use English locale because this is never used in UI (only in checkin and dump). 196 return String.format(Locale.ENGLISH, format, power); 197 } 198 uCtoMah(long chargeUC)199 static double uCtoMah(long chargeUC) { 200 return chargeUC * MILLIAMPHOUR_PER_MICROCOULOMB; 201 } 202 } 203