Convert WifiPowerCalculator to work with BatteryUsageStats

Also, combine WifePowerCalculator and WifiPowerEstimator: they
have a lot more in common than different.

Bug: 158137862
Test: atest WifiPowerCalculatorTest

Change-Id: Ib937102043a1fe04941ecfd09b5077b14058e6ef
This commit is contained in:
Dmitri Plotnikov
2021-02-03 16:15:05 -08:00
parent 92e23aa512
commit 80c0c66edc
6 changed files with 345 additions and 210 deletions

View File

@@ -47,6 +47,7 @@ public abstract class BatteryConsumer {
POWER_COMPONENT_SYSTEM_SERVICES,
POWER_COMPONENT_SENSORS,
POWER_COMPONENT_GNSS,
POWER_COMPONENT_WIFI,
POWER_COMPONENT_WAKELOCK,
POWER_COMPONENT_SCREEN,
POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
@@ -66,6 +67,7 @@ public abstract class BatteryConsumer {
public static final int POWER_COMPONENT_MOBILE_RADIO = 8;
public static final int POWER_COMPONENT_SENSORS = 9;
public static final int POWER_COMPONENT_GNSS = 10;
public static final int POWER_COMPONENT_WIFI = 11;
public static final int POWER_COMPONENT_WAKELOCK = 12;
public static final int POWER_COMPONENT_SCREEN = 13;
// Power that is re-attributed to other battery consumers. For example, for System Server
@@ -94,6 +96,7 @@ public abstract class BatteryConsumer {
TIME_COMPONENT_MOBILE_RADIO,
TIME_COMPONENT_SENSORS,
TIME_COMPONENT_GNSS,
TIME_COMPONENT_WIFI,
TIME_COMPONENT_WAKELOCK,
TIME_COMPONENT_SCREEN,
})
@@ -112,6 +115,7 @@ public abstract class BatteryConsumer {
public static final int TIME_COMPONENT_MOBILE_RADIO = 8;
public static final int TIME_COMPONENT_SENSORS = 9;
public static final int TIME_COMPONENT_GNSS = 10;
public static final int TIME_COMPONENT_WIFI = 11;
public static final int TIME_COMPONENT_WAKELOCK = 12;
public static final int TIME_COMPONENT_SCREEN = 13;

View File

@@ -32,6 +32,10 @@ public class UsageBasedPowerEstimator {
mAveragePowerMahPerMs = averagePowerMilliAmp / MILLIS_IN_HOUR;
}
public boolean isSupported() {
return mAveragePowerMahPerMs != 0;
}
/**
* Given a {@link BatteryStats.Timer}, returns the accumulated duration.
*/

View File

@@ -15,8 +15,13 @@
*/
package com.android.internal.os;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.SystemBatteryConsumer;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
@@ -30,25 +35,93 @@ import java.util.List;
public class WifiPowerCalculator extends PowerCalculator {
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
private static final String TAG = "WifiPowerCalculator";
private final double mIdleCurrentMa;
private final double mTxCurrentMa;
private final double mRxCurrentMa;
private final PowerProfile mPowerProfile;
private final UsageBasedPowerEstimator mIdlePowerEstimator;
private final UsageBasedPowerEstimator mTxPowerEstimator;
private final UsageBasedPowerEstimator mRxPowerEstimator;
private final UsageBasedPowerEstimator mPowerOnPowerEstimator;
private final UsageBasedPowerEstimator mScanPowerEstimator;
private final UsageBasedPowerEstimator mBatchScanPowerEstimator;
private final boolean mHasWifiPowerController;
private double mTotalAppPowerDrain = 0;
private long mTotalAppRunningTime = 0;
private WifiPowerEstimator mWifiPowerEstimator;
private boolean mHasWifiPowerReporting;
private final double mWifiPowerPerPacket;
private static class PowerDurationAndTraffic {
public double powerMah;
public long durationMs;
public long wifiRxPackets;
public long wifiTxPackets;
public long wifiRxBytes;
public long wifiTxBytes;
}
public WifiPowerCalculator(PowerProfile profile) {
mPowerProfile = profile;
mPowerOnPowerEstimator = new UsageBasedPowerEstimator(
profile.getAveragePower(PowerProfile.POWER_WIFI_ON));
mScanPowerEstimator = new UsageBasedPowerEstimator(
profile.getAveragePower(PowerProfile.POWER_WIFI_SCAN));
mBatchScanPowerEstimator = new UsageBasedPowerEstimator(
profile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN));
mIdlePowerEstimator = new UsageBasedPowerEstimator(
profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE));
mTxPowerEstimator = new UsageBasedPowerEstimator(
profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX));
mRxPowerEstimator = new UsageBasedPowerEstimator(
profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX));
mIdleCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE);
mTxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX);
mRxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX);
mWifiPowerPerPacket = getWifiPowerPerPacket(profile);
mHasWifiPowerController = mIdleCurrentMa != 0 && mTxCurrentMa != 0 && mRxCurrentMa != 0;
mWifiPowerEstimator = new WifiPowerEstimator(mPowerProfile);
mHasWifiPowerController =
mIdlePowerEstimator.isSupported() && mTxPowerEstimator.isSupported()
&& mRxPowerEstimator.isSupported();
}
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
// batteryStats.hasWifiActivityReporting can change if we get energy data at a later point,
// so always check this field.
final boolean hasWifiPowerReporting =
mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
builder.getOrCreateSystemBatteryConsumerBuilder(
SystemBatteryConsumer.DRAIN_TYPE_WIFI);
long totalAppDurationMs = 0;
double totalAppPowerMah = 0;
final PowerDurationAndTraffic powerDurationAndTraffic = new PowerDurationAndTraffic();
final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
builder.getUidBatteryConsumerBuilders();
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
calculateApp(powerDurationAndTraffic, app.getBatteryStatsUid(), rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED,
hasWifiPowerReporting);
totalAppDurationMs += powerDurationAndTraffic.durationMs;
totalAppPowerMah += powerDurationAndTraffic.powerMah;
app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
powerDurationAndTraffic.durationMs);
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
powerDurationAndTraffic.powerMah);
if (app.getUid() == Process.WIFI_UID) {
systemBatteryConsumerBuilder.addUidBatteryConsumer(app);
app.excludeFromBatteryUsageStats();
}
}
calculateRemaining(powerDurationAndTraffic, batteryStats, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED,
hasWifiPowerReporting, totalAppDurationMs, totalAppPowerMah);
systemBatteryConsumerBuilder
.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
powerDurationAndTraffic.durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
powerDurationAndTraffic.powerMah);
}
/**
@@ -64,100 +137,151 @@ public class WifiPowerCalculator extends PowerCalculator {
// batteryStats.hasWifiActivityReporting can change if we get energy data at a later point,
// so always check this field.
mHasWifiPowerReporting = mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
final boolean hasWifiPowerReporting =
mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
calculateRemaining(bs, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
long totalAppDurationMs = 0;
double totalAppPowerMah = 0;
final PowerDurationAndTraffic powerDurationAndTraffic = new PowerDurationAndTraffic();
for (int i = sippers.size() - 1; i >= 0; i--) {
BatterySipper app = sippers.get(i);
if (app.getUid() == Process.WIFI_UID) {
if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
app.isAggregated = true;
bs.add(app);
final BatterySipper app = sippers.get(i);
if (app.drainType == BatterySipper.DrainType.APP) {
calculateApp(powerDurationAndTraffic, app.uidObj, rawRealtimeUs, statsType,
hasWifiPowerReporting);
totalAppDurationMs += powerDurationAndTraffic.durationMs;
totalAppPowerMah += powerDurationAndTraffic.powerMah;
app.wifiPowerMah = powerDurationAndTraffic.powerMah;
app.wifiRunningTimeMs = powerDurationAndTraffic.durationMs;
app.wifiRxBytes = powerDurationAndTraffic.wifiRxBytes;
app.wifiRxPackets = powerDurationAndTraffic.wifiRxPackets;
app.wifiTxBytes = powerDurationAndTraffic.wifiTxBytes;
app.wifiTxPackets = powerDurationAndTraffic.wifiTxPackets;
if (app.getUid() == Process.WIFI_UID) {
if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
app.isAggregated = true;
bs.add(app);
}
}
}
calculateRemaining(powerDurationAndTraffic, batteryStats, rawRealtimeUs, statsType,
hasWifiPowerReporting, totalAppDurationMs, totalAppPowerMah);
bs.wifiRunningTimeMs += powerDurationAndTraffic.durationMs;
bs.wifiPowerMah += powerDurationAndTraffic.powerMah;
if (bs.sumPower() > 0) {
sippers.add(bs);
}
}
@Override
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
if (!mHasWifiPowerReporting) {
mWifiPowerEstimator.calculateApp(app, u, rawRealtimeUs, rawUptimeUs, statsType);
return;
}
final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
if (counter == null) {
return;
}
final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
app.wifiRunningTimeMs = idleTime + rxTime + txTime;
mTotalAppRunningTime += app.wifiRunningTimeMs;
app.wifiPowerMah =
((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa))
/ (1000 * 60 * 60);
mTotalAppPowerDrain += app.wifiPowerMah;
app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
private void calculateApp(PowerDurationAndTraffic powerDurationAndTraffic, BatteryStats.Uid u,
long rawRealtimeUs,
int statsType, boolean hasWifiPowerReporting) {
powerDurationAndTraffic.wifiRxPackets = u.getNetworkActivityPackets(
BatteryStats.NETWORK_WIFI_RX_DATA,
statsType);
app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
powerDurationAndTraffic.wifiTxPackets = u.getNetworkActivityPackets(
BatteryStats.NETWORK_WIFI_TX_DATA,
statsType);
app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
powerDurationAndTraffic.wifiRxBytes = u.getNetworkActivityBytes(
BatteryStats.NETWORK_WIFI_RX_DATA,
statsType);
app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
powerDurationAndTraffic.wifiTxBytes = u.getNetworkActivityBytes(
BatteryStats.NETWORK_WIFI_TX_DATA,
statsType);
if (DEBUG && app.wifiPowerMah != 0) {
Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime + "ms tx=" +
txTime + "ms power=" + formatCharge(app.wifiPowerMah));
if (hasWifiPowerReporting) {
final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
if (counter != null) {
final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
powerDurationAndTraffic.durationMs = idleTime + rxTime + txTime;
powerDurationAndTraffic.powerMah = mIdlePowerEstimator.calculatePower(idleTime)
+ mTxPowerEstimator.calculatePower(txTime)
+ mRxPowerEstimator.calculatePower(rxTime);
if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime
+ "ms tx=" + txTime + "ms power=" + formatCharge(
powerDurationAndTraffic.powerMah));
}
}
} else {
final double wifiPacketPower = (
powerDurationAndTraffic.wifiRxPackets + powerDurationAndTraffic.wifiTxPackets)
* mWifiPowerPerPacket;
final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
long batchScanTimeMs = 0;
for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
batchScanTimeMs += u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000;
}
powerDurationAndTraffic.durationMs = wifiRunningTime;
powerDurationAndTraffic.powerMah = wifiPacketPower
+ mPowerOnPowerEstimator.calculatePower(wifiRunningTime)
+ mScanPowerEstimator.calculatePower(wifiScanTimeMs)
+ mBatchScanPowerEstimator.calculatePower(batchScanTimeMs);
if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
Log.d(TAG, "UID " + u.getUid() + ": power=" + formatCharge(
powerDurationAndTraffic.powerMah));
}
}
}
private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
if (!mHasWifiPowerReporting) {
mWifiPowerEstimator.calculateRemaining(app, stats, rawRealtimeUs, rawUptimeUs,
statsType);
return;
private void calculateRemaining(PowerDurationAndTraffic powerDurationAndTraffic,
BatteryStats stats, long rawRealtimeUs,
int statsType, boolean hasWifiPowerReporting, long totalAppDurationMs,
double totalAppPowerMah) {
long totalDurationMs;
double totalPowerMah;
if (hasWifiPowerReporting) {
final BatteryStats.ControllerActivityCounter counter =
stats.getWifiControllerActivity();
final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
totalDurationMs = idleTimeMs + rxTimeMs + txTimeMs;
totalPowerMah =
counter.getPowerCounter().getCountLocked(statsType) / (double) (1000 * 60 * 60);
if (totalPowerMah == 0) {
// Some controllers do not report power drain, so we can calculate it here.
totalPowerMah = mIdlePowerEstimator.calculatePower(idleTimeMs)
+ mTxPowerEstimator.calculatePower(txTimeMs)
+ mRxPowerEstimator.calculatePower(rxTimeMs);
}
} else {
totalDurationMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType) / 1000;
totalPowerMah = mPowerOnPowerEstimator.calculatePower(totalDurationMs);
}
final BatteryStats.ControllerActivityCounter counter = stats.getWifiControllerActivity();
final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
app.wifiRunningTimeMs = Math.max(0,
(idleTimeMs + rxTimeMs + txTimeMs) - mTotalAppRunningTime);
double powerDrainMah = counter.getPowerCounter().getCountLocked(statsType)
/ (double) (1000 * 60 * 60);
if (powerDrainMah == 0) {
// Some controllers do not report power drain, so we can calculate it here.
powerDrainMah = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa)
+ (rxTimeMs * mRxCurrentMa)) / (1000 * 60 * 60);
}
app.wifiPowerMah = Math.max(0, powerDrainMah - mTotalAppPowerDrain);
powerDurationAndTraffic.durationMs = Math.max(0, totalDurationMs - totalAppDurationMs);
powerDurationAndTraffic.powerMah = Math.max(0, totalPowerMah - totalAppPowerMah);
if (DEBUG) {
Log.d(TAG, "left over WiFi power: " + formatCharge(app.wifiPowerMah));
Log.d(TAG, "left over WiFi power: " + formatCharge(powerDurationAndTraffic.powerMah));
}
}
@Override
public void reset() {
mTotalAppPowerDrain = 0;
mTotalAppRunningTime = 0;
mWifiPowerEstimator.reset();
/**
* Return estimated power per Wi-Fi packet in mAh/packet where 1 packet = 2 KB.
*/
private static double getWifiPowerPerPacket(PowerProfile profile) {
// TODO(b/179392913): Extract average bit rates from system
final long wifiBps = 1000000;
final double averageWifiActivePower =
profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE) / 3600;
return averageWifiActivePower / (((double) wifiBps) / 8 / 2048);
}
}

