huangcm
2025-08-25 2f2fd745743ad500687c6985119d523146531958
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
 * Copyright (C) 2016 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.server.wifi;
 
import android.os.BatteryStats;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.connectivity.WifiBatteryStats;
import android.text.format.DateUtils;
import android.util.Log;
 
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.server.wifi.nano.WifiMetricsProto.WifiPowerStats;
import com.android.server.wifi.nano.WifiMetricsProto.WifiRadioUsage;
 
import java.io.PrintWriter;
import java.text.DecimalFormat;
 
/**
 * WifiPowerMetrics holds the wifi power metrics and converts them to WifiPowerStats proto buf.
 * This proto buf is included in the Wifi proto buf.
 */
public class WifiPowerMetrics {
 
    private static final String TAG = "WifiPowerMetrics";
 
    /* BatteryStats API */
    private final IBatteryStats mBatteryStats;
 
    public WifiPowerMetrics() {
        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
                BatteryStats.SERVICE_NAME));
    }
 
    // This constructor injects IBatteryStats and should be used for testing only.
    @VisibleForTesting
    public WifiPowerMetrics(IBatteryStats batteryStats) {
        mBatteryStats = batteryStats;
    }
 
    /**
     * Build WifiPowerStats proto
     * A snapshot of Wifi statistics in Batterystats is obtained. Due to reboots multiple correlated
     * logs may be uploaded in a day. Resolution is on the server side. The log with longest
     * duration is picked.
     * @return WifiPowerStats
     */
    public WifiPowerStats buildProto() {
        WifiPowerStats m = new WifiPowerStats();
        WifiBatteryStats stats = getStats();
        if (stats != null) {
            m.loggingDurationMs = stats.getLoggingDurationMs();
            m.energyConsumedMah = stats.getEnergyConsumedMaMs()
                / ((double) DateUtils.HOUR_IN_MILLIS);
            m.idleTimeMs = stats.getIdleTimeMs();
            m.rxTimeMs = stats.getRxTimeMs();
            m.txTimeMs = stats.getTxTimeMs();
            m.wifiKernelActiveTimeMs = stats.getKernelActiveTimeMs();
            m.numPacketsTx = stats.getNumPacketsTx();
            m.numBytesTx = stats.getNumBytesTx();
            m.numPacketsRx = stats.getNumPacketsRx();
            m.numBytesRx = stats.getNumPacketsRx();
            m.sleepTimeMs = stats.getSleepTimeMs();
            m.scanTimeMs = stats.getScanTimeMs();
            m.monitoredRailEnergyConsumedMah = stats.getMonitoredRailChargeConsumedMaMs()
                    / ((double) DateUtils.HOUR_IN_MILLIS);
        }
        return m;
    }
 
    /**
     * Build WifiRadioUsage proto
     * A snapshot of Wifi statistics in Batterystats is obtained. Due to reboots multiple correlated
     * logs may be uploaded in a day. Server side should analyze based the ratio of collected
     * properties over the total logging duration (ie. |scanTimeMs| / |loggingDurationMs|)
     *
     * This proto contains additional wifi usage data that are not directly related to power
     * calculations.
     * @return WifiRadioUsage
     */
    public WifiRadioUsage buildWifiRadioUsageProto() {
        WifiRadioUsage m = new WifiRadioUsage();
        WifiBatteryStats stats = getStats();
        if (stats != null) {
            m.loggingDurationMs = stats.getLoggingDurationMs();
            m.scanTimeMs = stats.getScanTimeMs();
        }
        return m;
    }
 
    /**
     * Dump all WifiPowerStats to console (pw)
     * @param pw
     */
    public void dump(PrintWriter pw) {
        WifiPowerStats s = buildProto();
        if (s!=null) {
            pw.println("Wifi power metrics:");
            pw.println("Logging duration (time on battery): " + s.loggingDurationMs);
            pw.println("Energy consumed by wifi (mAh): " + s.energyConsumedMah);
            pw.println("Amount of time wifi is in idle (ms): " + s.idleTimeMs);
            pw.println("Amount of time wifi is in rx (ms): " + s.rxTimeMs);
            pw.println("Amount of time wifi is in tx (ms): " + s.txTimeMs);
            pw.println("Amount of time kernel is active because of wifi data (ms): "
                    + s.wifiKernelActiveTimeMs);
            pw.println("Amount of time wifi is in sleep (ms): " + s.sleepTimeMs);
            pw.println("Amount of time wifi is scanning (ms): " + s.scanTimeMs);
            pw.println("Number of packets sent (tx): " + s.numPacketsTx);
            pw.println("Number of bytes sent (tx): " + s.numBytesTx);
            pw.println("Number of packets received (rx): " + s.numPacketsRx);
            pw.println("Number of bytes sent (rx): " + s.numBytesRx);
            pw.println("Energy consumed across measured wifi rails (mAh): "
                    + new DecimalFormat("#.##").format(s.monitoredRailEnergyConsumedMah));
        }
        WifiRadioUsage wifiRadioUsage = buildWifiRadioUsageProto();
        pw.println("Wifi radio usage metrics:");
        pw.println("Logging duration (time on battery): " + wifiRadioUsage.loggingDurationMs);
        pw.println("Amount of time wifi is in scan mode while on battery (ms): "
                + wifiRadioUsage.scanTimeMs);
    }
 
    /**
     * Get wifi stats from batterystats
     * @return WifiBatteryStats
     */
    private WifiBatteryStats getStats() {
        try {
            return mBatteryStats.getWifiBatteryStats();
        } catch (RemoteException e) {
            Log.e(TAG, "Unable to obtain Wifi power stats from BatteryStats");
        }
        return null;
    }
}