blob: 1054c2ef1c5fee8c415f1c9969a162ccd4d67ec5 [file] [log] [blame]
/*
* 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;
}
}