ronnie
2022-10-14 1504bb53e29d3d46222c0b3ea994fc494b48e153
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
/*
 * Copyright 2018 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.content.Context;
import android.provider.Settings;
 
import com.android.server.wifi.nano.WifiMetricsProto.WifiIsUnusableEvent;
 
/**
 * Looks for Wifi data stalls
 */
public class WifiDataStall {
 
    // Default minimum number of txBadDelta to trigger data stall
    public static final int MIN_TX_BAD_DEFAULT = 1;
    // Default minimum number of txSuccessDelta to trigger data stall
    // when rxSuccessDelta is 0
    public static final int MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT = 50;
    // Maximum time gap between two WifiLinkLayerStats to trigger a data stall
    public static final long MAX_MS_DELTA_FOR_DATA_STALL = 60 * 1000; // 1 minute
 
    private final Context mContext;
    private final FrameworkFacade mFacade;
    private final WifiMetrics mWifiMetrics;
 
    private int mMinTxBad;
    private int mMinTxSuccessWithoutRx;
 
    public WifiDataStall(Context context, FrameworkFacade facade, WifiMetrics wifiMetrics) {
        mContext = context;
        mFacade = facade;
        mWifiMetrics = wifiMetrics;
        loadSettings();
    }
 
    /**
     * Load setting values related to wifi data stall.
     */
    public void loadSettings() {
        mMinTxBad = mFacade.getIntegerSetting(
                mContext, Settings.Global.WIFI_DATA_STALL_MIN_TX_BAD, MIN_TX_BAD_DEFAULT);
        mMinTxSuccessWithoutRx = mFacade.getIntegerSetting(
                mContext, Settings.Global.WIFI_DATA_STALL_MIN_TX_SUCCESS_WITHOUT_RX,
                MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT);
        mWifiMetrics.setWifiDataStallMinTxBad(mMinTxBad);
        mWifiMetrics.setWifiDataStallMinRxWithoutTx(mMinTxSuccessWithoutRx);
    }
 
    /**
     * Checks for data stall by looking at tx/rx packet counts
     * @param oldStats second most recent WifiLinkLayerStats
     * @param newStats most recent WifiLinkLayerStats
     * @return trigger type of WifiIsUnusableEvent
     */
    public int checkForDataStall(WifiLinkLayerStats oldStats, WifiLinkLayerStats newStats) {
        if (oldStats == null || newStats == null) {
            mWifiMetrics.resetWifiIsUnusableLinkLayerStats();
            return WifiIsUnusableEvent.TYPE_UNKNOWN;
        }
 
        long txSuccessDelta = (newStats.txmpdu_be + newStats.txmpdu_bk
                + newStats.txmpdu_vi + newStats.txmpdu_vo)
                - (oldStats.txmpdu_be + oldStats.txmpdu_bk
                + oldStats.txmpdu_vi + oldStats.txmpdu_vo);
        long txRetriesDelta = (newStats.retries_be + newStats.retries_bk
                + newStats.retries_vi + newStats.retries_vo)
                - (oldStats.retries_be + oldStats.retries_bk
                + oldStats.retries_vi + oldStats.retries_vo);
        long txBadDelta = (newStats.lostmpdu_be + newStats.lostmpdu_bk
                + newStats.lostmpdu_vi + newStats.lostmpdu_vo)
                - (oldStats.lostmpdu_be + oldStats.lostmpdu_bk
                + oldStats.lostmpdu_vi + oldStats.lostmpdu_vo);
        long rxSuccessDelta = (newStats.rxmpdu_be + newStats.rxmpdu_bk
                + newStats.rxmpdu_vi + newStats.rxmpdu_vo)
                - (oldStats.rxmpdu_be + oldStats.rxmpdu_bk
                + oldStats.rxmpdu_vi + oldStats.rxmpdu_vo);
        long timeMsDelta = newStats.timeStampInMs - oldStats.timeStampInMs;
 
        if (timeMsDelta < 0
                || txSuccessDelta < 0
                || txRetriesDelta < 0
                || txBadDelta < 0
                || rxSuccessDelta < 0) {
            // There was a reset in WifiLinkLayerStats
            mWifiMetrics.resetWifiIsUnusableLinkLayerStats();
            return WifiIsUnusableEvent.TYPE_UNKNOWN;
        }
 
        mWifiMetrics.updateWifiIsUnusableLinkLayerStats(txSuccessDelta, txRetriesDelta,
                txBadDelta, rxSuccessDelta, timeMsDelta);
        if (timeMsDelta < MAX_MS_DELTA_FOR_DATA_STALL) {
            // There is a data stall if there are too many tx failures
            // or if we are not receiving any packets despite many tx successes
            boolean dataStallBadTx = (txBadDelta >= mMinTxBad);
            boolean dataStallTxSuccessWithoutRx =
                    (rxSuccessDelta == 0 && txSuccessDelta >= mMinTxSuccessWithoutRx);
            if (dataStallBadTx && dataStallTxSuccessWithoutRx) {
                mWifiMetrics.logWifiIsUnusableEvent(WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH);
                return WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH;
            } else if (dataStallBadTx) {
                mWifiMetrics.logWifiIsUnusableEvent(WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX);
                return WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX;
            } else if (dataStallTxSuccessWithoutRx) {
                mWifiMetrics.logWifiIsUnusableEvent(
                        WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX);
                return WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX;
            }
        }
 
        return WifiIsUnusableEvent.TYPE_UNKNOWN;
    }
}