Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android耗電統計算法代碼

Android耗電統計算法代碼

編輯:關於Android編程

一、 概述
Android系統中的耗電統計分為軟件排行榜和硬件排行榜,軟件排序榜是統計每個App的耗電總量的排行榜,硬件排行榜則是統計主要硬件的耗電總量的排行榜。

涉及耗電統計相關的核心類:

/framework/base/core/res/res/xml/power_profile.xml
/framework/base/core/java/com/andorid/internal/os/PowerProfile.java
/framework/base/core/java/com/andorid/internal/os/BatteryStatsHelper.java
/framework/base/core/java/com/andorid/internal/os/BatterySipper.java

PowerProfile.java用於獲取各個組件的電流數值;power_profile.xml是一個可配置的功耗數據文件。
軟件排行榜的計算算法:BatteryStatsHelper類中的processAppUsage()方法
硬件排行榜的計算算法:BatteryStatsHelper類中的processMiscUsage()方法
下面直接切入主題,分別講述軟件和硬件的耗電統計

二、軟件排行榜
processAppUsage統計每個App的耗電情況

private void processAppUsage(SparseArray<UserHandle> asUsers) {
//判斷是否統計所有用戶的App耗電使用情況,目前該參數為true
final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
mStatsPeriod = mTypeBatteryRealtime; //耗電的統計時長
BatterySipper osSipper = null;

//獲取每個uid的統計信息
final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
final int NU = uidStats.size();
// 開始遍歷每個uid的耗電情況
for (int iu = 0; iu < NU; iu++) {
final Uid u = uidStats.valueAt(iu);
final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
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);

final double totalPower = app.sumPower(); //對App的8項耗電再進行累加。

//將app添加到 app list, WiFi, Bluetooth等,或其他用戶列表
if (totalPower != 0 || u.getUid() == 0) {

final int uid = app.getUid();
final int userId = UserHandle.getUserId(uid);
if (uid == Process.WIFI_UID) { //uid為wifi的情況
mWifiSippers.add(app);
} else if (uid == Process.BLUETOOTH_UID) {//uid為藍牙的情況
mBluetoothSippers.add(app);
} else if (!forAllUsers && asUsers.get(userId) == null
&& UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
//就目前來說 forAllUsers=true,不會進入此分支。
List<BatterySipper> list = mUserSippers.get(userId);
if (list == null) {
list = new ArrayList<>();
mUserSippers.put(userId, list);
}
list.add(app);
} else {
mUsageList.add(app); //把app耗電加入到mUsageList
}
if (uid == 0) {
osSipper = app; // root用戶,代表操作系統的耗電量
}
}
}
//app之外的耗電量
if (osSipper != null) {
mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtime, mRawUptime, mStatsType);
osSipper.sumPower();
}
}

流程分析:

mTypeBatteryRealtime

mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;

BatteryStats.STATS_SINCE_CHARGED,計算規則是從上次充滿電後數據;另外STATS_SINCE_UNPLUGGED是拔掉USB線後的數據。說明充電時間的計算是從上一次拔掉設備到現在的耗電量統計。

耗電計算項

8大模塊的耗電計算器,都繼承與PowerCalculator抽象類

計算項 Class文件
CPU功耗 mCpuPowerCalculator.java
Wakelock功耗 mWakelockPowerCalculator.java
無線電功耗 mMobileRadioPowerCalculator.java
WIFI功耗 mWifiPowerCalculator.java
藍牙功耗 mBluetoothPowerCalculator.java
Sensor功耗 mSensorPowerCalculator.java
相機功耗 mCameraPowerCalculator.java
閃光燈功耗 mFlashlightPowerCalculator.java

計算值添加到列表

mWifiSippers.add(app): uid為wifi的情況
mBluetoothSippers.add(app): uid為藍牙的情況
mUsageList.add(app): app耗電加入到mUsageList
osSipper: root用戶,代表操作系統的耗電量,app之外的wakelock耗電也計算該項
公式