View File

@@ -1,126 +0,0 @@
/*
* 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.internal.os;
import android.os.BatteryStats;
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
import java.util.List;
/**
* Estimates WiFi power usage based on timers in BatteryStats.
*/
public class WifiPowerEstimator extends PowerCalculator {
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
private static final String TAG = "WifiPowerEstimator";
private final double mWifiPowerPerPacket;
private final double mWifiPowerOn;
private final double mWifiPowerScan;
private final double mWifiPowerBatchScan;
private long mTotalAppWifiRunningTimeMs = 0;
public WifiPowerEstimator(PowerProfile profile) {
mWifiPowerPerPacket = getWifiPowerPerPacket(profile);
mWifiPowerOn = profile.getAveragePower(PowerProfile.POWER_WIFI_ON);
mWifiPowerScan = profile.getAveragePower(PowerProfile.POWER_WIFI_SCAN);
mWifiPowerBatchScan = profile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN);
}
@Override
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
calculateRemaining(bs, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
for (int i = sippers.size() - 1; i >= 0; i--) {
BatterySipper app = sippers.get(i);
if (app.getUid() == Process.WIFI_UID) {
if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
app.isAggregated = true;
bs.add(app);
}
}
if (bs.sumPower() > 0) {
sippers.add(bs);
}
}
/**
* Return estimated power per Wi-Fi packet in mAh/packet where 1 packet = 2 KB.
*/
private static double getWifiPowerPerPacket(PowerProfile profile) {
final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system
final double WIFI_POWER = profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE)
/ 3600;
return WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048);
}
@Override
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
statsType);
app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
statsType);
app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
statsType);
app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
statsType);
final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets)
* mWifiPowerPerPacket;
app.wifiRunningTimeMs = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
mTotalAppWifiRunningTimeMs += app.wifiRunningTimeMs;
final double wifiLockPower = (app.wifiRunningTimeMs * mWifiPowerOn) / (1000*60*60);
final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
final double wifiScanPower = (wifiScanTimeMs * mWifiPowerScan) / (1000*60*60);
double wifiBatchScanPower = 0;
for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
final long batchScanTimeMs =
u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000;
final double batchScanPower = (batchScanTimeMs * mWifiPowerBatchScan) / (1000*60*60);
wifiBatchScanPower += batchScanPower;
}
app.wifiPowerMah = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;
if (DEBUG && app.wifiPowerMah != 0) {
Log.d(TAG, "UID " + u.getUid() + ": power=" + formatCharge(app.wifiPowerMah));
}
}
void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
final long totalRunningTimeMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType)
/ 1000;
final double powerDrain = ((totalRunningTimeMs - mTotalAppWifiRunningTimeMs) * mWifiPowerOn)
/ (1000*60*60);
app.wifiRunningTimeMs = totalRunningTimeMs;
app.wifiPowerMah = Math.max(0, powerDrain);
}
@Override
public void reset() {
mTotalAppWifiRunningTimeMs = 0;
}
}

