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 * WiFi power calculator for when BatteryStats supports energy reporting
23 * from the WiFi controller.
24 */
25public class WifiPowerCalculator extends PowerCalculator {
26    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
27    private static final String TAG = "WifiPowerCalculator";
28    private final double mIdleCurrentMa;
29    private final double mTxCurrentMa;
30    private final double mRxCurrentMa;
31    private double mTotalAppPowerDrain = 0;
32    private long mTotalAppRunningTime = 0;
33
34    public WifiPowerCalculator(PowerProfile profile) {
35        mIdleCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE);
36        mTxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX);
37        mRxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX);
38    }
39
40    @Override
41    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
42                             long rawUptimeUs, int statsType) {
43        final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
44        if (counter == null) {
45            return;
46        }
47
48        final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
49        final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
50        final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
51        app.wifiRunningTimeMs = idleTime + rxTime + txTime;
52        mTotalAppRunningTime += app.wifiRunningTimeMs;
53
54        app.wifiPowerMah =
55                ((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa))
56                / (1000*60*60);
57        mTotalAppPowerDrain += app.wifiPowerMah;
58
59        app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
60                statsType);
61        app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
62                statsType);
63        app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
64                statsType);
65        app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
66                statsType);
67
68        if (DEBUG && app.wifiPowerMah != 0) {
69            Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime + "ms tx=" +
70                    txTime + "ms power=" + BatteryStatsHelper.makemAh(app.wifiPowerMah));
71        }
72    }
73
74    @Override
75    public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
76                                   long rawUptimeUs, int statsType) {
77        final BatteryStats.ControllerActivityCounter counter = stats.getWifiControllerActivity();
78
79        final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
80        final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
81        final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
82
83        app.wifiRunningTimeMs = Math.max(0,
84                (idleTimeMs + rxTimeMs + txTimeMs) - mTotalAppRunningTime);
85
86        double powerDrainMah = counter.getPowerCounter().getCountLocked(statsType)
87                / (double)(1000*60*60);
88        if (powerDrainMah == 0) {
89            // Some controllers do not report power drain, so we can calculate it here.
90            powerDrainMah = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa)
91                    + (rxTimeMs * mRxCurrentMa)) / (1000*60*60);
92        }
93        app.wifiPowerMah = Math.max(0, powerDrainMah - mTotalAppPowerDrain);
94
95        if (DEBUG) {
96            Log.d(TAG, "left over WiFi power: " + BatteryStatsHelper.makemAh(app.wifiPowerMah));
97        }
98    }
99
100    @Override
101    public void reset() {
102        mTotalAppPowerDrain = 0;
103        mTotalAppRunningTime = 0;
104    }
105}
106