processAppUsage統計的是Uid。一般地來說每個App都對應一個Uid,但存在以下特殊情況,如果兩個或多個App簽名和sharedUserId相同,則在運行時,他們擁有相同Uid。對於系統應用uid為system,則統一算入system應用的耗電量。

Uid_Power = process_1_Power + … + process_N_Power,其中所有進程都是屬於同一個uid。 當同一的uid下,只有一個進程時,Uid_Power = process_Power;

其中process_Power = CPU功耗 + Wakelock功耗 + 無線電功耗 + WIFI功耗 + 藍牙功耗 + Sensor功耗 + 相機功耗 + 閃光燈功耗。

接下來開始分配說明每一項的功耗計算公式。

2.1 CPU
CPU功耗項的計算是通過CpuPowerCalculator類

初始化

public CpuPowerCalculator(PowerProfile profile) {
final int speedSteps = profile.getNumSpeedSteps(); //獲取cpu的主頻等級的級數
mPowerCpuNormal = new double[speedSteps]; //用於記錄不同頻率下的功耗值
mSpeedStepTimes = new long[speedSteps];
for (int p = 0; p < speedSteps; p++) {
mPowerCpuNormal[p] = profile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p);
}
}

從對象的構造方法,可以看出PowerProfile類提供相應所需的基礎功耗值,而真正的功耗值數據來源於power_profile.xml文件,故可以通過配置合理的基礎功耗值,來達到較為精准的功耗統計結果。後續所有的PowerCalculator子類在構造方法中都有會相應所需的功耗配置項。

CPU功耗可配置項:

POWER_CPU_SPEEDS = “cpu.speeds” 所對應的數組,配置CPU的頻點,頻點個數取決於CPU硬件特性
POWER_CPU_ACTIVE = “cpu.active” 所對應的數組,配置CPU頻點所對應的單位功耗(mAh)
功耗計算

public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
final int speedSteps = mSpeedStepTimes.length;
long totalTimeAtSpeeds = 0;
for (int step = 0; step < speedSteps; step++) {
//獲取Cpu不同頻點下的運行時間
mSpeedStepTimes[step] = u.getTimeAtCpuSpeed(step, statsType);
totalTimeAtSpeeds += mSpeedStepTimes[step];
}
totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1); //獲取Cpu總共的運行時間
app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000; //獲取cpu在用戶態和內核態的執行時長

double cpuPowerMaMs = 0;
// 計算Cpu的耗電量
for (int step = 0; step < speedSteps; step++) {
final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds;
final double cpuSpeedStepPower = ratio * app.cpuTimeMs * mPowerCpuNormal[step];
cpuPowerMaMs += cpuSpeedStepPower;
}

//追蹤不同進程的耗電情況
double highestDrain = 0;
app.cpuFgTimeMs = 0;
final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
final int processStatsCount = processStats.size();
//統計同一個uid的不同進程的耗電情況
for (int i = 0; i < processStatsCount; i++) {
final BatteryStats.Uid.Proc ps = processStats.valueAt(i);
final String processName = processStats.keyAt(i);
app.cpuFgTimeMs += ps.getForegroundTime(statsType);
final long costValue = ps.getUserTime(statsType) + ps.getSystemTime(statsType) + ps.getForegroundTime(statsType);
//App可以有多個packages和多個不同的進程,跟蹤耗電最大的進程
if (app.packageWithHighestDrain == null ||
app.packageWithHighestDrain.startsWith("*")) {
highestDrain = costValue;
app.packageWithHighestDrain = processName;
} else if (highestDrain < costValue && !processName.startsWith("*")) {
highestDrain = costValue;
app.packageWithHighestDrain = processName;
}
}
//當Cpu前台時間 大於Cpu時間,將cpuFgTimeMs賦值為cpuTimeMs
if (app.cpuFgTimeMs > app.cpuTimeMs) {
app.cpuTimeMs = app.cpuFgTimeMs;
}

app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000); //轉換為mAh
}
}

子公式

