Android Performance Test-API for Power Consumption Statistics
Power Consumption API
AndroidThe system has been using power for a long time.API, But it is always hidden,AndroidSystemSettings-battery FunctionThis isAPI,APIThe core partcom.android.internal.os.BatteryStatsHelperClass, usePowerProfileClass, readpower_profile.xmlFile, let's take a look at how to calculate the power consumption, first from the latest version 6.0
API source code 6.0
BatteryStatsHelper
The method for calculating power consumption is 490 rowsprocessAppUsageTo explain the method step by step.
Power Consumption Calculation
private void processAppUsage(SparseArray
asUsers) {
The method parameter isSparseArrayArray, the stored object isUserHandleThe official documentation provides an explanation that represents a user and can be understood as storing user-related information in this class.
final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
Then, determine whether the calculation target all users.UserHandleOfUSER_ALLValue. The value is-1, Source Code address in https://github.com/DoctorQ/platform_frameworks_base/blob/android-6.0.0_r1/core/java/android/ OS /UserHandle.java.
mStatsPeriod = mTypeBatteryRealtime;
ThenmStatsPeriodAssign value. This valuemTypeBatteryRealtimeThe calculation process is in the 320 rowsrefreshStatsMethod:
mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
Here we useBatteryStats(mStats)ClasscomputeBatteryRealtimeMethod, which calculates the time interval of the current electric statistics. Okay, go back to the building.BatteryStatsHelper.
BatterySipper osSipper = null;final SparseArray
uidStats = mStats.getUidStats();final int NU = uidStats.size();
First, createBatterySipperObjectosSipperThis object can store some values that we will calculate later, and thenBatteryStatsClass ObjectmStatsTo obtainUidObjectSparseArrayThe number of groups. Then, the size of the array is calculated and saved in the variable NU.
for (int iu = 0; iu < NU; iu++) {final Uid u = uidStats.valueAt(iu); final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
ThenforCalculate eachUidRepresentedAppBecauseBatterySipperThere are three types of Computing: application, system service, and hardware.DrainType.APPAnd other optional types are as follows:
public enum DrainType { IDLE, CELL, PHONE, WIFI, BLUETOOTH, FLASHLIGHT, SCREEN, APP, USER, UNACCOUNTED, OVERCOUNTED, CAMERA }
Lists the modules that can calculate power consumption.
mCpuPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mWakelockPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mWifiPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mSensorPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mCameraPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
WheremStatsTypeIsBatteryStats.STATS_SINCE_CHARGEDIt indicates that our calculation rule is data from the last time the power is fully loaded. Another rule is:STATS_SINCE_UNPLUGGEDIs the data after the USB cable is unplugged. WhilemRawRealtimeIs the current time,mRawUptimeIs the running time. 6.0 of the consumption of each module is assigned to a separate class for computing. These classes are inherited fromPowerCalculatorAbstract class:
Bluetooth Power Consumption: descrithpowercalculator. java Camera power consumption: CameraPowerCalculator. javaCpu Power Consumption: CpuPowerCalculator. java flashlight Power Consumption: FlashlightPowerCalculator. java radio Power Consumption: MobileRadioPowerCalculator. java sensor power consumption: SensorPowerCalculator. javaWakelock Power Consumption: WakelockPowerCalculator. javaWifi Power Consumption: WifiPowerCalculator. java
I will explain this part separately. Now let's go backBatteryStatsHelperContinue
final double totalPower = app.sumPower();
BatterySipper#sumPowerThe method is to calculate the total power consumption. The method details are as follows, whereusagePowerMahThis value is a bit special, as described above.
/** * Sum all the powers and store the value into `value`. * @return the sum of all the power in this BatterySipper. */ public double sumPower() { return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah + flashlightPowerMah; }
Then print the information based on whether the DEBUG version is used. There is nothing to say about this. Then, the calculated electrical value will be added to the list:
// 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
list = mUserSippers.get(userId); if (list == null) { list = new ArrayList<>(); mUserSippers.put(userId, list); } list.add(app); } else { mUsageList.add(app); } if (uid == 0) { osSipper = app; } }
First, JudgetotalPowerAnd the currentUidWhether the rule is met. The rule is that the total power consumption is not 0 or the user ID is 0. WhenuidIt indicates that when it is WIFI or Bluetooth, it is added to the corresponding list below. Normally, the normal application is saved directly to the followingmUsageListBut there are some exceptions:
/** * List of apps using power. */ private final List
mUsageList = new ArrayList<>(); /** * List of apps using wifi power. */ private final List
mWifiSippers = new ArrayList<>(); /** * List of apps using bluetooth power. */ private final List
mBluetoothSippers = new ArrayList<>();
If our system is a single-user system and the currentuserIdNo. Is out of our statistical scope and its ProcessidNumber is greaterProcess.FIRST_APPLICATION_UID(10000, the actual ID number assigned by the system to a common application), we need to save itmUserSippersThe array is defined as follows:
private final SparseArray
> mUserSippers = new SparseArray<>();
Final judgmentuidIf it is 0, it indicatesAndroidThe power consumption of the operating system is assignedosSipper(494 rows ).appThe calculation is complete, and the traversal part is not mentioned. Save thisosSipperIt is for the last step of Computing:
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, mRawRealtime, mRawUptime, mStatsType); osSipper.sumPower(); }
The main process has been introduced. The following describes the power consumption calculation of each sub-module.
Cpu power consumption
CpuPowerCalculator. java
The PowerProfile class is used for Cpu computing. This class is mainly used to parse power_profile.xml:
0
0.1
0.1
0.1
0.1
0.1
0.1
0.1
0.1
0.1
0.1
0.1
0.1
0.1
0.1
0.2
0.1
400000
0.1
0.1
1000
.0002
.002
.02
.2
2
The Cpu (cpu. speeds) clock speed level is stored in the memory, and the memory (cpu. active) consumed per second for each clock speed.CpuPowerCalculator, First look at the constructor
public CpuPowerCalculator(PowerProfile profile) { final int speedSteps = profile.getNumSpeedSteps(); mPowerCpuNormal = new double[speedSteps]; mSpeedStepTimes = new long[speedSteps]; for (int p = 0; p < speedSteps; p++) { mPowerCpuNormal[p] = profile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p); } }
The first step is to obtain several clock speed levels for the Cpu. Because the power consumed by different levels is different, we need to treat them differently. According to the number of clock speed, then initializemPowerCpuNormalAndmSpeedStepTimesThe former is used to save the power consumption speed of different levels, the latter is used to save the time consumption of different levels, and thenmPowerCpuNormalValue attached to each element. The constructor completes all of its work.calculateApp,
final int speedSteps = mSpeedStepTimes.length; long totalTimeAtSpeeds = 0; for (int step = 0; step < speedSteps; step++) { mSpeedStepTimes[step] = u.getTimeAtCpuSpeed(step, statsType); totalTimeAtSpeeds += mSpeedStepTimes[step]; } totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
FirstCpuNumber of clock speed levels, and thenBatteryStats.UidObtain the execution time at different clock frequencies and calculateCpuThe total time consumed is stored intotalTimeAtSpeedsMedium,
app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
CpuThe execution time is divided into many parts, but we pay attentionUserAndKernalPart, that is, the aboveSystemCpuTime,