1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.internal.os;
17
18import android.os.BatteryStats;
19import android.util.Log;
20
21/**
22 * Estimates WiFi power usage based on timers in BatteryStats.
23 */
24public class WifiPowerEstimator extends PowerCalculator {
25    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
26    private static final String TAG = "WifiPowerEstimator";
27    private final double mWifiPowerPerPacket;
28    private final double mWifiPowerOn;
29    private final double mWifiPowerScan;
30    private final double mWifiPowerBatchScan;
31    private long mTotalAppWifiRunningTimeMs = 0;
32
33    public WifiPowerEstimator(PowerProfile profile) {
34        mWifiPowerPerPacket = getWifiPowerPerPacket(profile);
35        mWifiPowerOn = profile.getAveragePower(PowerProfile.POWER_WIFI_ON);
36        mWifiPowerScan = profile.getAveragePower(PowerProfile.POWER_WIFI_SCAN);
37        mWifiPowerBatchScan = profile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN);
38    }
39
40    /**
41     * Return estimated power per Wi-Fi packet in mAh/packet where 1 packet = 2 KB.
42     */
43    private static double getWifiPowerPerPacket(PowerProfile profile) {
44        final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system
45        final double WIFI_POWER = profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE)
46                / 3600;
47        return WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048);
48    }
49
50    @Override
51    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
52                             long rawUptimeUs, int statsType) {
53        app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
54                statsType);
55        app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
56                statsType);
57        app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
58                statsType);
59        app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
60                statsType);
61
62        final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets)
63                * mWifiPowerPerPacket;
64
65        app.wifiRunningTimeMs = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
66        mTotalAppWifiRunningTimeMs += app.wifiRunningTimeMs;
67        final double wifiLockPower = (app.wifiRunningTimeMs * mWifiPowerOn) / (1000*60*60);
68
69        final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
70        final double wifiScanPower = (wifiScanTimeMs * mWifiPowerScan) / (1000*60*60);
71
72        double wifiBatchScanPower = 0;
73        for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
74            final long batchScanTimeMs =
75                    u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000;
76            final double batchScanPower = (batchScanTimeMs * mWifiPowerBatchScan) / (1000*60*60);
77            wifiBatchScanPower += batchScanPower;
78        }
79
80        app.wifiPowerMah = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;
81        if (DEBUG && app.wifiPowerMah != 0) {
82            Log.d(TAG, "UID " + u.getUid() + ": power=" +
83                    BatteryStatsHelper.makemAh(app.wifiPowerMah));
84        }
85    }
86
87    @Override
88    public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
89                                   long rawUptimeUs, int statsType) {
90        final long totalRunningTimeMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType)
91                / 1000;
92        final double powerDrain = ((totalRunningTimeMs - mTotalAppWifiRunningTimeMs) * mWifiPowerOn)
93                / (1000*60*60);
94        app.wifiRunningTimeMs = totalRunningTimeMs;
95        app.wifiPowerMah = Math.max(0, powerDrain);
96    }
97
98    @Override
99    public void reset() {
100        mTotalAppWifiRunningTimeMs = 0;
101    }
102}
103