cpuPower = ratio_1 * cpu_time * cpu_ratio_1_power + … +ratio_n * cpu_time * cpu_ratio_n_power

其中: ratio_i = cpu_speed_time/ cpu_speeds_total_time,(i=1,2,…,N,N為CPU頻點個數)

2.2 Wakelock
Wakelock功耗項的計算是通過WakelockPowerCalculator類

初始化

public WakelockPowerCalculator(PowerProfile profile) {
mPowerWakelock = profile.getAveragePower(PowerProfile.POWER_CPU_AWAKE);
}

Wakelock功耗可配置項:

power_profile.xml文件:

POWER_CPU_AWAKE = “cpu.awake” 所對應的值
功耗計算

public 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();
final int wakelockStatsCount = wakelockStats.size();
for (int i = 0; i < wakelockStatsCount; i++) {
final BatteryStats.Uid.Wakelock wakelock = wakelockStats.valueAt(i);
//只統計partial wake locks,由於 full wake locks在滅屏後會自動取消
BatteryStats.Timer timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
if (timer != null) {
wakeLockTimeUs += timer.getTotalTimeLocked(rawRealtimeUs, statsType);
}
}
app.wakeLockTimeMs = wakeLockTimeUs / 1000; //轉換單位為秒
mTotalAppWakelockTimeMs += app.wakeLockTimeMs;
//計算喚醒功耗
app.wakeLockPowerMah = (app.wakeLockTimeMs * mPowerWakelock) / (1000*60*60);
}

子公式

wakeLockPowerMah = (app.wakeLockTimeMs * mPowerWakelock) / (10006060);

2.3 Wifi
WifiPowerCalculator
Wifi功耗項的計算是通過WifiPowerCalculator類

初始化

public WifiPowerCalculator(PowerProfile 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);
}

Wifi功耗可配置項:

POWER_WIFI_CONTROLLER_IDLE = “wifi.controller.idle” 項所對應的值
POWER_WIFI_CONTROLLER_RX = “wifi.controller.rx” 項所對應的值
POWER_WIFI_CONTROLLER_TX = “wifi.controller.tx” 項所對應的值
功耗計算

public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
final long idleTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_IDLE_TIME, statsType);
final long txTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_TX_TIME, statsType);
final long rxTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_RX_TIME, statsType);
app.wifiRunningTimeMs = idleTime + rxTime + txTime; //計算wifi的時間
app.wifiPowerMah = ((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa)) / (1000*60*60);
mTotalAppPowerDrain += app.wifiPowerMah;
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);
}

子公式

wifiPowerMah = ((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa)) / (1000* 60* 60);

WifiPowerEstimator
可配置項

POWER_WIFI_ACTIVE = “wifi.active”(用於計算mWifiPowerPerPacket)
POWER_WIFI_ON=”wifi.on”
POWER_WIFI_SCAN = “wifi.scan”
POWER_WIFI_BATCHED_SCAN = “wifi.batchedscan”;
功耗計算-

public 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;
}

其中 BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS=5

另外

private static double getWifiPowerPerPacket(PowerProfile profile) {
final long WIFI_BPS = 1000000; //初略估算每秒的收發1000000bit
final double WIFI_POWER = profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE)
/ 3600;
return (WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048)) / (60*60);
}

子公式

wifiPowerMah = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;

wifiPacketPower = (wifiRxPackets + wifiTxPackets) * mWifiPowerPerPacket; wifiLockPower = (wifiRunningTimeMs * mWifiPowerOn) / (1000* 60* 60); wifiScanPower = (wifiScanTimeMs * mWifiPowerScan) / (1000* 60* 60);

wifiBatchScanPower = ∑ (batchScanTimeMs * mWifiPowerBatchScan) / (1000* 60* 60) ,5次相加。

2.4 Bluetooth
Bluetooth功耗項的計算是通過BluetoothPowerCalculator類

初始化

public BluetoothPowerCalculator(PowerProfile profile) {
mIdleMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE);
mRxMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX);
mTxMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX);
}

