/* * 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; } }