/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.os; import android.os.BatteryStats; import android.util.Log; /** * Estimates WiFi power usage based on timers in BatteryStats. */ public class WifiPowerEstimator extends PowerCalculator { private static final boolean DEBUG = BatteryStatsHelper.DEBUG; private static final String TAG = "WifiPowerEstimator"; private final double mWifiPowerPerPacket; private final double mWifiPowerOn; private final double mWifiPowerScan; private final double mWifiPowerBatchScan; private long mTotalAppWifiRunningTimeMs = 0; public WifiPowerEstimator(PowerProfile profile) { mWifiPowerPerPacket = getWifiPowerPerPacket(profile); mWifiPowerOn = profile.getAveragePower(PowerProfile.POWER_WIFI_ON); mWifiPowerScan = profile.getAveragePower(PowerProfile.POWER_WIFI_SCAN); mWifiPowerBatchScan = profile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN); } /** * Return estimated power (in mAs) of sending a byte with the Wi-Fi radio. */ private static double getWifiPowerPerPacket(PowerProfile profile) { final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system final double WIFI_POWER = profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE) / 3600; return (WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048)) / (60*60); } @Override 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; if (DEBUG && app.wifiPowerMah != 0) { Log.d(TAG, "UID " + u.getUid() + ": power=" + BatteryStatsHelper.makemAh(app.wifiPowerMah)); } } @Override public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, long rawUptimeUs, int statsType) { final long totalRunningTimeMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType) / 1000; final double powerDrain = ((totalRunningTimeMs - mTotalAppWifiRunningTimeMs) * mWifiPowerOn) / (1000*60*60); app.wifiRunningTimeMs = totalRunningTimeMs; app.wifiPowerMah = Math.max(0, powerDrain); } @Override public void reset() { mTotalAppWifiRunningTimeMs = 0; } }