View File

@@ -71,6 +71,7 @@ import org.junit.runners.Suite;
UserPowerCalculatorTest.class,
VideoPowerCalculatorTest.class,
WakelockPowerCalculatorTest.class,
WifiPowerCalculatorTest.class,
com.android.internal.power.MeasuredEnergyStatsTest.class
})

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2021 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.internal.os;
import static com.google.common.truth.Truth.assertThat;
import android.net.NetworkCapabilities;
import android.net.NetworkStats;
import android.os.BatteryConsumer;
import android.os.Process;
import android.os.SystemBatteryConsumer;
import android.os.UidBatteryConsumer;
import android.os.WorkSource;
import android.os.connectivity.WifiActivityEnergyInfo;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class WifiPowerCalculatorTest {
private static final double PRECISION = 0.00001;
private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
@Rule
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
.setAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE, 360.0)
.setAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX, 480.0)
.setAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX, 720.0)
.setAveragePower(PowerProfile.POWER_WIFI_ON, 360.0)
.setAveragePower(PowerProfile.POWER_WIFI_SCAN, 480.0)
.setAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, 720.0)
.setAveragePower(PowerProfile.POWER_WIFI_ACTIVE, 1080.0);
@Test
public void testPowerControllerBasedModel() {
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
batteryStats.noteNetworkInterfaceForTransports("wifi",
new int[]{NetworkCapabilities.TRANSPORT_WIFI});
NetworkStats networkStats = new NetworkStats(10000, 1)
.insertEntry("wifi", APP_UID, 0, 0, 1000, 100, 2000, 20, 100)
.insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
mStatsRule.setNetworkStats(networkStats);
WifiActivityEnergyInfo energyInfo = new WifiActivityEnergyInfo(10000,
WifiActivityEnergyInfo.STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000);
batteryStats.updateWifiState(energyInfo, 1000, 1000);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
.isEqualTo(1423);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.2214666);
SystemBatteryConsumer systemConsumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
.isEqualTo(5577);
assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.645200);
}
@Test
public void testTimerBasedModel() {
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
batteryStats.noteNetworkInterfaceForTransports("wifi",
new int[]{NetworkCapabilities.TRANSPORT_WIFI});
NetworkStats networkStats = new NetworkStats(10000, 1)
.insertEntry("wifi", APP_UID, 0, 0, 1000, 100, 2000, 20, 100)
.insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
mStatsRule.setNetworkStats(networkStats);
batteryStats.noteWifiScanStartedLocked(APP_UID, 1000, 1000);
batteryStats.noteWifiScanStoppedLocked(APP_UID, 2000, 2000);
batteryStats.noteWifiRunningLocked(new WorkSource(APP_UID), 3000, 3000);
batteryStats.noteWifiStoppedLocked(new WorkSource(APP_UID), 4000, 4000);
batteryStats.noteWifiRunningLocked(new WorkSource(Process.WIFI_UID), 1111, 2222);
batteryStats.noteWifiStoppedLocked(new WorkSource(Process.WIFI_UID), 3333, 4444);
// Don't pass WifiActivityEnergyInfo, making WifiPowerCalculator rely exclusively
// on the packet counts.
batteryStats.updateWifiState(/* energyInfo */ null, 1000, 1000);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
.isEqualTo(1000);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.8231573);
SystemBatteryConsumer systemConsumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
.isEqualTo(2222);
assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.8759216);
}
}