Bluetooth功耗可配置項(目前藍牙功耗計算的方法為空,此配置暫可忽略):

POWER_BLUETOOTH_CONTROLLER_IDLE = “bluetooth.controller.idle” 所對應的值
POWER_BLUETOOTH_CONTROLLER_RX = “bluetooth.controller.rx” 所對應的值
POWER_BLUETOOTH_CONTROLLER_TX = “bluetooth.controller.tx” 所對應的值
功耗計算

public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
// No per-app distribution yet.
}

子公式

bluePower = 0;

還沒有給每個App統計藍牙的算法。

2.5 Camera
Camera功耗項的計算是通過CameraPowerCalculator類

初始化

public CameraPowerCalculator(PowerProfile profile) {
mCameraPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_CAMERA);
}

Camera功耗可配置項:

POWER_CAMERA = “camera.avg” 所對應的值
功耗計算

public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
//對於camera功耗的評估比較粗,camera打開認定功耗一致
final BatteryStats.Timer timer = u.getCameraTurnedOnTimer();
if (timer != null) {
final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
app.cameraTimeMs = totalTime;
app.cameraPowerMah = (totalTime * mCameraPowerOnAvg) / (1000*60*60);
} else {
app.cameraTimeMs = 0;
app.cameraPowerMah = 0;
}
}

子公式

cameraPowerMah = (totalTime * mCameraPowerOnAvg) / (10006060);

2.6 Flashlight
Flashlight功耗項的計算是通過FlashlightPowerCalculator類

初始化

public FlashlightPowerCalculator(PowerProfile profile) {
mFlashlightPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_FLASHLIGHT);
}

Flashlight功耗可配置項:

POWER_FLASHLIGHT = “camera.flashlight” 所對應的值
功耗計算

public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
final BatteryStats.Timer timer = u.getFlashlightTurnedOnTimer();
if (timer != null) {
final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
app.flashlightTimeMs = totalTime;
app.flashlightPowerMah = (totalTime * mFlashlightPowerOnAvg) / (1000*60*60);
} else {
app.flashlightTimeMs = 0;
app.flashlightPowerMah = 0;
}
}

子公式

flashlightPowerMah = (totalTime * mFlashlightPowerOnAvg) / (10006060);

flashlight計算方式與Camera功耗計算思路一樣。

2.7 MobileRadio
無線電功耗項的計算是通過MobileRadioPowerCalculator類

初始化

public MobileRadioPowerCalculator(PowerProfile profile, BatteryStats stats) {
mPowerRadioOn = profile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE);
for (int i = 0; i < mPowerBins.length; i++) {
mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i);
}
mPowerScan = profile.getAveragePower(PowerProfile.POWER_RADIO_SCANNING);
mStats = stats;
}

無線電功耗可配置項:

POWER_RADIO_ACTIVE = “radio.active” 所對應的值
功耗計算

public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA, statsType);
app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA, statsType);
app.mobileActive = u.getMobileRadioActiveTime(statsType) / 1000;
app.mobileActiveCount = u.getMobileRadioActiveCount(statsType);
app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
statsType);
app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
statsType);
if (app.mobileActive > 0) {
// 當追蹤信號的開頭,則采用mobileActive時間乘以相應功耗
mTotalAppMobileActiveMs += app.mobileActive;
app.mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000*60*60);
} else {
//當沒有追蹤信號開關,則采用收發數據包來評估功耗
app.mobileRadioPowerMah = (app.mobileRxPackets + app.mobileTxPackets) * getMobilePowerPerPacket(rawRealtimeUs, statsType);
}
}

計算出每收/發一個數據包的功耗值

private double getMobilePowerPerPacket(long rawRealtimeUs, int statsType) {
final long MOBILE_BPS = 200000; //Extract average bit rates from system
final double MOBILE_POWER = mPowerRadioOn / 3600;
final long mobileRx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
statsType);
final long mobileTx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
statsType);
final long mobileData = mobileRx + mobileTx;
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);
}

