1 /* 2 * Copyright (C) 2020 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 17 package com.android.internal.os; 18 19 import android.os.BatteryConsumer; 20 import android.os.BatteryStats; 21 import android.os.BatteryUsageStats; 22 import android.os.BatteryUsageStatsQuery; 23 import android.os.Process; 24 import android.os.UidBatteryConsumer; 25 import android.os.UserHandle; 26 import android.util.Log; 27 import android.util.SparseArray; 28 29 import java.util.List; 30 31 /** 32 * Estimates the amount of power consumed by the System Server handling requests from 33 * a given app. 34 */ 35 public class SystemServicePowerCalculator extends PowerCalculator { 36 private static final boolean DEBUG = false; 37 private static final String TAG = "SystemServicePowerCalc"; 38 39 // Power estimators per CPU cluster, per CPU frequency. The array is flattened according 40 // to this layout: 41 // {cluster1-speed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...} 42 private final UsageBasedPowerEstimator[] mPowerEstimators; 43 private final CpuPowerCalculator mCpuPowerCalculator; 44 SystemServicePowerCalculator(PowerProfile powerProfile)45 public SystemServicePowerCalculator(PowerProfile powerProfile) { 46 mCpuPowerCalculator = new CpuPowerCalculator(powerProfile); 47 int numFreqs = 0; 48 final int numCpuClusters = powerProfile.getNumCpuClusters(); 49 for (int cluster = 0; cluster < numCpuClusters; cluster++) { 50 numFreqs += powerProfile.getNumSpeedStepsInCpuCluster(cluster); 51 } 52 53 mPowerEstimators = new UsageBasedPowerEstimator[numFreqs]; 54 int index = 0; 55 for (int cluster = 0; cluster < numCpuClusters; cluster++) { 56 final int numSpeeds = powerProfile.getNumSpeedStepsInCpuCluster(cluster); 57 for (int speed = 0; speed < numSpeeds; speed++) { 58 mPowerEstimators[index++] = new UsageBasedPowerEstimator( 59 powerProfile.getAveragePowerForCpuCore(cluster, speed)); 60 } 61 } 62 } 63 64 @Override calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query)65 public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, 66 long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { 67 final BatteryStats.Uid systemUid = batteryStats.getUidStats().get(Process.SYSTEM_UID); 68 if (systemUid == null) { 69 return; 70 } 71 72 final long consumptionUC = systemUid.getCpuMeasuredBatteryConsumptionUC(); 73 final int powerModel = getPowerModel(consumptionUC, query); 74 75 double systemServicePowerMah; 76 if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) { 77 systemServicePowerMah = calculatePowerUsingMeasuredConsumption(batteryStats, 78 systemUid, consumptionUC); 79 } else { 80 systemServicePowerMah = calculatePowerUsingPowerProfile(batteryStats); 81 } 82 83 final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders = 84 builder.getUidBatteryConsumerBuilders(); 85 final UidBatteryConsumer.Builder systemServerConsumer = uidBatteryConsumerBuilders.get( 86 Process.SYSTEM_UID); 87 88 if (systemServerConsumer != null) { 89 systemServicePowerMah = Math.min(systemServicePowerMah, 90 systemServerConsumer.getTotalPower()); 91 92 // The system server power needs to be adjusted because part of it got 93 // distributed to applications 94 systemServerConsumer.setConsumedPower( 95 BatteryConsumer.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS, 96 -systemServicePowerMah, powerModel); 97 } 98 99 for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { 100 final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); 101 if (app != systemServerConsumer) { 102 final BatteryStats.Uid uid = app.getBatteryStatsUid(); 103 app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES, 104 systemServicePowerMah * uid.getProportionalSystemServiceUsage(), 105 powerModel); 106 } 107 } 108 109 builder.getAggregateBatteryConsumerBuilder( 110 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) 111 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES, 112 systemServicePowerMah); 113 builder.getAggregateBatteryConsumerBuilder( 114 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) 115 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES, 116 systemServicePowerMah); 117 } 118 119 @Override calculate(List<BatterySipper> sippers, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers)120 public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, 121 long rawRealtimeUs, long rawUptimeUs, int statsType, 122 SparseArray<UserHandle> asUsers) { 123 final BatteryStats.Uid systemUid = batteryStats.getUidStats().get(Process.SYSTEM_UID); 124 if (systemUid == null) { 125 return; 126 } 127 128 final long consumptionUC = systemUid.getCpuMeasuredBatteryConsumptionUC(); 129 double systemServicePowerMah; 130 if (getPowerModel(consumptionUC) == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) { 131 systemServicePowerMah = calculatePowerUsingMeasuredConsumption(batteryStats, 132 systemUid, consumptionUC); 133 } else { 134 systemServicePowerMah = calculatePowerUsingPowerProfile(batteryStats); 135 } 136 137 BatterySipper systemServerSipper = null; 138 for (int i = sippers.size() - 1; i >= 0; i--) { 139 final BatterySipper app = sippers.get(i); 140 if (app.drainType == BatterySipper.DrainType.APP) { 141 if (app.getUid() == Process.SYSTEM_UID) { 142 systemServerSipper = app; 143 break; 144 } 145 } 146 } 147 148 if (systemServerSipper != null) { 149 systemServicePowerMah = Math.min(systemServicePowerMah, systemServerSipper.sumPower()); 150 151 // The system server power needs to be adjusted because part of it got 152 // distributed to applications 153 systemServerSipper.powerReattributedToOtherSippersMah = -systemServicePowerMah; 154 } 155 156 for (int i = sippers.size() - 1; i >= 0; i--) { 157 final BatterySipper app = sippers.get(i); 158 if (app.drainType == BatterySipper.DrainType.APP) { 159 if (app != systemServerSipper) { 160 final BatteryStats.Uid uid = app.uidObj; 161 app.systemServiceCpuPowerMah = 162 systemServicePowerMah * uid.getProportionalSystemServiceUsage(); 163 } 164 } 165 } 166 } 167 calculatePowerUsingMeasuredConsumption(BatteryStats batteryStats, BatteryStats.Uid systemUid, long consumptionUC)168 private double calculatePowerUsingMeasuredConsumption(BatteryStats batteryStats, 169 BatteryStats.Uid systemUid, long consumptionUC) { 170 // Use the PowerProfile based model to estimate the ratio between the power consumed 171 // while handling incoming binder calls and the entire System UID power consumption. 172 // Apply that ratio to the _measured_ system UID power consumption to get a more 173 // accurate estimate of the power consumed by incoming binder calls. 174 final double systemServiceModeledPowerMah = calculatePowerUsingPowerProfile(batteryStats); 175 final double systemUidModeledPowerMah = mCpuPowerCalculator.calculateUidModeledPowerMah( 176 systemUid, BatteryStats.STATS_SINCE_CHARGED); 177 178 return uCtoMah(consumptionUC) * systemServiceModeledPowerMah 179 / systemUidModeledPowerMah; 180 } 181 calculatePowerUsingPowerProfile(BatteryStats batteryStats)182 private double calculatePowerUsingPowerProfile(BatteryStats batteryStats) { 183 final long[] systemServiceTimeAtCpuSpeeds = batteryStats.getSystemServiceTimeAtCpuSpeeds(); 184 if (systemServiceTimeAtCpuSpeeds == null) { 185 return 0; 186 } 187 188 // TODO(179210707): additionally account for CPU active and per cluster battery use 189 190 double powerMah = 0; 191 final int size = Math.min(mPowerEstimators.length, systemServiceTimeAtCpuSpeeds.length); 192 for (int i = 0; i < size; i++) { 193 powerMah += mPowerEstimators[i].calculatePower(systemServiceTimeAtCpuSpeeds[i] / 1000); 194 } 195 196 if (DEBUG) { 197 Log.d(TAG, "System service power:" + powerMah); 198 } 199 return powerMah; 200 } 201 } 202