Move calculations from BatteryStatsHelper to PowerCalculators
Bug: 162379528 Test: atest FrameworksCoreTests Change-Id: I61002c3c1f198fb10441800eba49760aba90823a
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.UserHandle;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Estimates power consumed by the ambient display
|
||||
*/
|
||||
public class AmbientDisplayPowerCalculator extends PowerCalculator {
|
||||
|
||||
private final PowerProfile mPowerProfile;
|
||||
|
||||
public AmbientDisplayPowerCalculator(PowerProfile powerProfile) {
|
||||
mPowerProfile = powerProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ambient display power is the additional power the screen takes while in ambient display/
|
||||
* screen doze/ always-on display (interchangeable terms) mode. Ambient display power should
|
||||
* be hidden {@link BatteryStatsHelper#shouldHideSipper(BatterySipper)}, but should not be
|
||||
* included in smearing {@link BatteryStatsHelper#removeHiddenBatterySippers(List)}.
|
||||
*/
|
||||
@Override
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
|
||||
long ambientDisplayMs = batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000;
|
||||
double power = mPowerProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY)
|
||||
* ambientDisplayMs / (60 * 60 * 1000);
|
||||
if (power > 0) {
|
||||
BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0);
|
||||
bs.usagePowerMah = power;
|
||||
bs.usageTimeMs = ambientDisplayMs;
|
||||
bs.sumPower();
|
||||
sippers.add(bs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,6 +132,10 @@ public class BatterySipper implements Comparable<BatterySipper> {
|
||||
public double wifiPowerMah;
|
||||
public double systemServiceCpuPowerMah;
|
||||
|
||||
// Do not include this sipper in results because it is included
|
||||
// in an aggregate sipper.
|
||||
public boolean isAggregated;
|
||||
|
||||
// ****************
|
||||
// This list must be kept current with atoms.proto (frameworks/base/cmds/statsd/src/atoms.proto)
|
||||
// so the ordinal values (and therefore the order) must never change.
|
||||
|
||||
@@ -54,9 +54,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A helper class for retrieving the power usage information for all applications and services.
|
||||
@@ -77,6 +75,8 @@ public class BatteryStatsHelper {
|
||||
final private boolean mCollectBatteryBroadcast;
|
||||
final private boolean mWifiOnly;
|
||||
|
||||
private List<PowerCalculator> mPowerCalculators;
|
||||
|
||||
@UnsupportedAppUsage
|
||||
private IBatteryStats mBatteryInfo;
|
||||
private BatteryStats mStats;
|
||||
@@ -94,18 +94,6 @@ public class BatteryStatsHelper {
|
||||
@UnsupportedAppUsage
|
||||
private final List<BatterySipper> mUsageList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* List of apps using wifi power.
|
||||
*/
|
||||
private final List<BatterySipper> mWifiSippers = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* List of apps using bluetooth power.
|
||||
*/
|
||||
private final List<BatterySipper> mBluetoothSippers = new ArrayList<>();
|
||||
|
||||
private final SparseArray<List<BatterySipper>> mUserSippers = new SparseArray<>();
|
||||
|
||||
private final List<BatterySipper> mMobilemsppList = new ArrayList<>();
|
||||
|
||||
private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
|
||||
@@ -114,8 +102,6 @@ public class BatteryStatsHelper {
|
||||
long mRawUptimeUs;
|
||||
long mBatteryRealtimeUs;
|
||||
long mBatteryUptimeUs;
|
||||
long mTypeBatteryRealtimeUs;
|
||||
long mTypeBatteryUptimeUs;
|
||||
long mBatteryTimeRemainingUs;
|
||||
long mChargeTimeRemainingUs;
|
||||
|
||||
@@ -133,21 +119,6 @@ public class BatteryStatsHelper {
|
||||
private double mMinDrainedPower;
|
||||
private double mMaxDrainedPower;
|
||||
|
||||
PowerCalculator mCpuPowerCalculator;
|
||||
SystemServicePowerCalculator mSystemServicePowerCalculator;
|
||||
PowerCalculator mWakelockPowerCalculator;
|
||||
MobileRadioPowerCalculator mMobileRadioPowerCalculator;
|
||||
PowerCalculator mWifiPowerCalculator;
|
||||
PowerCalculator mBluetoothPowerCalculator;
|
||||
PowerCalculator mSensorPowerCalculator;
|
||||
PowerCalculator mCameraPowerCalculator;
|
||||
PowerCalculator mFlashlightPowerCalculator;
|
||||
PowerCalculator mMemoryPowerCalculator;
|
||||
PowerCalculator mMediaPowerCalculator;
|
||||
|
||||
boolean mHasWifiPowerReporting = false;
|
||||
boolean mHasBluetoothPowerReporting = false;
|
||||
|
||||
public static boolean checkWifiOnly(Context context) {
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
|
||||
Context.CONNECTIVITY_SERVICE);
|
||||
@@ -157,21 +128,6 @@ public class BatteryStatsHelper {
|
||||
return !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
|
||||
}
|
||||
|
||||
public static boolean checkHasWifiPowerReporting(BatteryStats stats, PowerProfile profile) {
|
||||
return stats.hasWifiActivityReporting() &&
|
||||
profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE) != 0 &&
|
||||
profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX) != 0 &&
|
||||
profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX) != 0;
|
||||
}
|
||||
|
||||
public static boolean checkHasBluetoothPowerReporting(BatteryStats stats,
|
||||
PowerProfile profile) {
|
||||
return stats.hasBluetoothActivityReporting() &&
|
||||
profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE) != 0 &&
|
||||
profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX) != 0 &&
|
||||
profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX) != 0;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public BatteryStatsHelper(Context context) {
|
||||
this(context, true);
|
||||
@@ -308,31 +264,7 @@ public class BatteryStatsHelper {
|
||||
}
|
||||
|
||||
public static String makemAh(double power) {
|
||||
if (power == 0) return "0";
|
||||
|
||||
final String format;
|
||||
if (power < .00001) {
|
||||
format = "%.8f";
|
||||
} else if (power < .0001) {
|
||||
format = "%.7f";
|
||||
} else if (power < .001) {
|
||||
format = "%.6f";
|
||||
} else if (power < .01) {
|
||||
format = "%.5f";
|
||||
} else if (power < .1) {
|
||||
format = "%.4f";
|
||||
} else if (power < 1) {
|
||||
format = "%.3f";
|
||||
} else if (power < 10) {
|
||||
format = "%.2f";
|
||||
} else if (power < 100) {
|
||||
format = "%.1f";
|
||||
} else {
|
||||
format = "%.0f";
|
||||
}
|
||||
|
||||
// Use English locale because this is never used in UI (only in checkin and dump).
|
||||
return String.format(Locale.ENGLISH, format, power);
|
||||
return PowerCalculator.formatCharge(power);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -384,97 +316,58 @@ public class BatteryStatsHelper {
|
||||
mTotalPower = 0;
|
||||
|
||||
mUsageList.clear();
|
||||
mWifiSippers.clear();
|
||||
mBluetoothSippers.clear();
|
||||
mUserSippers.clear();
|
||||
mMobilemsppList.clear();
|
||||
|
||||
if (mStats == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCpuPowerCalculator == null) {
|
||||
mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
|
||||
}
|
||||
mCpuPowerCalculator.reset();
|
||||
if (mPowerCalculators == null) {
|
||||
mPowerCalculators = new ArrayList<>();
|
||||
|
||||
if (mSystemServicePowerCalculator == null) {
|
||||
mSystemServicePowerCalculator = new SystemServicePowerCalculator(mPowerProfile, mStats);
|
||||
}
|
||||
mSystemServicePowerCalculator.reset();
|
||||
// Power calculators are applied in the order of registration
|
||||
mPowerCalculators.add(new CpuPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new MemoryPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new WakelockPowerCalculator(mPowerProfile));
|
||||
if (!mWifiOnly) {
|
||||
mPowerCalculators.add(new MobileRadioPowerCalculator(mPowerProfile));
|
||||
}
|
||||
mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new BluetoothPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new SensorPowerCalculator(mPowerProfile,
|
||||
mContext.getSystemService(SensorManager.class)));
|
||||
mPowerCalculators.add(new CameraPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new MediaPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new PhonePowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new ScreenPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new SystemServicePowerCalculator(mPowerProfile));
|
||||
mPowerCalculators.add(new IdlePowerCalculator(mPowerProfile));
|
||||
|
||||
if (mMemoryPowerCalculator == null) {
|
||||
mMemoryPowerCalculator = new MemoryPowerCalculator(mPowerProfile);
|
||||
mPowerCalculators.add(new UserPowerCalculator());
|
||||
}
|
||||
mMemoryPowerCalculator.reset();
|
||||
|
||||
if (mWakelockPowerCalculator == null) {
|
||||
mWakelockPowerCalculator = new WakelockPowerCalculator(mPowerProfile);
|
||||
for (int i = 0, size = mPowerCalculators.size(); i < size; i++) {
|
||||
mPowerCalculators.get(i).reset();
|
||||
}
|
||||
mWakelockPowerCalculator.reset();
|
||||
|
||||
if (mMobileRadioPowerCalculator == null) {
|
||||
mMobileRadioPowerCalculator = new MobileRadioPowerCalculator(mPowerProfile, mStats);
|
||||
}
|
||||
mMobileRadioPowerCalculator.reset(mStats);
|
||||
|
||||
// checkHasWifiPowerReporting can change if we get energy data at a later point, so
|
||||
// always check this field.
|
||||
final boolean hasWifiPowerReporting = checkHasWifiPowerReporting(mStats, mPowerProfile);
|
||||
if (mWifiPowerCalculator == null || hasWifiPowerReporting != mHasWifiPowerReporting) {
|
||||
mWifiPowerCalculator = hasWifiPowerReporting ?
|
||||
new WifiPowerCalculator(mPowerProfile) :
|
||||
new WifiPowerEstimator(mPowerProfile);
|
||||
mHasWifiPowerReporting = hasWifiPowerReporting;
|
||||
}
|
||||
mWifiPowerCalculator.reset();
|
||||
|
||||
final boolean hasBluetoothPowerReporting = checkHasBluetoothPowerReporting(mStats,
|
||||
mPowerProfile);
|
||||
if (mBluetoothPowerCalculator == null ||
|
||||
hasBluetoothPowerReporting != mHasBluetoothPowerReporting) {
|
||||
mBluetoothPowerCalculator = new BluetoothPowerCalculator(mPowerProfile);
|
||||
mHasBluetoothPowerReporting = hasBluetoothPowerReporting;
|
||||
}
|
||||
mBluetoothPowerCalculator.reset();
|
||||
|
||||
mSensorPowerCalculator = new SensorPowerCalculator(mPowerProfile,
|
||||
(SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE),
|
||||
mStats, rawRealtimeUs, statsType);
|
||||
mSensorPowerCalculator.reset();
|
||||
|
||||
if (mCameraPowerCalculator == null) {
|
||||
mCameraPowerCalculator = new CameraPowerCalculator(mPowerProfile);
|
||||
}
|
||||
mCameraPowerCalculator.reset();
|
||||
|
||||
if (mFlashlightPowerCalculator == null) {
|
||||
mFlashlightPowerCalculator = new FlashlightPowerCalculator(mPowerProfile);
|
||||
}
|
||||
mFlashlightPowerCalculator.reset();
|
||||
|
||||
if (mMediaPowerCalculator == null) {
|
||||
mMediaPowerCalculator = new MediaPowerCalculator(mPowerProfile);
|
||||
}
|
||||
mMediaPowerCalculator.reset();
|
||||
|
||||
mStatsType = statsType;
|
||||
mRawUptimeUs = rawUptimeUs;
|
||||
mRawRealtimeUs = rawRealtimeUs;
|
||||
mBatteryUptimeUs = mStats.getBatteryUptime(rawUptimeUs);
|
||||
mBatteryRealtimeUs = mStats.getBatteryRealtime(rawRealtimeUs);
|
||||
mTypeBatteryUptimeUs = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
|
||||
mTypeBatteryRealtimeUs = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
|
||||
mBatteryTimeRemainingUs = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
|
||||
mChargeTimeRemainingUs = mStats.computeChargeTimeRemaining(rawRealtimeUs);
|
||||
mStatsPeriod = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs / 1000) + " uptime="
|
||||
+ (rawUptimeUs / 1000));
|
||||
Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtimeUs / 1000) + " uptime="
|
||||
+ (mBatteryUptimeUs / 1000));
|
||||
Log.d(TAG, "Battery type time: realtime=" + (mTypeBatteryRealtimeUs / 1000) + " uptime="
|
||||
+ (mTypeBatteryUptimeUs / 1000));
|
||||
Log.d(TAG, "Battery type time: realtime=" + (mStatsPeriod / 1000) + " uptime="
|
||||
+ (mStats.computeBatteryUptime(rawRealtimeUs, mStatsType) / 1000));
|
||||
}
|
||||
mMinDrainedPower = (mStats.getLowDischargeAmountSinceCharge()
|
||||
* mPowerProfile.getBatteryCapacity()) / 100;
|
||||
@@ -483,36 +376,11 @@ public class BatteryStatsHelper {
|
||||
|
||||
processAppUsage(asUsers);
|
||||
|
||||
// Before aggregating apps in to users, collect all apps to sort by their ms per packet.
|
||||
for (int i = 0; i < mUsageList.size(); i++) {
|
||||
BatterySipper bs = mUsageList.get(i);
|
||||
bs.computeMobilemspp();
|
||||
if (bs.mobilemspp != 0) {
|
||||
mMobilemsppList.add(bs);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < mUserSippers.size(); i++) {
|
||||
List<BatterySipper> user = mUserSippers.valueAt(i);
|
||||
for (int j = 0; j < user.size(); j++) {
|
||||
BatterySipper bs = user.get(j);
|
||||
bs.computeMobilemspp();
|
||||
if (bs.mobilemspp != 0) {
|
||||
mMobilemsppList.add(bs);
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(mMobilemsppList, new Comparator<BatterySipper>() {
|
||||
@Override
|
||||
public int compare(BatterySipper lhs, BatterySipper rhs) {
|
||||
return Double.compare(rhs.mobilemspp, lhs.mobilemspp);
|
||||
}
|
||||
});
|
||||
|
||||
processMiscUsage();
|
||||
|
||||
Collections.sort(mUsageList);
|
||||
|
||||
Collections.sort(mMobilemsppList,
|
||||
(lhs, rhs) -> Double.compare(rhs.mobilemspp, lhs.mobilemspp));
|
||||
|
||||
// At this point, we've sorted the list so we are guaranteed the max values are at the top.
|
||||
// We have only added real powers so far.
|
||||
if (!mUsageList.isEmpty()) {
|
||||
@@ -524,8 +392,9 @@ public class BatteryStatsHelper {
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Accuracy: total computed=" + makemAh(mComputedPower) + ", min discharge="
|
||||
+ makemAh(mMinDrainedPower) + ", max discharge=" + makemAh(mMaxDrainedPower));
|
||||
Log.d(TAG, "Accuracy: total computed=" + PowerCalculator.formatCharge(mComputedPower)
|
||||
+ ", min discharge=" + PowerCalculator.formatCharge(mMinDrainedPower)
|
||||
+ ", max discharge=" + PowerCalculator.formatCharge(mMaxDrainedPower));
|
||||
}
|
||||
|
||||
mTotalPower = mComputedPower;
|
||||
@@ -573,244 +442,43 @@ public class BatteryStatsHelper {
|
||||
}
|
||||
|
||||
private void processAppUsage(SparseArray<UserHandle> asUsers) {
|
||||
final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
|
||||
mStatsPeriod = mTypeBatteryRealtimeUs;
|
||||
|
||||
BatterySipper osSipper = null;
|
||||
final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
|
||||
final int NU = uidStats.size();
|
||||
for (int iu = 0; iu < NU; iu++) {
|
||||
|
||||
final ArrayList<BatterySipper> sippers = new ArrayList<>(uidStats.size());
|
||||
|
||||
for (int iu = 0, size = uidStats.size(); iu < size; iu++) {
|
||||
final Uid u = uidStats.valueAt(iu);
|
||||
final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
|
||||
sippers.add(new BatterySipper(DrainType.APP, u, 0));
|
||||
}
|
||||
|
||||
mCpuPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
|
||||
mWakelockPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
|
||||
mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
|
||||
mStatsType);
|
||||
mWifiPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
|
||||
mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
|
||||
mStatsType);
|
||||
mSensorPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
|
||||
mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
|
||||
mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
|
||||
mStatsType);
|
||||
mMediaPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
|
||||
mSystemServicePowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
|
||||
mStatsType);
|
||||
for (int i = 0, size = mPowerCalculators.size(); i < size; i++) {
|
||||
final PowerCalculator calculator = mPowerCalculators.get(i);
|
||||
calculator.calculate(sippers, mStats, mRawRealtimeUs, mRawUptimeUs, mStatsType,
|
||||
asUsers);
|
||||
}
|
||||
|
||||
final double totalPower = app.sumPower();
|
||||
for (int i = sippers.size() - 1; i >= 0; i--) {
|
||||
final BatterySipper sipper = sippers.get(i);
|
||||
final double totalPower = sipper.sumPower();
|
||||
if (DEBUG && totalPower != 0) {
|
||||
Log.d(TAG, String.format("UID %d: total power=%s", u.getUid(),
|
||||
makemAh(totalPower)));
|
||||
Log.d(TAG, String.format("UID %d: total power=%s", sipper.getUid(),
|
||||
PowerCalculator.formatCharge(totalPower)));
|
||||
}
|
||||
|
||||
// Add the app to the list if it is consuming power.
|
||||
if (totalPower != 0 || u.getUid() == 0) {
|
||||
//
|
||||
// Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list.
|
||||
//
|
||||
final int uid = app.getUid();
|
||||
final int userId = UserHandle.getUserId(uid);
|
||||
if (uid == Process.WIFI_UID) {
|
||||
mWifiSippers.add(app);
|
||||
} else if (uid == Process.BLUETOOTH_UID) {
|
||||
mBluetoothSippers.add(app);
|
||||
} else if (!forAllUsers && asUsers.get(userId) == null
|
||||
&& UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
|
||||
// We are told to just report this user's apps as one large entry.
|
||||
List<BatterySipper> list = mUserSippers.get(userId);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
mUserSippers.put(userId, list);
|
||||
// Add the sipper to the list if it is consuming power.
|
||||
if (totalPower != 0 || sipper.getUid() == 0) {
|
||||
if (sipper.drainType == DrainType.APP) {
|
||||
sipper.computeMobilemspp();
|
||||
if (sipper.mobilemspp != 0) {
|
||||
mMobilemsppList.add(sipper);
|
||||
}
|
||||
list.add(app);
|
||||
} else {
|
||||
mUsageList.add(app);
|
||||
}
|
||||
|
||||
if (uid == 0) {
|
||||
osSipper = app;
|
||||
if (!sipper.isAggregated) {
|
||||
mUsageList.add(sipper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (osSipper != null) {
|
||||
// The device has probably been awake for longer than the screen on
|
||||
// time and application wake lock time would account for. Assign
|
||||
// this remainder to the OS, if possible.
|
||||
mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtimeUs,
|
||||
mRawUptimeUs, mStatsType);
|
||||
osSipper.sumPower();
|
||||
}
|
||||
}
|
||||
|
||||
private void addPhoneUsage() {
|
||||
long phoneOnTimeMs = mStats.getPhoneOnTime(mRawRealtimeUs, mStatsType) / 1000;
|
||||
double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
|
||||
* phoneOnTimeMs / (60 * 60 * 1000);
|
||||
if (phoneOnPower != 0) {
|
||||
addEntry(BatterySipper.DrainType.PHONE, phoneOnTimeMs, phoneOnPower);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Screen power is the additional power the screen takes while the device is running.
|
||||
*/
|
||||
private void addScreenUsage() {
|
||||
double power = 0;
|
||||
long screenOnTimeMs = mStats.getScreenOnTime(mRawRealtimeUs, mStatsType) / 1000;
|
||||
power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON);
|
||||
final double screenFullPower =
|
||||
mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
|
||||
for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
|
||||
double screenBinPower = screenFullPower * (i + 0.5f)
|
||||
/ BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
|
||||
long brightnessTime = mStats.getScreenBrightnessTime(i, mRawRealtimeUs, mStatsType)
|
||||
/ 1000;
|
||||
double p = screenBinPower * brightnessTime;
|
||||
if (DEBUG && p != 0) {
|
||||
Log.d(TAG, "Screen bin #" + i + ": time=" + brightnessTime
|
||||
+ " power=" + makemAh(p / (60 * 60 * 1000)));
|
||||
}
|
||||
power += p;
|
||||
}
|
||||
power /= (60 * 60 * 1000); // To hours
|
||||
if (power != 0) {
|
||||
addEntry(BatterySipper.DrainType.SCREEN, screenOnTimeMs, power);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ambient display power is the additional power the screen takes while in ambient display/
|
||||
* screen doze/ always-on display (interchangeable terms) mode. Ambient display power should
|
||||
* be hidden {@link #shouldHideSipper(BatterySipper)}, but should not be included in smearing
|
||||
* {@link #removeHiddenBatterySippers(List)}.
|
||||
*/
|
||||
private void addAmbientDisplayUsage() {
|
||||
long ambientDisplayMs = mStats.getScreenDozeTime(mRawRealtimeUs, mStatsType) / 1000;
|
||||
double power = mPowerProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY)
|
||||
* ambientDisplayMs / (60 * 60 * 1000);
|
||||
if (power > 0) {
|
||||
addEntry(DrainType.AMBIENT_DISPLAY, ambientDisplayMs, power);
|
||||
}
|
||||
}
|
||||
|
||||
private void addRadioUsage() {
|
||||
BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
|
||||
mMobileRadioPowerCalculator.calculateRemaining(radio, mStats, mRawRealtimeUs, mRawUptimeUs,
|
||||
mStatsType);
|
||||
radio.sumPower();
|
||||
if (radio.totalPowerMah > 0) {
|
||||
mUsageList.add(radio);
|
||||
}
|
||||
}
|
||||
|
||||
private void aggregateSippers(BatterySipper bs, List<BatterySipper> from, String tag) {
|
||||
for (int i = 0; i < from.size(); i++) {
|
||||
BatterySipper wbs = from.get(i);
|
||||
if (DEBUG) Log.d(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTimeMs);
|
||||
bs.add(wbs);
|
||||
}
|
||||
bs.computeMobilemspp();
|
||||
bs.sumPower();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the baseline power usage for the device when it is in suspend and idle.
|
||||
* The device is drawing POWER_CPU_SUSPEND power at its lowest power state.
|
||||
* The device is drawing POWER_CPU_SUSPEND + POWER_CPU_IDLE power when a wakelock is held.
|
||||
*/
|
||||
private void addIdleUsage() {
|
||||
final double suspendPowerMaMs = (mTypeBatteryRealtimeUs / 1000) *
|
||||
mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND);
|
||||
final double idlePowerMaMs = (mTypeBatteryUptimeUs / 1000) *
|
||||
mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
|
||||
final double totalPowerMah = (suspendPowerMaMs + idlePowerMaMs) / (60 * 60 * 1000);
|
||||
if (DEBUG && totalPowerMah != 0) {
|
||||
Log.d(TAG, "Suspend: time=" + (mTypeBatteryRealtimeUs / 1000)
|
||||
+ " power=" + makemAh(suspendPowerMaMs / (60 * 60 * 1000)));
|
||||
Log.d(TAG, "Idle: time=" + (mTypeBatteryUptimeUs / 1000)
|
||||
+ " power=" + makemAh(idlePowerMaMs / (60 * 60 * 1000)));
|
||||
}
|
||||
|
||||
if (totalPowerMah != 0) {
|
||||
addEntry(BatterySipper.DrainType.IDLE, mTypeBatteryRealtimeUs / 1000, totalPowerMah);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We do per-app blaming of WiFi activity. If energy info is reported from the controller,
|
||||
* then only the WiFi process gets blamed here since we normalize power calculations and
|
||||
* assign all the power drain to apps. If energy info is not reported, we attribute the
|
||||
* difference between total running time of WiFi for all apps and the actual running time
|
||||
* of WiFi to the WiFi subsystem.
|
||||
*/
|
||||
private void addWiFiUsage() {
|
||||
BatterySipper bs = new BatterySipper(DrainType.WIFI, null, 0);
|
||||
mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtimeUs, mRawUptimeUs,
|
||||
mStatsType);
|
||||
aggregateSippers(bs, mWifiSippers, "WIFI");
|
||||
if (bs.totalPowerMah > 0) {
|
||||
mUsageList.add(bs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bluetooth usage is not attributed to any apps yet, so the entire blame goes to the
|
||||
* Bluetooth Category.
|
||||
*/
|
||||
private void addBluetoothUsage() {
|
||||
BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
|
||||
mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtimeUs, mRawUptimeUs,
|
||||
mStatsType);
|
||||
aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
|
||||
if (bs.totalPowerMah > 0) {
|
||||
mUsageList.add(bs);
|
||||
}
|
||||
}
|
||||
|
||||
private void addUserUsage() {
|
||||
for (int i = 0; i < mUserSippers.size(); i++) {
|
||||
final int userId = mUserSippers.keyAt(i);
|
||||
BatterySipper bs = new BatterySipper(DrainType.USER, null, 0);
|
||||
bs.userId = userId;
|
||||
aggregateSippers(bs, mUserSippers.valueAt(i), "User");
|
||||
mUsageList.add(bs);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMemoryUsage() {
|
||||
BatterySipper memory = new BatterySipper(DrainType.MEMORY, null, 0);
|
||||
mMemoryPowerCalculator.calculateRemaining(memory, mStats, mRawRealtimeUs, mRawUptimeUs,
|
||||
mStatsType);
|
||||
memory.sumPower();
|
||||
if (memory.totalPowerMah > 0) {
|
||||
mUsageList.add(memory);
|
||||
}
|
||||
}
|
||||
|
||||
private void processMiscUsage() {
|
||||
addUserUsage();
|
||||
addPhoneUsage();
|
||||
addScreenUsage();
|
||||
addAmbientDisplayUsage();
|
||||
addWiFiUsage();
|
||||
addBluetoothUsage();
|
||||
addMemoryUsage();
|
||||
addIdleUsage(); // Not including cellular idle power
|
||||
// Don't compute radio usage if it's a wifi-only device
|
||||
if (!mWifiOnly) {
|
||||
addRadioUsage();
|
||||
}
|
||||
}
|
||||
|
||||
private BatterySipper addEntry(DrainType drainType, long time, double power) {
|
||||
BatterySipper bs = new BatterySipper(drainType, null, 0);
|
||||
bs.usagePowerMah = power;
|
||||
bs.usageTimeMs = time;
|
||||
bs.sumPower();
|
||||
mUsageList.add(bs);
|
||||
return bs;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
|
||||
@@ -16,14 +16,20 @@
|
||||
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;
|
||||
|
||||
public class BluetoothPowerCalculator extends PowerCalculator {
|
||||
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
|
||||
private static final String TAG = "BluetoothPowerCalculator";
|
||||
private static final String TAG = "BluetoothPowerCalc";
|
||||
private final double mIdleMa;
|
||||
private final double mRxMa;
|
||||
private final double mTxMa;
|
||||
private final boolean mHasBluetoothPowerController;
|
||||
private double mAppTotalPowerMah = 0;
|
||||
private long mAppTotalTimeMs = 0;
|
||||
|
||||
@@ -31,10 +37,36 @@ public class BluetoothPowerCalculator extends PowerCalculator {
|
||||
mIdleMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE);
|
||||
mRxMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX);
|
||||
mTxMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX);
|
||||
mHasBluetoothPowerController = mIdleMa != 0 && mRxMa != 0 && mTxMa != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
if (!mHasBluetoothPowerController || !batteryStats.hasBluetoothActivityReporting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
|
||||
|
||||
BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, 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.BLUETOOTH_UID) {
|
||||
if (DEBUG) Log.d(TAG, "Bluetooth adding sipper " + app + ": cpu=" + app.cpuTimeMs);
|
||||
app.isAggregated = true;
|
||||
bs.add(app);
|
||||
}
|
||||
}
|
||||
if (bs.sumPower() > 0) {
|
||||
sippers.add(bs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
|
||||
final BatteryStats.ControllerActivityCounter counter = u.getBluetoothControllerActivity();
|
||||
@@ -63,8 +95,7 @@ public class BluetoothPowerCalculator extends PowerCalculator {
|
||||
mAppTotalTimeMs += totalTimeMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
final BatteryStats.ControllerActivityCounter counter =
|
||||
stats.getBluetoothControllerActivity();
|
||||
@@ -87,7 +118,7 @@ public class BluetoothPowerCalculator extends PowerCalculator {
|
||||
|
||||
if (DEBUG && powerMah != 0) {
|
||||
Log.d(TAG, "Bluetooth active: time=" + (totalTimeMs)
|
||||
+ " power=" + BatteryStatsHelper.makemAh(powerMah));
|
||||
+ " power=" + formatCharge(powerMah));
|
||||
}
|
||||
|
||||
app.bluetoothPowerMah = powerMah;
|
||||
|
||||
@@ -30,7 +30,7 @@ public class CameraPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
|
||||
// Calculate camera power usage. Right now, this is a (very) rough estimate based on the
|
||||
|
||||
@@ -30,7 +30,7 @@ public class CpuPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
|
||||
final int numClusters = mProfile.getNumCpuClusters();
|
||||
@@ -45,7 +45,7 @@ public class CpuPowerCalculator extends PowerCalculator {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
|
||||
+ speed + " timeUs=" + timeUs + " power="
|
||||
+ BatteryStatsHelper.makemAh(cpuSpeedStepPower / MICROSEC_IN_HR));
|
||||
+ formatCharge(cpuSpeedStepPower / MICROSEC_IN_HR));
|
||||
}
|
||||
cpuPowerMaUs += cpuSpeedStepPower;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ public class CpuPowerCalculator extends PowerCalculator {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + i + " clusterTimeUs="
|
||||
+ cpuClusterTimes[i] + " power="
|
||||
+ BatteryStatsHelper.makemAh(power / MICROSEC_IN_HR));
|
||||
+ formatCharge(power / MICROSEC_IN_HR));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -74,7 +74,7 @@ public class CpuPowerCalculator extends PowerCalculator {
|
||||
|
||||
if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power="
|
||||
+ BatteryStatsHelper.makemAh(app.cpuPowerMah));
|
||||
+ formatCharge(app.cpuPowerMah));
|
||||
}
|
||||
|
||||
// Keep track of the package with highest drain.
|
||||
|
||||
@@ -28,7 +28,7 @@ public class FlashlightPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
|
||||
// Calculate flashlight power usage. Right now, this is based on the average power draw
|
||||
|
||||
74
core/java/com/android/internal/os/IdlePowerCalculator.java
Normal file
74
core/java/com/android/internal/os/IdlePowerCalculator.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Estimates the amount of power consumed when the device is idle.
|
||||
*/
|
||||
public class IdlePowerCalculator extends PowerCalculator {
|
||||
private static final String TAG = "IdlePowerCalculator";
|
||||
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
|
||||
private final PowerProfile mPowerProfile;
|
||||
|
||||
public IdlePowerCalculator(PowerProfile powerProfile) {
|
||||
mPowerProfile = powerProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the baseline power usage for the device when it is in suspend and idle.
|
||||
* The device is drawing POWER_CPU_SUSPEND power at its lowest power state.
|
||||
* The device is drawing POWER_CPU_SUSPEND + POWER_CPU_IDLE power when a wakelock is held.
|
||||
*/
|
||||
@Override
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
long batteryUptimeUs = batteryStats.computeBatteryUptime(rawUptimeUs, statsType);
|
||||
long batteryRealtimeUs = batteryStats.computeBatteryRealtime(rawRealtimeUs, statsType);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Battery type time: realtime=" + (batteryRealtimeUs / 1000) + " uptime="
|
||||
+ (batteryUptimeUs / 1000));
|
||||
}
|
||||
|
||||
final double suspendPowerMaMs = (batteryRealtimeUs / 1000)
|
||||
* mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND);
|
||||
final double idlePowerMaMs = (batteryUptimeUs / 1000)
|
||||
* mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
|
||||
final double totalPowerMah = (suspendPowerMaMs + idlePowerMaMs) / (60 * 60 * 1000);
|
||||
if (DEBUG && totalPowerMah != 0) {
|
||||
Log.d(TAG, "Suspend: time=" + (batteryRealtimeUs / 1000)
|
||||
+ " power=" + formatCharge(suspendPowerMaMs / (60 * 60 * 1000)));
|
||||
Log.d(TAG, "Idle: time=" + (batteryUptimeUs / 1000)
|
||||
+ " power=" + formatCharge(idlePowerMaMs / (60 * 60 * 1000)));
|
||||
}
|
||||
|
||||
if (totalPowerMah != 0) {
|
||||
BatterySipper bs = new BatterySipper(BatterySipper.DrainType.IDLE, null, 0);
|
||||
bs.usagePowerMah = totalPowerMah;
|
||||
bs.usageTimeMs = batteryRealtimeUs / 1000;
|
||||
bs.sumPower();
|
||||
sippers.add(bs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public class MediaPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
// Calculate audio power usage, an estimate based on the average power routed to different
|
||||
// components like speaker, bluetooth, usb-c, earphone, etc.
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.android.internal.os;
|
||||
|
||||
import android.os.BatteryStats;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MemoryPowerCalculator extends PowerCalculator {
|
||||
|
||||
@@ -22,11 +26,17 @@ public class MemoryPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {}
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
BatterySipper memory = new BatterySipper(BatterySipper.DrainType.MEMORY, null, 0);
|
||||
calculateRemaining(memory, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
|
||||
memory.sumPower();
|
||||
if (memory.totalPowerMah > 0) {
|
||||
sippers.add(memory);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
double totalMah = 0;
|
||||
long totalTimeMs = 0;
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
package com.android.internal.os;
|
||||
|
||||
import android.os.BatteryStats;
|
||||
import android.os.UserHandle;
|
||||
import android.telephony.CellSignalStrength;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MobileRadioPowerCalculator extends PowerCalculator {
|
||||
private static final String TAG = "MobileRadioPowerController";
|
||||
private static final String TAG = "MobRadioPowerCalculator";
|
||||
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
|
||||
private final double mPowerRadioOn;
|
||||
private final double[] mPowerBins = new double[CellSignalStrength.getNumSignalStrengthLevels()];
|
||||
@@ -44,12 +48,12 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
|
||||
final long radioDataUptimeMs =
|
||||
mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
|
||||
final double mobilePps = (mobileData != 0 && radioDataUptimeMs != 0)
|
||||
? (mobileData / (double)radioDataUptimeMs)
|
||||
: (((double)MOBILE_BPS) / 8 / 2048);
|
||||
return (MOBILE_POWER / mobilePps) / (60*60);
|
||||
? (mobileData / (double) radioDataUptimeMs)
|
||||
: (((double) MOBILE_BPS) / 8 / 2048);
|
||||
return (MOBILE_POWER / mobilePps) / (60 * 60);
|
||||
}
|
||||
|
||||
public MobileRadioPowerCalculator(PowerProfile profile, BatteryStats stats) {
|
||||
public MobileRadioPowerCalculator(PowerProfile profile) {
|
||||
double temp =
|
||||
profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ACTIVE, -1);
|
||||
if (temp != -1) {
|
||||
@@ -64,7 +68,7 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
|
||||
temp = profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ON, -1);
|
||||
if (temp != -1 ) {
|
||||
if (temp != -1) {
|
||||
for (int i = 0; i < mPowerBins.length; i++) {
|
||||
mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i);
|
||||
}
|
||||
@@ -77,12 +81,25 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
|
||||
mPowerScan = profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_SCANNING, 0);
|
||||
mStats = stats;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
mStats = batteryStats;
|
||||
super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
|
||||
|
||||
BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
|
||||
calculateRemaining(radio, mStats, rawRealtimeUs, rawUptimeUs, statsType);
|
||||
radio.sumPower();
|
||||
if (radio.totalPowerMah > 0) {
|
||||
sippers.add(radio);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
// Add cost of mobile traffic.
|
||||
app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
|
||||
statsType);
|
||||
@@ -99,7 +116,7 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
|
||||
// We are tracking when the radio is up, so can use the active time to
|
||||
// determine power use.
|
||||
mTotalAppMobileActiveMs += app.mobileActive;
|
||||
app.mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000*60*60);
|
||||
app.mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000 * 60 * 60);
|
||||
} else {
|
||||
// We are not tracking when the radio is up, so must approximate power use
|
||||
// based on the number of packets.
|
||||
@@ -110,23 +127,22 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
|
||||
+ (app.mobileRxPackets + app.mobileTxPackets)
|
||||
+ " active time " + app.mobileActive
|
||||
+ " power=" + BatteryStatsHelper.makemAh(app.mobileRadioPowerMah));
|
||||
+ " power=" + formatCharge(app.mobileRadioPowerMah));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
double power = 0;
|
||||
long signalTimeMs = 0;
|
||||
long noCoverageTimeMs = 0;
|
||||
for (int i = 0; i < mPowerBins.length; i++) {
|
||||
long strengthTimeMs = stats.getPhoneSignalStrengthTime(i, rawRealtimeUs, statsType)
|
||||
/ 1000;
|
||||
final double p = (strengthTimeMs * mPowerBins[i]) / (60*60*1000);
|
||||
final double p = (strengthTimeMs * mPowerBins[i]) / (60 * 60 * 1000);
|
||||
if (DEBUG && p != 0) {
|
||||
Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
|
||||
+ BatteryStatsHelper.makemAh(p));
|
||||
+ formatCharge(p));
|
||||
}
|
||||
power += p;
|
||||
signalTimeMs += strengthTimeMs;
|
||||
@@ -137,16 +153,15 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
|
||||
|
||||
final long scanningTimeMs = stats.getPhoneSignalScanningTime(rawRealtimeUs, statsType)
|
||||
/ 1000;
|
||||
final double p = (scanningTimeMs * mPowerScan) / (60*60*1000);
|
||||
final double p = (scanningTimeMs * mPowerScan) / (60 * 60 * 1000);
|
||||
if (DEBUG && p != 0) {
|
||||
Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs
|
||||
+ " power=" + BatteryStatsHelper.makemAh(p));
|
||||
Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + formatCharge(p));
|
||||
}
|
||||
power += p;
|
||||
long radioActiveTimeMs = mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
|
||||
long remainingActiveTimeMs = radioActiveTimeMs - mTotalAppMobileActiveMs;
|
||||
if (remainingActiveTimeMs > 0) {
|
||||
power += (mPowerRadioOn * remainingActiveTimeMs) / (1000*60*60);
|
||||
power += (mPowerRadioOn * remainingActiveTimeMs) / (1000 * 60 * 60);
|
||||
}
|
||||
|
||||
if (power != 0) {
|
||||
@@ -162,10 +177,6 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
|
||||
@Override
|
||||
public void reset() {
|
||||
mTotalAppMobileActiveMs = 0;
|
||||
}
|
||||
|
||||
public void reset(BatteryStats stats) {
|
||||
reset();
|
||||
mStats = stats;
|
||||
mStats = null;
|
||||
}
|
||||
}
|
||||
|
||||
49
core/java/com/android/internal/os/PhonePowerCalculator.java
Normal file
49
core/java/com/android/internal/os/PhonePowerCalculator.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.UserHandle;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Estimates power consumed by telephony.
|
||||
*/
|
||||
public class PhonePowerCalculator extends PowerCalculator {
|
||||
private final PowerProfile mPowerProfile;
|
||||
|
||||
public PhonePowerCalculator(PowerProfile powerProfile) {
|
||||
mPowerProfile = powerProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, statsType) / 1000;
|
||||
double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
|
||||
* phoneOnTimeMs / (60 * 60 * 1000);
|
||||
if (phoneOnPower != 0) {
|
||||
BatterySipper bs = new BatterySipper(BatterySipper.DrainType.PHONE, null, 0);
|
||||
bs.usagePowerMah = phoneOnPower;
|
||||
bs.usageTimeMs = phoneOnTimeMs;
|
||||
bs.sumPower();
|
||||
sippers.add(bs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,44 @@
|
||||
package com.android.internal.os;
|
||||
|
||||
import android.os.BatteryStats;
|
||||
import android.os.UserHandle;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Calculates power use of a device subsystem for an app.
|
||||
*/
|
||||
public abstract class PowerCalculator {
|
||||
|
||||
/**
|
||||
* Attributes the total amount of power used by this subsystem to various consumers such
|
||||
* as apps.
|
||||
*
|
||||
* @param sippers A list of battery sippers that contains battery attribution data.
|
||||
* The calculator may modify the list.
|
||||
* @param batteryStats The recorded battery stats.
|
||||
* @param rawRealtimeUs The raw system realtime in microseconds.
|
||||
* @param rawUptimeUs The raw system uptime in microseconds.
|
||||
* @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this
|
||||
* can only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
|
||||
* {@link BatteryStats#STATS_CURRENT} and
|
||||
* {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
|
||||
* @param asUsers An array of users for which the attribution is requested. It may
|
||||
* contain {@link UserHandle#USER_ALL} to indicate that the attribution
|
||||
* should be performed for all users.
|
||||
*/
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
for (int i = sippers.size() - 1; i >= 0; i--) {
|
||||
final BatterySipper app = sippers.get(i);
|
||||
if (app.drainType == BatterySipper.DrainType.APP) {
|
||||
calculateApp(app, app.uidObj, rawRealtimeUs, rawUptimeUs, statsType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the amount of power an app used for this subsystem.
|
||||
* @param app The BatterySipper that represents the power use of an app.
|
||||
@@ -32,27 +65,43 @@ public abstract class PowerCalculator {
|
||||
* {@link BatteryStats#STATS_CURRENT} and
|
||||
* {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
|
||||
*/
|
||||
public abstract void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType);
|
||||
|
||||
/**
|
||||
* Calculate the remaining power that can not be attributed to an app.
|
||||
* @param app The BatterySipper that will represent this remaining power.
|
||||
* @param stats The BatteryStats object from which to retrieve data.
|
||||
* @param rawRealtimeUs The raw system realtime in microseconds.
|
||||
* @param rawUptimeUs The raw system uptime in microseconds.
|
||||
* @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this can
|
||||
* only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
|
||||
* {@link BatteryStats#STATS_CURRENT} and
|
||||
* {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
|
||||
*/
|
||||
public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
}
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {}
|
||||
|
||||
/**
|
||||
* Reset any state maintained in this calculator.
|
||||
*/
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts charge in mAh to string.
|
||||
*/
|
||||
public static String formatCharge(double power) {
|
||||
if (power == 0) return "0";
|
||||
|
||||
final String format;
|
||||
if (power < .00001) {
|
||||
format = "%.8f";
|
||||
} else if (power < .0001) {
|
||||
format = "%.7f";
|
||||
} else if (power < .001) {
|
||||
format = "%.6f";
|
||||
} else if (power < .01) {
|
||||
format = "%.5f";
|
||||
} else if (power < .1) {
|
||||
format = "%.4f";
|
||||
} else if (power < 1) {
|
||||
format = "%.3f";
|
||||
} else if (power < 10) {
|
||||
format = "%.2f";
|
||||
} else if (power < 100) {
|
||||
format = "%.1f";
|
||||
} else {
|
||||
format = "%.0f";
|
||||
}
|
||||
|
||||
// Use English locale because this is never used in UI (only in checkin and dump).
|
||||
return String.format(Locale.ENGLISH, format, power);
|
||||
}
|
||||
}
|
||||
|
||||
71
core/java/com/android/internal/os/ScreenPowerCalculator.java
Normal file
71
core/java/com/android/internal/os/ScreenPowerCalculator.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Estimates power consumed by the screen(s)
|
||||
*/
|
||||
public class ScreenPowerCalculator extends PowerCalculator {
|
||||
private static final String TAG = "ScreenPowerCalculator";
|
||||
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
|
||||
|
||||
private final PowerProfile mPowerProfile;
|
||||
|
||||
public ScreenPowerCalculator(PowerProfile powerProfile) {
|
||||
mPowerProfile = powerProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Screen power is the additional power the screen takes while the device is running.
|
||||
*/
|
||||
@Override
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
double power = 0;
|
||||
final long screenOnTimeMs = batteryStats.getScreenOnTime(rawRealtimeUs, statsType) / 1000;
|
||||
power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON);
|
||||
final double screenFullPower =
|
||||
mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
|
||||
for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
|
||||
final double screenBinPower = screenFullPower * (i + 0.5f)
|
||||
/ BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
|
||||
final long brightnessTime =
|
||||
batteryStats.getScreenBrightnessTime(i, rawRealtimeUs, statsType) / 1000;
|
||||
final double p = screenBinPower * brightnessTime;
|
||||
if (DEBUG && p != 0) {
|
||||
Log.d(TAG, "Screen bin #" + i + ": time=" + brightnessTime
|
||||
+ " power=" + formatCharge(p / (60 * 60 * 1000)));
|
||||
}
|
||||
power += p;
|
||||
}
|
||||
power /= (60 * 60 * 1000); // To hours
|
||||
if (power != 0) {
|
||||
final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.SCREEN, null, 0);
|
||||
bs.usagePowerMah = power;
|
||||
bs.usageTimeMs = screenOnTimeMs;
|
||||
bs.sumPower();
|
||||
sippers.add(bs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.android.internal.os;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.UserHandle;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.location.gnssmetrics.GnssMetrics;
|
||||
@@ -25,17 +26,24 @@ import com.android.internal.location.gnssmetrics.GnssMetrics;
|
||||
import java.util.List;
|
||||
|
||||
public class SensorPowerCalculator extends PowerCalculator {
|
||||
private final PowerProfile mPowerProfile;
|
||||
private final List<Sensor> mSensors;
|
||||
private final double mGpsPower;
|
||||
private double mGpsPower;
|
||||
|
||||
public SensorPowerCalculator(PowerProfile profile, SensorManager sensorManager,
|
||||
BatteryStats stats, long rawRealtimeUs, int statsType) {
|
||||
public SensorPowerCalculator(PowerProfile profile, SensorManager sensorManager) {
|
||||
mPowerProfile = profile;
|
||||
mSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
|
||||
mGpsPower = getAverageGpsPower(profile, stats, rawRealtimeUs, statsType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
mGpsPower = getAverageGpsPower(batteryStats, rawRealtimeUs, statsType);
|
||||
super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
// Process Sensor usage
|
||||
final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
|
||||
@@ -49,14 +57,14 @@ public class SensorPowerCalculator extends PowerCalculator {
|
||||
switch (sensorHandle) {
|
||||
case BatteryStats.Uid.Sensor.GPS:
|
||||
app.gpsTimeMs = sensorTime;
|
||||
app.gpsPowerMah = (app.gpsTimeMs * mGpsPower) / (1000*60*60);
|
||||
app.gpsPowerMah = (app.gpsTimeMs * mGpsPower) / (1000 * 60 * 60);
|
||||
break;
|
||||
default:
|
||||
final int sensorsCount = mSensors.size();
|
||||
for (int i = 0; i < sensorsCount; i++) {
|
||||
final Sensor s = mSensors.get(i);
|
||||
if (s.getHandle() == sensorHandle) {
|
||||
app.sensorPowerMah += (sensorTime * s.getPower()) / (1000*60*60);
|
||||
app.sensorPowerMah += (sensorTime * s.getPower()) / (1000 * 60 * 60);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -65,10 +73,10 @@ public class SensorPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
}
|
||||
|
||||
private double getAverageGpsPower(PowerProfile profile, BatteryStats stats, long rawRealtimeUs,
|
||||
private double getAverageGpsPower(BatteryStats stats, long rawRealtimeUs,
|
||||
int statsType) {
|
||||
double averagePower =
|
||||
profile.getAveragePowerOrDefault(PowerProfile.POWER_GPS_ON, -1);
|
||||
mPowerProfile.getAveragePowerOrDefault(PowerProfile.POWER_GPS_ON, -1);
|
||||
if (averagePower != -1) {
|
||||
return averagePower;
|
||||
}
|
||||
@@ -78,8 +86,9 @@ public class SensorPowerCalculator extends PowerCalculator {
|
||||
for (int i = 0; i < GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
|
||||
long timePerLevel = stats.getGpsSignalQualityTime(i, rawRealtimeUs, statsType);
|
||||
totalTime += timePerLevel;
|
||||
totalPower += profile.getAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i)
|
||||
* timePerLevel;
|
||||
totalPower +=
|
||||
mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i)
|
||||
* timePerLevel;
|
||||
}
|
||||
if (totalTime != 0) {
|
||||
averagePower = totalPower / totalTime;
|
||||
|
||||
@@ -17,9 +17,12 @@
|
||||
package com.android.internal.os;
|
||||
|
||||
import android.os.BatteryStats;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Estimates the amount of power consumed by the System Server handling requests from
|
||||
@@ -32,39 +35,40 @@ public class SystemServicePowerCalculator extends PowerCalculator {
|
||||
private static final long MICROSEC_IN_HR = (long) 60 * 60 * 1000 * 1000;
|
||||
|
||||
private final PowerProfile mPowerProfile;
|
||||
private final BatteryStats mBatteryStats;
|
||||
|
||||
// Tracks system server CPU [cluster][speed] power in milliAmp-microseconds
|
||||
// Data organized like this:
|
||||
// {cluster1-speed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...}
|
||||
private double[] mSystemServicePowerMaUs;
|
||||
|
||||
public SystemServicePowerCalculator(PowerProfile powerProfile, BatteryStats batteryStats) {
|
||||
public SystemServicePowerCalculator(PowerProfile powerProfile) {
|
||||
mPowerProfile = powerProfile;
|
||||
mBatteryStats = batteryStats;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType,
|
||||
SparseArray<UserHandle> asUsers) {
|
||||
updateSystemServicePower(batteryStats);
|
||||
super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
final double proportionalUsage = u.getProportionalSystemServiceUsage();
|
||||
if (proportionalUsage > 0) {
|
||||
if (mSystemServicePowerMaUs == null) {
|
||||
updateSystemServicePower();
|
||||
if (proportionalUsage > 0 && mSystemServicePowerMaUs != null) {
|
||||
double cpuPowerMaUs = 0;
|
||||
for (int i = 0; i < mSystemServicePowerMaUs.length; i++) {
|
||||
cpuPowerMaUs += mSystemServicePowerMaUs[i] * proportionalUsage;
|
||||
}
|
||||
|
||||
if (mSystemServicePowerMaUs != null) {
|
||||
double cpuPowerMaUs = 0;
|
||||
for (int i = 0; i < mSystemServicePowerMaUs.length; i++) {
|
||||
cpuPowerMaUs += mSystemServicePowerMaUs[i] * proportionalUsage;
|
||||
}
|
||||
|
||||
app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
|
||||
}
|
||||
app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSystemServicePower() {
|
||||
final long[] systemServiceTimeAtCpuSpeeds = mBatteryStats.getSystemServiceTimeAtCpuSpeeds();
|
||||
private void updateSystemServicePower(BatteryStats batteryStats) {
|
||||
final long[] systemServiceTimeAtCpuSpeeds = batteryStats.getSystemServiceTimeAtCpuSpeeds();
|
||||
if (systemServiceTimeAtCpuSpeeds == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
66
core/java/com/android/internal/os/UserPowerCalculator.java
Normal file
66
core/java/com/android/internal/os/UserPowerCalculator.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.SparseArray;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Computes power consumed by Users
|
||||
*/
|
||||
public class UserPowerCalculator extends PowerCalculator {
|
||||
|
||||
@Override
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
|
||||
if (forAllUsers) {
|
||||
return;
|
||||
}
|
||||
|
||||
SparseArray<BatterySipper> userSippers = new SparseArray<>();
|
||||
|
||||
for (int i = sippers.size() - 1; i >= 0; i--) {
|
||||
BatterySipper sipper = sippers.get(i);
|
||||
final int uid = sipper.getUid();
|
||||
final int userId = UserHandle.getUserId(uid);
|
||||
if (asUsers.get(userId) == null
|
||||
&& UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
|
||||
// We are told to just report this user's apps as one accumulated entry.
|
||||
BatterySipper userSipper = userSippers.get(userId);
|
||||
if (userSipper == null) {
|
||||
userSipper = new BatterySipper(BatterySipper.DrainType.USER, null, 0);
|
||||
userSipper.userId = userId;
|
||||
userSippers.put(userId, userSipper);
|
||||
}
|
||||
userSipper.add(sipper);
|
||||
sipper.isAggregated = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < userSippers.size(); i++) {
|
||||
BatterySipper sipper = userSippers.valueAt(i);
|
||||
if (sipper.sumPower() > 0) {
|
||||
sippers.add(sipper);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,12 @@
|
||||
package com.android.internal.os;
|
||||
|
||||
import android.os.BatteryStats;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WakelockPowerCalculator extends PowerCalculator {
|
||||
private static final String TAG = "WakelockPowerCalculator";
|
||||
@@ -30,8 +34,31 @@ public class WakelockPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
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);
|
||||
|
||||
// The device has probably been awake for longer than the screen on
|
||||
// time and application wake lock time would account for. Assign
|
||||
// this remainder to the OS, if possible.
|
||||
BatterySipper osSipper = null;
|
||||
for (int i = sippers.size() - 1; i >= 0; i--) {
|
||||
BatterySipper app = sippers.get(i);
|
||||
if (app.getUid() == 0) {
|
||||
osSipper = app;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (osSipper != null) {
|
||||
calculateRemaining(osSipper, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
|
||||
osSipper.sumPower();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
long wakeLockTimeUs = 0;
|
||||
final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
|
||||
u.getWakelockStats();
|
||||
@@ -50,24 +77,22 @@ public class WakelockPowerCalculator extends PowerCalculator {
|
||||
mTotalAppWakelockTimeMs += app.wakeLockTimeMs;
|
||||
|
||||
// Add cost of holding a wake lock.
|
||||
app.wakeLockPowerMah = (app.wakeLockTimeMs * mPowerWakelock) / (1000*60*60);
|
||||
app.wakeLockPowerMah = (app.wakeLockTimeMs * mPowerWakelock) / (1000 * 60 * 60);
|
||||
if (DEBUG && app.wakeLockPowerMah != 0) {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": wake " + app.wakeLockTimeMs
|
||||
+ " power=" + BatteryStatsHelper.makemAh(app.wakeLockPowerMah));
|
||||
+ " power=" + formatCharge(app.wakeLockPowerMah));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
long wakeTimeMillis = stats.getBatteryUptime(rawUptimeUs) / 1000;
|
||||
wakeTimeMillis -= mTotalAppWakelockTimeMs
|
||||
+ (stats.getScreenOnTime(rawRealtimeUs, statsType) / 1000);
|
||||
if (wakeTimeMillis > 0) {
|
||||
final double power = (wakeTimeMillis * mPowerWakelock) / (1000*60*60);
|
||||
final double power = (wakeTimeMillis * mPowerWakelock) / (1000 * 60 * 60);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power "
|
||||
+ BatteryStatsHelper.makemAh(power));
|
||||
Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power " + formatCharge(power));
|
||||
}
|
||||
app.wakeLockTimeMs += wakeTimeMillis;
|
||||
app.wakeLockPowerMah += power;
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* WiFi power calculator for when BatteryStats supports energy reporting
|
||||
@@ -28,18 +33,65 @@ public class WifiPowerCalculator extends PowerCalculator {
|
||||
private final double mIdleCurrentMa;
|
||||
private final double mTxCurrentMa;
|
||||
private final double mRxCurrentMa;
|
||||
private final PowerProfile mPowerProfile;
|
||||
private final boolean mHasWifiPowerController;
|
||||
private double mTotalAppPowerDrain = 0;
|
||||
private long mTotalAppRunningTime = 0;
|
||||
private WifiPowerEstimator mWifiPowerEstimator;
|
||||
private boolean mHasWifiPowerReporting;
|
||||
|
||||
public WifiPowerCalculator(PowerProfile profile) {
|
||||
mPowerProfile = profile;
|
||||
|
||||
mIdleCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE);
|
||||
mTxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX);
|
||||
mRxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX);
|
||||
|
||||
mHasWifiPowerController = mIdleCurrentMa != 0 && mTxCurrentMa != 0 && mRxCurrentMa != 0;
|
||||
mWifiPowerEstimator = new WifiPowerEstimator(mPowerProfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* We do per-app blaming of WiFi activity. If energy info is reported from the controller,
|
||||
* then only the WiFi process gets blamed here since we normalize power calculations and
|
||||
* assign all the power drain to apps. If energy info is not reported, we attribute the
|
||||
* difference between total running time of WiFi for all apps and the actual running time
|
||||
* of WiFi to the WiFi subsystem.
|
||||
*/
|
||||
@Override
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
|
||||
// batteryStats.hasWifiActivityReporting can change if we get energy data at a later point,
|
||||
// so always check this field.
|
||||
mHasWifiPowerReporting = 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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
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;
|
||||
@@ -53,7 +105,7 @@ public class WifiPowerCalculator extends PowerCalculator {
|
||||
|
||||
app.wifiPowerMah =
|
||||
((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa))
|
||||
/ (1000*60*60);
|
||||
/ (1000 * 60 * 60);
|
||||
mTotalAppPowerDrain += app.wifiPowerMah;
|
||||
|
||||
app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
|
||||
@@ -67,13 +119,18 @@ public class WifiPowerCalculator extends PowerCalculator {
|
||||
|
||||
if (DEBUG && app.wifiPowerMah != 0) {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime + "ms tx=" +
|
||||
txTime + "ms power=" + BatteryStatsHelper.makemAh(app.wifiPowerMah));
|
||||
txTime + "ms power=" + formatCharge(app.wifiPowerMah));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
if (!mHasWifiPowerReporting) {
|
||||
mWifiPowerEstimator.calculateRemaining(app, stats, rawRealtimeUs, rawUptimeUs,
|
||||
statsType);
|
||||
return;
|
||||
}
|
||||
|
||||
final BatteryStats.ControllerActivityCounter counter = stats.getWifiControllerActivity();
|
||||
|
||||
final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
|
||||
@@ -84,16 +141,16 @@ public class WifiPowerCalculator extends PowerCalculator {
|
||||
(idleTimeMs + rxTimeMs + txTimeMs) - mTotalAppRunningTime);
|
||||
|
||||
double powerDrainMah = counter.getPowerCounter().getCountLocked(statsType)
|
||||
/ (double)(1000*60*60);
|
||||
/ (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);
|
||||
+ (rxTimeMs * mRxCurrentMa)) / (1000 * 60 * 60);
|
||||
}
|
||||
app.wifiPowerMah = Math.max(0, powerDrainMah - mTotalAppPowerDrain);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "left over WiFi power: " + BatteryStatsHelper.makemAh(app.wifiPowerMah));
|
||||
Log.d(TAG, "left over WiFi power: " + formatCharge(app.wifiPowerMah));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,5 +158,6 @@ public class WifiPowerCalculator extends PowerCalculator {
|
||||
public void reset() {
|
||||
mTotalAppPowerDrain = 0;
|
||||
mTotalAppRunningTime = 0;
|
||||
mWifiPowerEstimator.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
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.
|
||||
@@ -37,6 +42,27 @@ public class WifiPowerEstimator extends PowerCalculator {
|
||||
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.
|
||||
*/
|
||||
@@ -48,7 +74,7 @@ public class WifiPowerEstimator extends PowerCalculator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
|
||||
statsType);
|
||||
@@ -79,13 +105,11 @@ public class WifiPowerEstimator extends PowerCalculator {
|
||||
|
||||
app.wifiPowerMah = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;
|
||||
if (DEBUG && app.wifiPowerMah != 0) {
|
||||
Log.d(TAG, "UID " + u.getUid() + ": power=" +
|
||||
BatteryStatsHelper.makemAh(app.wifiPowerMah));
|
||||
Log.d(TAG, "UID " + u.getUid() + ": power=" + formatCharge(app.wifiPowerMah));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
final long totalRunningTimeMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType)
|
||||
/ 1000;
|
||||
|
||||
@@ -33,6 +33,8 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class PowerCalculatorTest extends TestCase {
|
||||
@@ -61,11 +63,9 @@ public class PowerCalculatorTest extends TestCase {
|
||||
when(videoTimer.getTotalTimeLocked(2L * US_IN_HR, 0)).thenReturn(1L * US_IN_HR);
|
||||
|
||||
MediaPowerCalculator mediaPowerCalculator = new MediaPowerCalculator(mPowerProfile);
|
||||
BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, null, 0);
|
||||
BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
|
||||
|
||||
mediaPowerCalculator.calculateApp(app, u, 2L * US_IN_HR, 2L * US_IN_HR, 0);
|
||||
mediaPowerCalculator.calculate(List.of(app), null, 2L * US_IN_HR, 2L * US_IN_HR, 0, null);
|
||||
assertEquals(49.0, app.sumPower());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.junit.runner.RunWith;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -58,8 +59,7 @@ public class SystemServicePowerCalculatorTest {
|
||||
.setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader)
|
||||
.setUserInfoProvider(new MockUserInfoProvider());
|
||||
mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
|
||||
mSystemServicePowerCalculator =
|
||||
new SystemServicePowerCalculator(mProfile, mMockBatteryStats);
|
||||
mSystemServicePowerCalculator = new SystemServicePowerCalculator(mProfile);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -105,14 +105,12 @@ public class SystemServicePowerCalculatorTest {
|
||||
|
||||
BatterySipper app1 = new BatterySipper(BatterySipper.DrainType.APP,
|
||||
mMockBatteryStats.getUidStatsLocked(workSourceUid1), 0);
|
||||
mSystemServicePowerCalculator.calculateApp(app1, app1.uidObj, 0, 0,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
assertEquals(0.00016269, app1.systemServiceCpuPowerMah, 0.0000001);
|
||||
|
||||
BatterySipper app2 = new BatterySipper(BatterySipper.DrainType.APP,
|
||||
mMockBatteryStats.getUidStatsLocked(workSourceUid2), 0);
|
||||
mSystemServicePowerCalculator.calculateApp(app2, app2.uidObj, 0, 0,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
mSystemServicePowerCalculator.calculate(List.of(app1, app2), mMockBatteryStats, 0, 0,
|
||||
BatteryStats.STATS_SINCE_CHARGED, null);
|
||||
|
||||
assertEquals(0.00016269, app1.systemServiceCpuPowerMah, 0.0000001);
|
||||
assertEquals(0.00146426, app2.systemServiceCpuPowerMah, 0.0000001);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user