1 /* 2 * Copyright 2018 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 */ 16 17 package com.android.server.wifi; 18 19 import android.content.Context; 20 import android.provider.Settings; 21 22 import com.android.server.wifi.nano.WifiMetricsProto.WifiIsUnusableEvent; 23 24 /** 25 * Looks for Wifi data stalls 26 */ 27 public class WifiDataStall { 28 29 // Default minimum number of txBadDelta to trigger data stall 30 public static final int MIN_TX_BAD_DEFAULT = 1; 31 // Default minimum number of txSuccessDelta to trigger data stall 32 // when rxSuccessDelta is 0 33 public static final int MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT = 50; 34 // Maximum time gap between two WifiLinkLayerStats to trigger a data stall 35 public static final long MAX_MS_DELTA_FOR_DATA_STALL = 60 * 1000; // 1 minute 36 37 private final Context mContext; 38 private final FrameworkFacade mFacade; 39 private final WifiMetrics mWifiMetrics; 40 41 private int mMinTxBad; 42 private int mMinTxSuccessWithoutRx; 43 WifiDataStall(Context context, FrameworkFacade facade, WifiMetrics wifiMetrics)44 public WifiDataStall(Context context, FrameworkFacade facade, WifiMetrics wifiMetrics) { 45 mContext = context; 46 mFacade = facade; 47 mWifiMetrics = wifiMetrics; 48 loadSettings(); 49 } 50 51 /** 52 * Load setting values related to wifi data stall. 53 */ loadSettings()54 public void loadSettings() { 55 mMinTxBad = mFacade.getIntegerSetting( 56 mContext, Settings.Global.WIFI_DATA_STALL_MIN_TX_BAD, MIN_TX_BAD_DEFAULT); 57 mMinTxSuccessWithoutRx = mFacade.getIntegerSetting( 58 mContext, Settings.Global.WIFI_DATA_STALL_MIN_TX_SUCCESS_WITHOUT_RX, 59 MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT); 60 mWifiMetrics.setWifiDataStallMinTxBad(mMinTxBad); 61 mWifiMetrics.setWifiDataStallMinRxWithoutTx(mMinTxSuccessWithoutRx); 62 } 63 64 /** 65 * Checks for data stall by looking at tx/rx packet counts 66 * @param oldStats second most recent WifiLinkLayerStats 67 * @param newStats most recent WifiLinkLayerStats 68 * @return trigger type of WifiIsUnusableEvent 69 */ checkForDataStall(WifiLinkLayerStats oldStats, WifiLinkLayerStats newStats)70 public int checkForDataStall(WifiLinkLayerStats oldStats, WifiLinkLayerStats newStats) { 71 if (oldStats == null || newStats == null) { 72 mWifiMetrics.resetWifiIsUnusableLinkLayerStats(); 73 return WifiIsUnusableEvent.TYPE_UNKNOWN; 74 } 75 76 long txSuccessDelta = (newStats.txmpdu_be + newStats.txmpdu_bk 77 + newStats.txmpdu_vi + newStats.txmpdu_vo) 78 - (oldStats.txmpdu_be + oldStats.txmpdu_bk 79 + oldStats.txmpdu_vi + oldStats.txmpdu_vo); 80 long txRetriesDelta = (newStats.retries_be + newStats.retries_bk 81 + newStats.retries_vi + newStats.retries_vo) 82 - (oldStats.retries_be + oldStats.retries_bk 83 + oldStats.retries_vi + oldStats.retries_vo); 84 long txBadDelta = (newStats.lostmpdu_be + newStats.lostmpdu_bk 85 + newStats.lostmpdu_vi + newStats.lostmpdu_vo) 86 - (oldStats.lostmpdu_be + oldStats.lostmpdu_bk 87 + oldStats.lostmpdu_vi + oldStats.lostmpdu_vo); 88 long rxSuccessDelta = (newStats.rxmpdu_be + newStats.rxmpdu_bk 89 + newStats.rxmpdu_vi + newStats.rxmpdu_vo) 90 - (oldStats.rxmpdu_be + oldStats.rxmpdu_bk 91 + oldStats.rxmpdu_vi + oldStats.rxmpdu_vo); 92 long timeMsDelta = newStats.timeStampInMs - oldStats.timeStampInMs; 93 94 if (timeMsDelta < 0 95 || txSuccessDelta < 0 96 || txRetriesDelta < 0 97 || txBadDelta < 0 98 || rxSuccessDelta < 0) { 99 // There was a reset in WifiLinkLayerStats 100 mWifiMetrics.resetWifiIsUnusableLinkLayerStats(); 101 return WifiIsUnusableEvent.TYPE_UNKNOWN; 102 } 103 104 mWifiMetrics.updateWifiIsUnusableLinkLayerStats(txSuccessDelta, txRetriesDelta, 105 txBadDelta, rxSuccessDelta, timeMsDelta); 106 if (timeMsDelta < MAX_MS_DELTA_FOR_DATA_STALL) { 107 // There is a data stall if there are too many tx failures 108 // or if we are not receiving any packets despite many tx successes 109 boolean dataStallBadTx = (txBadDelta >= mMinTxBad); 110 boolean dataStallTxSuccessWithoutRx = 111 (rxSuccessDelta == 0 && txSuccessDelta >= mMinTxSuccessWithoutRx); 112 if (dataStallBadTx && dataStallTxSuccessWithoutRx) { 113 mWifiMetrics.logWifiIsUnusableEvent(WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH); 114 return WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH; 115 } else if (dataStallBadTx) { 116 mWifiMetrics.logWifiIsUnusableEvent(WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX); 117 return WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX; 118 } else if (dataStallTxSuccessWithoutRx) { 119 mWifiMetrics.logWifiIsUnusableEvent( 120 WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX); 121 return WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX; 122 } 123 } 124 125 return WifiIsUnusableEvent.TYPE_UNKNOWN; 126 } 127 } 128