子公式

情況一:當追蹤信號活動時間,即mobileActive > 0,采用:

mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000* 60* 60);

情況二:當沒有追蹤信號活動時間,則采用:

mobileRadioPowerMah = (app.mobileRxPackets + app.mobileTxPackets) * MobilePowerPerPacket

其中MobilePowerPerPacket = ((mPowerRadioOn / 3600) / mobilePps) / (60*60), mobilePps= (mobileRx + mobileTx)/radioDataUptimeMs

2.8 Sensor
Sensor功耗項的計算是通過SensorPowerCalculator類

初始化

public SensorPowerCalculator(PowerProfile profile, SensorManager sensorManager) {
mSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
mGpsPowerOn = profile.getAveragePower(PowerProfile.POWER_GPS_ON);
}

Sensor功耗可配置項:

POWER_GPS_ON = “gps.on” 所對應的值
功耗計算

d calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, int statsType) {
// 計算沒有個Uid
final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
final int NSE = sensorStats.size();
for (int ise = 0; ise < NSE; ise++) {
final BatteryStats.Uid.Sensor sensor = sensorStats.valueAt(ise);
final int sensorHandle = sensorStats.keyAt(ise);
final BatteryStats.Timer timer = sensor.getSensorTime();
final long sensorTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
switch (sensorHandle) {
case BatteryStats.Uid.Sensor.GPS: //對於uid為GPS的情況
app.gpsTimeMs = sensorTime;
app.gpsPowerMah = (app.gpsTimeMs * mGpsPowerOn) / (1000*60*60);
break;
default:
final int sensorsCount = mSensors.size();
for (int i = 0; i < sensorsCount; i++) { //統計所有的sensor情況
final Sensor s = mSensors.get(i);
if (s.getHandle() == sensorHandle) {
app.sensorPowerMah += (sensorTime * s.getPower()) / (1000*60*60);
break;
}
}
break;
}
}
}

GPS的功耗計算與sensor的計算方法放在一塊

子公式

gpsPowerMah = (app.gpsTimeMs * mGpsPowerOn) / (1000* 60* 60);

軟件功耗總公式
BatterySipper中,功耗計算方法:

public double sumPower() {
return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah +
sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah +
flashlightPowerMah;
}

軟件功耗的子項共分為9項:

功耗項 解釋
usage 通用的功耗
cpu cpu的消耗
wakelock 喚醒帶來的功耗
mobileRadio 移動無線的功耗
wifi wifi功耗
gps 定位的功耗
sensor 傳感器的功耗
camera 相機功耗
flashlight 閃光燈功耗

目前沒有統計藍牙的耗電,源碼中統計藍牙耗電的方法是空方法。gps耗電的計算在sensor模塊一起計算的。

軟件功耗總公式

calculate_software_power

三、 硬件排行榜
processMiscUsage()

private void processMiscUsage() {
addUserUsage();
addPhoneUsage();
addScreenUsage();
addWiFiUsage();
addBluetoothUsage();
addIdleUsage();
if (!mWifiOnly) { //對於只有wifi上網功能的設備,將不算計此項
addRadioUsage();
}
}

硬件功耗的子項共分為7項:

功耗項 解釋
UserUsage 用戶功耗
PhoneUsage 通話功耗
ScreenUsage 屏幕功耗
WiFiUsage Wifi功耗
BluetoothUsage 藍牙消耗
IdleUsage CPU Idle功耗
RadioUsage 移動無線功耗

3.1 User
用戶功耗的類型DrainType.USER

功耗計算

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"); //將UserSippers中的功耗都合入bs.
mUsageList.add(bs);
}
}

合計

private void aggregateSippers(BatterySipper bs, List<BatterySipper> from, String tag) {
for (int i=0; i<from.size(); i++) {
BatterySipper wbs = from.get(i);
bs.add(wbs); //將from中的功耗數據合入bs
}
bs.computeMobilemspp();
bs.sumPower(); //計算總功耗
}

子公式

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved