diff options
4 files changed, 1026 insertions, 113 deletions
diff --git a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java index 36f0656a8..6c069ade9 100644 --- a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java +++ b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java @@ -27,55 +27,100 @@ import java.util.List; import java.util.Map; /** - * <TBD> Intended Purpose/Behavior of the class upon completion: + * This Class is a Work-In-Progress, intended behavior is as follows: * Essentially this class automates a user toggling 'Airplane Mode' when WiFi "won't work". * IF each available saved network has failed connecting more times than the FAILURE_THRESHOLD * THEN Watchdog will restart Supplicant, wifi driver and return WifiStateMachine to InitialState. - * </TBD> */ public class WifiLastResortWatchdog { private static final String TAG = "WifiLastResortWatchdog"; private static final boolean VDBG = false; + private static final boolean DBG = true; + /** + * Association Failure code + */ + public static final int FAILURE_CODE_ASSOCIATION = 1; + /** + * Authentication Failure code + */ + public static final int FAILURE_CODE_AUTHENTICATION = 2; + /** + * Dhcp Failure code + */ + public static final int FAILURE_CODE_DHCP = 3; + /** + * Maximum number of scan results received since we last saw a BSSID. + * If it is not seen before this limit is reached, the network is culled + */ + public static final int MAX_BSSID_AGE = 10; + /** + * BSSID used to increment failure counts against ALL bssids associated with a particular SSID + */ + public static final String BSSID_ANY = "any"; + /** + * Failure count that each available networks must meet to possibly trigger the Watchdog + */ + public static final int FAILURE_THRESHOLD = 7; /** * Cached WifiConfigurations of available networks seen within MAX_BSSID_AGE scan results * Key:BSSID, Value:Counters of failure types */ private Map<String, AvailableNetworkFailureCount> mRecentAvailableNetworks = new HashMap<>(); - - // Maximum number of scan results received since we last saw a BSSID. - // If it is not seen before this limit is reached, the network is culled - public static final int MAX_BSSID_AGE = 10; + /** + * Map of SSID to <FailureCount, AP count>, used to count failures & number of access points + * belonging to an SSID. + */ + private Map<String, Pair<AvailableNetworkFailureCount, Integer>> mSsidFailureCount = + new HashMap<>(); /** * Refreshes recentAvailableNetworks with the latest available networks * Adds new networks, removes old ones that have timed out. Should be called after Wifi * framework decides what networks it is potentially connecting to. - * @param availableNetworkFailureCounts ScanDetail & Config list of potential connection + * @param availableNetworks ScanDetail & Config list of potential connection * candidates */ public void updateAvailableNetworks( - List<Pair<ScanDetail, WifiConfiguration>> availableNetworkFailureCounts) { + List<Pair<ScanDetail, WifiConfiguration>> availableNetworks) { + if (VDBG) Log.v(TAG, "updateAvailableNetworks: size = " + availableNetworks.size()); // Add new networks to mRecentAvailableNetworks - if (availableNetworkFailureCounts != null) { - for (Pair<ScanDetail, WifiConfiguration> pair : availableNetworkFailureCounts) { - ScanResult scanResult = pair.first.getScanResult(); + if (availableNetworks != null) { + for (Pair<ScanDetail, WifiConfiguration> pair : availableNetworks) { + final ScanDetail scanDetail = pair.first; + final WifiConfiguration config = pair.second; + ScanResult scanResult = scanDetail.getScanResult(); if (scanResult == null) continue; - String key = scanResult.BSSID; - + String bssid = scanResult.BSSID; + String ssid = "\"" + scanDetail.getSSID() + "\""; + if (VDBG) Log.v(TAG, " " + bssid + ": " + scanDetail.getSSID()); // Cache the scanResult & WifiConfig AvailableNetworkFailureCount availableNetworkFailureCount = - mRecentAvailableNetworks.get(key); - if (availableNetworkFailureCount != null) { - // We've already cached this, refresh timeout count & config - availableNetworkFailureCount.config = pair.second; - } else { + mRecentAvailableNetworks.get(bssid); + if (availableNetworkFailureCount == null) { // New network is available - availableNetworkFailureCount = new AvailableNetworkFailureCount(pair.second); - availableNetworkFailureCount.Ssid = pair.first.getSSID(); + availableNetworkFailureCount = new AvailableNetworkFailureCount(config); + availableNetworkFailureCount.ssid = ssid; + + // Count AP for this SSID + Pair<AvailableNetworkFailureCount, Integer> ssidFailsAndApCount = + mSsidFailureCount.get(ssid); + if (ssidFailsAndApCount == null) { + // This is a new SSID, create new FailureCount for it and set AP count to 1 + ssidFailsAndApCount = Pair.create(new AvailableNetworkFailureCount(config), + 1); + } else { + final Integer numberOfAps = ssidFailsAndApCount.second; + // This is not a new SSID, increment the AP count for it + ssidFailsAndApCount = Pair.create(ssidFailsAndApCount.first, + numberOfAps + 1); + } + mSsidFailureCount.put(ssid, ssidFailsAndApCount); } - // If we saw a network, set its Age to -1 here, next incrementation will set it to 0 + // refresh config + availableNetworkFailureCount.config = config; + // If we saw a network, set its Age to -1 here, aging iteration will set it to 0 availableNetworkFailureCount.age = -1; - mRecentAvailableNetworks.put(key, availableNetworkFailureCount); + mRecentAvailableNetworks.put(bssid, availableNetworkFailureCount); } } @@ -87,6 +132,24 @@ public class WifiLastResortWatchdog { if (entry.getValue().age < MAX_BSSID_AGE - 1) { entry.getValue().age++; } else { + // Decrement this SSID : AP count + String ssid = entry.getValue().ssid; + Pair<AvailableNetworkFailureCount, Integer> ssidFails = + mSsidFailureCount.get(ssid); + if (ssidFails != null) { + Integer apCount = ssidFails.second - 1; + if (apCount > 0) { + ssidFails = Pair.create(ssidFails.first, apCount); + mSsidFailureCount.put(ssid, ssidFails); + } else { + mSsidFailureCount.remove(ssid); + } + } else { + if (DBG) { + Log.d(TAG, "updateAvailableNetworks: SSID to AP count mismatch for " + + ssid); + } + } it.remove(); } } @@ -94,6 +157,112 @@ public class WifiLastResortWatchdog { } /** + * Increments the failure reason count for the given bssid. Performs a check to see if we have + * exceeded a failure threshold for all available networks, and executes the last resort restart + * @param bssid of the network that has failed connection, can be "any" + * @param reason Message id from WifiStateMachine for this failure + * @return true if watchdog triggers, returned for test visibility + */ + public boolean noteConnectionFailureAndTriggerIfNeeded(String ssid, String bssid, int reason) { + if (VDBG) { + Log.v(TAG, "noteConnectionFailureAndTriggerIfNeeded: [" + ssid + ", " + bssid + ", " + + reason + "]"); + } + // Update failure count for the failing network + updateFailureCountForNetwork(ssid, bssid, reason); + return false; + } + + /** + * Increments the failure reason count for the given network, in 'mSsidFailureCount' + * Failures are counted per SSID, either; by using the ssid string when the bssid is "any" + * or by looking up the ssid attached to a specific bssid + * An unused set of counts is also kept which is bssid specific, in 'mRecentAvailableNetworks' + * @param ssid of the network that has failed connection + * @param bssid of the network that has failed connection, can be "any" + * @param reason Message id from WifiStateMachine for this failure + */ + private void updateFailureCountForNetwork(String ssid, String bssid, int reason) { + if (VDBG) { + Log.v(TAG, "updateFailureCountForNetwork: [" + ssid + ", " + bssid + ", " + + reason + "]"); + } + if (BSSID_ANY.equals(bssid)) { + incrementSsidFailureCount(ssid, reason); + } else { + // Bssid count is actually unused except for logging purposes + // SSID count is incremented within the BSSID counting method + incrementBssidFailureCount(ssid, bssid, reason); + } + } + + /** + * Update the per-SSID failure count + * @param ssid the ssid to increment failure count for + * @param reason the failure type to increment count for + */ + private void incrementSsidFailureCount(String ssid, int reason) { + Pair<AvailableNetworkFailureCount, Integer> ssidFails = mSsidFailureCount.get(ssid); + if (ssidFails == null) { + if (DBG) { + Log.v(TAG, "updateFailureCountForNetwork: No networks for ssid = " + ssid); + } + return; + } + AvailableNetworkFailureCount failureCount = ssidFails.first; + failureCount.incrementFailureCount(reason); + } + + /** + * Update the per-BSSID failure count + * @param bssid the bssid to increment failure count for + * @param reason the failure type to increment count for + */ + private void incrementBssidFailureCount(String ssid, String bssid, int reason) { + AvailableNetworkFailureCount availableNetworkFailureCount = + mRecentAvailableNetworks.get(bssid); + if (availableNetworkFailureCount == null) { + if (DBG) { + Log.d(TAG, "updateFailureCountForNetwork: Unable to find Network [" + ssid + + ", " + bssid + "]"); + } + return; + } + if (!availableNetworkFailureCount.ssid.equals(ssid)) { + if (DBG) { + Log.d(TAG, "updateFailureCountForNetwork: Failed connection attempt has" + + " wrong ssid. Failed [" + ssid + ", " + bssid + "], buffered [" + + availableNetworkFailureCount.ssid + ", " + bssid + "]"); + } + return; + } + if (availableNetworkFailureCount.config == null) { + if (VDBG) { + Log.v(TAG, "updateFailureCountForNetwork: network has no config [" + + ssid + ", " + bssid + "]"); + } + } + availableNetworkFailureCount.incrementFailureCount(reason); + incrementSsidFailureCount(ssid, reason); + } + + /** + * Clear failure counts for each network in recentAvailableNetworks + */ + private void clearAllFailureCounts() { + if (VDBG) Log.v(TAG, "clearAllFailureCounts."); + for (Map.Entry<String, AvailableNetworkFailureCount> entry + : mRecentAvailableNetworks.entrySet()) { + final AvailableNetworkFailureCount failureCount = entry.getValue(); + entry.getValue().resetCounts(); + } + for (Map.Entry<String, Pair<AvailableNetworkFailureCount, Integer>> entry + : mSsidFailureCount.entrySet()) { + final AvailableNetworkFailureCount failureCount = entry.getValue().first; + failureCount.resetCounts(); + } + } + /** * Gets the buffer of recently available networks */ Map<String, AvailableNetworkFailureCount> getRecentAvailableNetworks() { @@ -110,10 +279,67 @@ public class WifiLastResortWatchdog { : mRecentAvailableNetworks.entrySet()) { sb.append("\n " + entry.getKey() + ": " + entry.getValue()); } + sb.append("\nmSsidFailureCount:"); + for (Map.Entry<String, Pair<AvailableNetworkFailureCount, Integer>> entry : + mSsidFailureCount.entrySet()) { + final AvailableNetworkFailureCount failureCount = entry.getValue().first; + final Integer apCount = entry.getValue().second; + sb.append("\n" + entry.getKey() + ": " + apCount + ", " + + failureCount.toString()); + } return sb.toString(); } - static class AvailableNetworkFailureCount { + /** + * @param bssid bssid to check the failures for + * @return true if any failure count is over FAILURE_THRESHOLD + */ + public boolean isOverFailureThreshold(String bssid) { + if ((getFailureCount(bssid, FAILURE_CODE_ASSOCIATION) >= FAILURE_THRESHOLD) + || (getFailureCount(bssid, FAILURE_CODE_AUTHENTICATION) >= FAILURE_THRESHOLD) + || (getFailureCount(bssid, FAILURE_CODE_DHCP) >= FAILURE_THRESHOLD)) { + return true; + } + return false; + } + + /** + * Get the failure count for a specific bssid. This actually checks the ssid attached to the + * BSSID and returns the SSID count + * @param reason failure reason to get count for + */ + public int getFailureCount(String bssid, int reason) { + AvailableNetworkFailureCount availableNetworkFailureCount = + mRecentAvailableNetworks.get(bssid); + if (availableNetworkFailureCount == null) { + return 0; + } + String ssid = availableNetworkFailureCount.ssid; + Pair<AvailableNetworkFailureCount, Integer> ssidFails = mSsidFailureCount.get(ssid); + if (ssidFails == null) { + if (DBG) { + Log.d(TAG, "getFailureCount: Could not find SSID count for " + ssid); + } + return 0; + } + final AvailableNetworkFailureCount failCount = ssidFails.first; + switch (reason) { + case FAILURE_CODE_ASSOCIATION: + return failCount.associationRejection; + case FAILURE_CODE_AUTHENTICATION: + return failCount.authenticationFailure; + case FAILURE_CODE_DHCP: + return failCount.dhcpFailure; + default: + return 0; + } + } + + /** + * This class holds the failure counts for an 'available network' (one of the potential + * candidates for connection, as determined by framework). + */ + public static class AvailableNetworkFailureCount { /** * WifiConfiguration associated with this network. Can be null for Ephemeral networks */ @@ -121,17 +347,17 @@ public class WifiLastResortWatchdog { /** * SSID of the network (from ScanDetail) */ - public String Ssid = ""; + public String ssid = ""; /** - * Number of times network has failed for this reason + * Number of times network has failed due to Association Rejection */ public int associationRejection = 0; /** - * Number of times network has failed for this reason + * Number of times network has failed due to Authentication Failure or SSID_TEMP_DISABLED */ - public int authenticationRejection = 0; + public int authenticationFailure = 0; /** - * Number of times network has failed for this reason + * Number of times network has failed due to DHCP failure */ public int dhcpFailure = 0; /** @@ -143,18 +369,39 @@ public class WifiLastResortWatchdog { config = config; } + /** + * @param reason failure reason to increment count for + */ + public void incrementFailureCount(int reason) { + switch (reason) { + case FAILURE_CODE_ASSOCIATION: + associationRejection++; + break; + case FAILURE_CODE_AUTHENTICATION: + authenticationFailure++; + break; + case FAILURE_CODE_DHCP: + dhcpFailure++; + break; + default: //do nothing + } + } + + /** + * Set all failure counts for this network to 0 + */ void resetCounts() { associationRejection = 0; - authenticationRejection = 0; + authenticationFailure = 0; dhcpFailure = 0; } public String toString() { - return Ssid + ", HasEverConnected: " + ((config != null) + return ssid + ", HasEverConnected: " + ((config != null) ? config.getNetworkSelectionStatus().getHasEverConnected() : false) + ", Failures: {" + "Assoc: " + associationRejection - + ", Auth: " + authenticationRejection + + ", Auth: " + authenticationFailure + ", Dhcp: " + dhcpFailure + "}" + ", Age: " + age; diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 9ab7fd206..bd3cd1c30 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -1243,6 +1243,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss sendMessage(CMD_IPV4_PROVISIONING_SUCCESS, dhcpResults); } else { sendMessage(CMD_IPV4_PROVISIONING_FAILURE); + mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(getTargetSsid(), + mTargetRoamBSSID, + WifiLastResortWatchdog.FAILURE_CODE_DHCP); } } @@ -5343,6 +5346,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss reportConnectionAttemptEnd( WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION, WifiMetricsProto.ConnectionEvent.HLF_NONE); + mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(getTargetSsid(), + bssid, + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); break; case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTH_FAILURE); @@ -5356,6 +5362,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss reportConnectionAttemptEnd( WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE, WifiMetricsProto.ConnectionEvent.HLF_NONE); + mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(getTargetSsid(), + mTargetRoamBSSID, + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); break; case WifiMonitor.SSID_TEMP_DISABLED: Log.e(TAG, "Supplicant SSID temporary disabled:" @@ -5367,6 +5376,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss reportConnectionAttemptEnd( WifiMetrics.ConnectionEvent.FAILURE_SSID_TEMP_DISABLED, WifiMetricsProto.ConnectionEvent.HLF_NONE); + mWifiLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(getTargetSsid(), + mTargetRoamBSSID, + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); break; case WifiMonitor.SSID_REENABLED: Log.d(TAG, "Supplicant SSID reenable:" @@ -8326,4 +8338,16 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss } mContext.sendBroadcastAsUser(intent, UserHandle.ALL); } + + /** + * Gets the SSID from the WifiConfiguration pointed at by 'mTargetNetworkId' + * This should match the network config framework is attempting to connect to. + */ + private String getTargetSsid() { + WifiConfiguration currentConfig = mWifiConfigManager.getWifiConfiguration(mTargetNetworkId); + if (currentConfig != null) { + return currentConfig.SSID; + } + return null; + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java b/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java index fc38e62ab..58cb7fae8 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiLastResortWatchdogTest.java @@ -39,6 +39,16 @@ import java.util.List; public class WifiLastResortWatchdogTest { WifiLastResortWatchdog mLastResortWatchdog; + private String[] mSsids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""}; + private String[] mBssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55", + "c0:ff:ee:ee:e3:ee"}; + private int[] mFrequencies = {2437, 5180, 5180, 2437}; + private String[] mCaps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", + "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"}; + private int[] mLevels = {-60, -86, -50, -62}; + private boolean[] mIsEphemeral = {false, false, false, false}; + private boolean[] mHasEverConnected = {false, false, false, false}; + @Before public void setUp() throws Exception { mLastResortWatchdog = new WifiLastResortWatchdog(); @@ -50,8 +60,10 @@ public class WifiLastResortWatchdogTest { List<Pair<ScanDetail, WifiConfiguration>> candidates = new ArrayList<>(); long timeStamp = System.currentTimeMillis(); for (int index = 0; index < ssids.length; index++) { - ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssids[index]), - bssids[index], caps[index], levels[index], frequencies[index], timeStamp, 0); + String ssid = ssids[index].replaceAll("^\"+", "").replaceAll("\"+$", ""); + ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssid), + bssids[index], caps[index], levels[index], frequencies[index], timeStamp, + 0); WifiConfiguration config = null; if (!isEphemeral[index]) { config = mock(WifiConfiguration.class); @@ -65,6 +77,41 @@ public class WifiLastResortWatchdogTest { return candidates; } + private List<Pair<ScanDetail, WifiConfiguration>> createFilteredQnsCandidates(String[] ssids, + String[] bssids, int[] frequencies, String[] caps, int[] levels, + boolean[] isEphemeral, boolean[] hasEverConnected) { + List<Pair<ScanDetail, WifiConfiguration>> candidates = + new ArrayList<Pair<ScanDetail, WifiConfiguration>>(); + long timeStamp = System.currentTimeMillis(); + for (int index = 0; index < ssids.length; index++) { + String ssid = ssids[index].replaceAll("^\"+", "").replaceAll("\"+$", ""); + ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssid), + bssids[index], caps[index], levels[index], frequencies[index], timeStamp, + 0); + WifiConfiguration config = null; + if (!isEphemeral[index]) { + config = mock(WifiConfiguration.class); + WifiConfiguration.NetworkSelectionStatus networkSelectionStatus = + mock(WifiConfiguration.NetworkSelectionStatus.class); + when(config.getNetworkSelectionStatus()).thenReturn(networkSelectionStatus); + when(networkSelectionStatus.getHasEverConnected()) + .thenReturn(hasEverConnected[index]); + } + candidates.add(Pair.create(scanDetail, config)); + } + return candidates; + } + + private void assertFailureCountEquals( + String bssid, int associationRejections, int authenticationFailures, int dhcpFailures) { + assertEquals(associationRejections, mLastResortWatchdog.getFailureCount(bssid, + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION)); + assertEquals(authenticationFailures, mLastResortWatchdog.getFailureCount(bssid, + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION)); + assertEquals(dhcpFailures, mLastResortWatchdog.getFailureCount(bssid, + WifiLastResortWatchdog.FAILURE_CODE_DHCP)); + } + /** * Case #1: Test aging works in available network buffering * This test simulates 4 networks appearing in a scan result, and then only the first 2 @@ -74,34 +121,27 @@ public class WifiLastResortWatchdogTest { */ @Test public void testAvailableNetworkBuffering_ageCullingWorks() throws Exception { - String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""}; - String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55", - "c0:ff:ee:ee:e3:ee"}; - int[] frequencies = {2437, 5180, 5180, 2437}; - String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", - "[WPA2-EAP-CCMP][ESS]"}; - int[] levels = {-60, -86, -50, -62}; - boolean[] isEphemeral = {false, false, false, false}; - // Buffer potential candidates 1,2,3 & 4 - List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids, - bssids, frequencies, caps, levels, isEphemeral); + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral); mLastResortWatchdog.updateAvailableNetworks(candidates); assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4); // Repeatedly buffer candidates 1 & 2, MAX_BSSID_AGE - 1 times - candidates = createFilteredQnsCandidates(Arrays.copyOfRange(ssids, 0, 2), - Arrays.copyOfRange(bssids, 0, 2), - Arrays.copyOfRange(frequencies, 0, 2), - Arrays.copyOfRange(caps, 0, 2), - Arrays.copyOfRange(levels, 0, 2), - Arrays.copyOfRange(isEphemeral, 0, 2)); + candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 2), + Arrays.copyOfRange(mBssids, 0, 2), + Arrays.copyOfRange(mFrequencies, 0, 2), + Arrays.copyOfRange(mCaps, 0, 2), + Arrays.copyOfRange(mLevels, 0, 2), + Arrays.copyOfRange(mIsEphemeral, 0, 2)); for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE - 1; i++) { mLastResortWatchdog.updateAvailableNetworks(candidates); - assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(bssids[0]).age, 0); - assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(bssids[1]).age, 0); - assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(bssids[2]).age, i+1); - assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(bssids[3]).age, i+1); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[0]).age, 0); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[1]).age, 0); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[2]).age, + i + 1); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[3]).age, + i + 1); } assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4); @@ -121,28 +161,19 @@ public class WifiLastResortWatchdogTest { */ @Test public void testAvailableNetworkBuffering_emptyBufferWithEmptyScanResults() throws Exception { - String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""}; - String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55", - "c0:ff:ee:ee:e3:ee"}; - int[] frequencies = {2437, 5180, 5180, 2437}; - String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", - "[WPA2-EAP-CCMP][ESS]"}; - int[] levels = {-60, -86, -50, -62}; - boolean[] isEphemeral = {false, false, false, false}; - // Buffer potential candidates 1,2,3 & 4 - List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids, - bssids, frequencies, caps, levels, isEphemeral); + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral); mLastResortWatchdog.updateAvailableNetworks(candidates); assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4); // Repeatedly buffer with no candidates - candidates = createFilteredQnsCandidates(Arrays.copyOfRange(ssids, 0, 0), - Arrays.copyOfRange(bssids, 0, 0), - Arrays.copyOfRange(frequencies, 0, 0), - Arrays.copyOfRange(caps, 0, 0), - Arrays.copyOfRange(levels, 0, 0), - Arrays.copyOfRange(isEphemeral, 0, 0)); + candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 0), + Arrays.copyOfRange(mBssids, 0, 0), + Arrays.copyOfRange(mFrequencies, 0, 0), + Arrays.copyOfRange(mCaps, 0, 0), + Arrays.copyOfRange(mLevels, 0, 0), + Arrays.copyOfRange(mIsEphemeral, 0, 0)); for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) { mLastResortWatchdog.updateAvailableNetworks(candidates); } @@ -154,34 +185,26 @@ public class WifiLastResortWatchdogTest { }; /** - * Case 3: Adding more networks over time - * In this test, each successive (4 total) scan result buffers one more network. - * Expected behavior: recentAvailableNetworks grows with number of scan results + * Case 3: Adding more networks over time + * In this test, each successive (4 total) scan result buffers one more network. + * Expected behavior: recentAvailableNetworks grows with number of scan results */ @Test public void testAvailableNetworkBuffering_addNewNetworksOverTime() throws Exception { - String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""}; - String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55", - "c0:ff:ee:ee:e3:ee"}; - int[] frequencies = {2437, 5180, 5180, 2437}; - String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", - "[WPA2-EAP-CCMP][ESS]"}; - int[] levels = {-60, -86, -50, -62}; - boolean[] isEphemeral = {false, false, false, false}; List<Pair<ScanDetail, WifiConfiguration>> candidates; // Buffer (i) scan results with each successive scan result - for (int i = 1; i <= ssids.length; i++) { - candidates = createFilteredQnsCandidates(Arrays.copyOfRange(ssids, 0, i), - Arrays.copyOfRange(bssids, 0, i), - Arrays.copyOfRange(frequencies, 0, i), - Arrays.copyOfRange(caps, 0, i), - Arrays.copyOfRange(levels, 0, i), - Arrays.copyOfRange(isEphemeral, 0, i)); + for (int i = 1; i <= mSsids.length; i++) { + candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, i), + Arrays.copyOfRange(mBssids, 0, i), + Arrays.copyOfRange(mFrequencies, 0, i), + Arrays.copyOfRange(mCaps, 0, i), + Arrays.copyOfRange(mLevels, 0, i), + Arrays.copyOfRange(mIsEphemeral, 0, i)); mLastResortWatchdog.updateAvailableNetworks(candidates); assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), i); for (int j = 0; j < i; j++) { assertEquals( - mLastResortWatchdog.getRecentAvailableNetworks().get(bssids[j]).age, 0); + mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[j]).age, 0); } } }; @@ -196,35 +219,30 @@ public class WifiLastResortWatchdogTest { */ @Test public void testAvailableNetworkBuffering_multipleNetworksSomeEphemeral() throws Exception { - String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""}; - String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55", - "c0:ff:ee:ee:e3:ee"}; - int[] frequencies = {2437, 5180, 5180, 2437}; - String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", - "[WPA2-EAP-CCMP][ESS]"}; - int[] levels = {-60, -86, -50, -62}; boolean[] isEphemeral = {true, false, true, false}; // Buffer potential candidates 1,2,3 & 4 - List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids, - bssids, frequencies, caps, levels, isEphemeral); + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, isEphemeral); mLastResortWatchdog.updateAvailableNetworks(candidates); assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4); // Repeatedly buffer candidates 1 & 2, MAX_BSSID_AGE - 1 times - candidates = createFilteredQnsCandidates(Arrays.copyOfRange(ssids, 0, 2), - Arrays.copyOfRange(bssids, 0, 2), - Arrays.copyOfRange(frequencies, 0, 2), - Arrays.copyOfRange(caps, 0, 2), - Arrays.copyOfRange(levels, 0, 2), + candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 2), + Arrays.copyOfRange(mBssids, 0, 2), + Arrays.copyOfRange(mFrequencies, 0, 2), + Arrays.copyOfRange(mCaps, 0, 2), + Arrays.copyOfRange(mLevels, 0, 2), Arrays.copyOfRange(isEphemeral, 0, 2)); for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE - 1; i++) { mLastResortWatchdog.updateAvailableNetworks(candidates); mLastResortWatchdog.toString(); - assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(bssids[0]).age, 0); - assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(bssids[1]).age, 0); - assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(bssids[2]).age, i+1); - assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(bssids[3]).age, i+1); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[0]).age, 0); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[1]).age, 0); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[2]).age, + i + 1); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[3]).age, + i + 1); } assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4); @@ -233,4 +251,627 @@ public class WifiLastResortWatchdogTest { assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 2); mLastResortWatchdog.toString(); }; + + /** + * Case 5: Test failure counting, incrementing a specific BSSID + * Test has 4 networks buffered, increment each different failure type on one of them + * Expected behaviour: See failure counts for the specific failures rise to the appropriate + * level for the specific network + */ + @Test + public void testFailureCounting_countFailuresForSingleBssid() throws Exception { + int associationRejections = 5; + int authenticationFailures = 9; + int dhcpFailures = 11; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).associationRejection); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).authenticationFailure); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).dhcpFailure); + } + assertFailureCountEquals(mBssids[0], associationRejections, 0, 0); + assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0); + assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures); + assertFailureCountEquals(mBssids[3], 0, 0, 0); + } + + /** + * Case 6: Test failure counting, incrementing a specific BSSID, with some ephemeral networks + * Almost identical to test case 5. + * Test has 4 networks buffered (two are ephemeral), increment each different failure type on + * one of them. + * Expected behavior: See failure counts for the specific failures rise to the appropriate + * level for the specific network + */ + @Test + public void testFailureCounting_countFailuresForSingleBssidWithEphemeral() throws Exception { + int associationRejections = 5; + int authenticationFailures = 9; + int dhcpFailures = 11; + boolean[] mIsEphemeral = {false, true, false, true}; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).associationRejection, i + 1); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).authenticationFailure, i + 1); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + assertEquals(mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).dhcpFailure, i + 1); + } + assertFailureCountEquals(mBssids[0], associationRejections, 0, 0); + assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0); + assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures); + assertFailureCountEquals(mBssids[3], 0, 0, 0); + } + + /** + * Case 7: Test failure counting, incrementing a specific BSSID but with the wrong SSID given + * Test has 4 networks buffered, increment each different failure type on one of them but using + * the wrong ssid. + * Expected behavior: Failure counts will remain at zero for all networks + */ + @Test + public void testFailureCounting_countFailuresForSingleBssidWrongSsid() throws Exception { + String badSsid = "ItHertzWhenIP"; + int associationRejections = 5; + int authenticationFailures = 9; + int dhcpFailures = 11; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(badSsid, mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(badSsid, mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(badSsid, mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + } + + // Ensure all networks still have zero failure count + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + } + + /** + * Case 8: Test failure counting, increment a bssid that does not exist + * Test has 4 networks buffered, increment each failure type, but using the wrong bssid + * Expected behavior: Failure counts will remain at zero for all networks + */ + @Test + public void testFailureCounting_countFailuresForNonexistentBssid() throws Exception { + String badBssid = "de:ad:be:ee:e3:ef"; + int associationRejections = 5; + int authenticationFailures = 9; + int dhcpFailures = 11; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], badBssid, + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], badBssid, + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], badBssid, + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + } + + // Ensure all networks still have zero failure count + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + } + + /** + * Case 9: Test Failure Counting, using the "Any" BSSID + * Test has 4 buffered networks, two of which share the same SSID (different bssids) + * Each failure type is incremented for the shared SSID, but with BSSID "any" + * Expected Behavior: Both networks increment their counts in tandem + */ + @Test + public void testFailureCounting_countFailuresForAnyBssid() throws Exception { + String[] ssids = {"\"test1\"", "\"test2\"", "\"test1\"", "\"test4\""}; + int associationRejections = 5; + int authenticationFailures = 9; + int dhcpFailures = 11; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < ssids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[0], WifiLastResortWatchdog.BSSID_ANY, + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[0], WifiLastResortWatchdog.BSSID_ANY, + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[0], WifiLastResortWatchdog.BSSID_ANY, + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + } + assertFailureCountEquals(mBssids[0], associationRejections, authenticationFailures, + dhcpFailures); + assertFailureCountEquals(mBssids[1], 0, 0, 0); + assertFailureCountEquals(mBssids[2], associationRejections, authenticationFailures, + dhcpFailures); + assertFailureCountEquals(mBssids[3], 0, 0, 0); + } + + /** + * Case 10: Test Failure Counting, using the "Any" BSSID for nonexistent SSID + * Test has 4 buffered networks, two of which share the same SSID (different mBssids) + * Each failure type is incremented for a bad SSID (doesn't exist), but with BSSID "any" + * Expected Behavior: No Failures counted + */ + @Test + public void testFailureCounting_countFailuresForAnyBssidNonexistentSsid() throws Exception { + int associationRejections = 5; + int authenticationFailures = 9; + int dhcpFailures = 11; + String badSsid = "DropItLikeIt'sHotSpot"; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + badSsid, WifiLastResortWatchdog.BSSID_ANY, + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + badSsid, WifiLastResortWatchdog.BSSID_ANY, + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + badSsid, WifiLastResortWatchdog.BSSID_ANY, + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + } + // Check that all network failure counts are still zero + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + } + + /** + * Case 11: Test Failure Counting, over failure Threshold check + * Test has 4 buffered networks, cause FAILURE_THRESHOLD failures for each failure type to one + * of each network (leaving one unfailed). + * Expected Behavior: 3 of the Available Networks report OverFailureThreshold + */ + @Test + public void testFailureCounting_failureOverThresholdCheck() throws Exception { + int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD; + int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD; + int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + } + assertEquals(true, mLastResortWatchdog.isOverFailureThreshold(mBssids[0])); + assertEquals(true, mLastResortWatchdog.isOverFailureThreshold(mBssids[1])); + assertEquals(true, mLastResortWatchdog.isOverFailureThreshold(mBssids[2])); + assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[3])); + } + + /** + * Case 12: Test Failure Counting, under failure Threshold check + * Test has 4 buffered networks, cause FAILURE_THRESHOLD - 1 failures for each failure type to + * one of each network (leaving one unfailed). + * Expected Behavior: 0 of the Available Networks report OverFailureThreshold + */ + @Test + public void testFailureCounting_failureUnderThresholdCheck() throws Exception { + int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; + int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; + int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + } + assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[0])); + assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[1])); + assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[2])); + assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[3])); + } + + /** + * Case 13: Test Failure Counting, available network buffering does not affect counts + * In this test: + * 4 networks are buffered + * Some number of failures are counted + * networks are buffered again + * Expected Behavior: Failure counts are not modified by buffering + */ + @Test + public void testAvailableNetworkBuffering_doesNotAffectFailureCounts() { + int associationRejections = 5; + int authenticationFailures = 9; + int dhcpFailures = 11; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).associationRejection); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).authenticationFailure); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).dhcpFailure); + } + // Check Each Network has appropriate failure count + assertFailureCountEquals(mBssids[0], associationRejections, 0, 0); + assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0); + assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures); + assertFailureCountEquals(mBssids[3], 0, 0, 0); + + // Re-buffer all networks + for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) { + mLastResortWatchdog.updateAvailableNetworks(candidates); + } + + // Check Each Network still has appropriate failure count + assertFailureCountEquals(mBssids[0], associationRejections, 0, 0); + assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0); + assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures); + assertFailureCountEquals(mBssids[3], 0, 0, 0); + } + + /** + * Case 14: Test Failure Counting, culling of an old network will remove its failure counts + * In this test: + * 4 networks are buffered + * Some number of failures are counted for all networks + * 3 of the networks are buffered until the 4th dies of old age + * The 4th network is re-buffered + * Expected Behavior: Failure counts for the 4th network are cleared after re-buffering + */ + @Test + public void testAvailableNetworkBuffering_rebufferWipesCounts() { + int associationRejections = 5; + int authenticationFailures = 9; + int dhcpFailures = 11; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).associationRejection); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).authenticationFailure); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks() + .get(mBssids[net]).dhcpFailure); + } + // Check Each Network has appropriate failure count + assertFailureCountEquals(mBssids[0], associationRejections, 0, 0); + assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0); + assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures); + assertFailureCountEquals(mBssids[3], 0, 0, 0); + + // Re-buffer all networks except 'test1' until it dies of old age + candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 1, 4), + Arrays.copyOfRange(mBssids, 1, 4), + Arrays.copyOfRange(mFrequencies, 1, 4), + Arrays.copyOfRange(mCaps, 1, 4), + Arrays.copyOfRange(mLevels, 1, 4), + Arrays.copyOfRange(mIsEphemeral, 1, 4)); + for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) { + mLastResortWatchdog.updateAvailableNetworks(candidates); + } + assertEquals(3, mLastResortWatchdog.getRecentAvailableNetworks().size()); + // Re-buffer All networks, with 'test1' again + candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Check Each Network has appropriate failure count (network 1 should be zero'd) + assertFailureCountEquals(mBssids[0], 0, 0, 0); + assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0); + assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures); + assertFailureCountEquals(mBssids[3], 0, 0, 0); + } + + /** + * Case 26: Test Failure Counting, null failure incrementation + * In this test: + * 4 networks are buffered + * Attempt to increment failures with null BSSID & SSID + * Expected behavior: Nothing breaks, no counts incremented + */ + @Test + public void testFailureCounting_nullInputsNoBreaky() { + int associationRejections = 5; + int authenticationFailures = 9; + int dhcpFailures = 11; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids, + mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + + //Increment failure count for each network and failure type + int net = 0; + for (int i = 0; i < associationRejections; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(null, mBssids[net], + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + } + net = 1; + for (int i = 0; i < authenticationFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], null, + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + } + net = 2; + for (int i = 0; i < dhcpFailures; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(null, null, + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + } + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < mSsids.length; i++) { + assertFailureCountEquals(mBssids[i], 0, 0, 0); + } + } + + /** + * Case 27: Test Failure Counting, test all failures are counted across SSID + * In this test there are 8 networks, + * the first 4 networks have unique SSIDs amongst themselves, + * the last 4 networks share these SSIDs respectively, so there are 2 networks per SSID + * In this test we increment failure counts for the 'test1' ssid for a specific BSSID, and for + * the 'test2' ssid for BSSID_ANY. + * Expected behaviour: Failure counts for both networks on the same SSID are mirrored via both + * incrementation methods + */ + @Test + public void testFailureCounting_countFailuresAcrossSsids() throws Exception { + String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\"", + "\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""}; + String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55", + "c0:ff:ee:ee:e3:ee", "6c:f3:7f:ae:3c:f3", "6c:f3:7f:ae:3c:f4", "d3:ad:ba:b1:35:55", + "c0:ff:ee:ee:33:ee"}; + int[] frequencies = {2437, 5180, 5180, 2437, 2437, 5180, 5180, 2437}; + String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", + "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", + "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"}; + int[] levels = {-60, -86, -50, -62, -60, -86, -50, -62}; + boolean[] isEphemeral = {false, false, false, false, false, false, false, false}; + boolean[] hasEverConnected = {false, false, false, false, false, false, false, + false}; + int firstNetFails = 13; + int secondNetFails = 8; + // Buffer potential candidates 1,2,3 & 4 + List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids, + bssids, frequencies, caps, levels, isEphemeral, hasEverConnected); + mLastResortWatchdog.updateAvailableNetworks(candidates); + + // Ensure new networks have zero'ed failure counts + for (int i = 0; i < ssids.length; i++) { + assertFailureCountEquals(bssids[i], 0, 0, 0); + } + + //Increment failure count for the first test network ssid & bssid + for (int i = 0; i < firstNetFails; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_DHCP); + } + //Increment failure count for the first test network ssid & BSSID_ANY + for (int i = 0; i < secondNetFails; i++) { + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[1], WifiLastResortWatchdog.BSSID_ANY, + WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION); + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[1], WifiLastResortWatchdog.BSSID_ANY, + WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION); + mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded( + ssids[1], WifiLastResortWatchdog.BSSID_ANY, + WifiLastResortWatchdog.FAILURE_CODE_DHCP); + } + assertFailureCountEquals(bssids[0], firstNetFails, firstNetFails, firstNetFails); + assertFailureCountEquals(bssids[1], secondNetFails, secondNetFails, secondNetFails); + assertFailureCountEquals(bssids[2], 0, 0, 0); + assertFailureCountEquals(bssids[3], 0, 0, 0); + assertFailureCountEquals(bssids[4], firstNetFails, firstNetFails, firstNetFails); + assertFailureCountEquals(bssids[5], secondNetFails, secondNetFails, secondNetFails); + assertFailureCountEquals(bssids[6], 0, 0, 0); + assertFailureCountEquals(bssids[7], 0, 0, 0); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java index 7b09b9f4a..6f635e72d 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java @@ -331,6 +331,8 @@ public class WifiStateMachineTest { @Mock WifiApConfigStore mApConfigStore; @Mock BackupManagerProxy mBackupManagerProxy; @Mock WifiCountryCode mCountryCode; + @Mock WifiInjector mWifiInjector; + @Mock WifiLastResortWatchdog mWifiLastResortWatchdog; public WifiStateMachineTest() throws Exception { } @@ -349,10 +351,9 @@ public class WifiStateMachineTest { TestUtil.installWlanWifiNative(mWifiNative); mWifiMonitor = new MockWifiMonitor(); - mWifiMetrics = mock(WifiMetrics.class); - WifiInjector wifiInjector = mock(WifiInjector.class); - when(wifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics); - when(wifiInjector.getClock()).thenReturn(mock(Clock.class)); + when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics); + when(mWifiInjector.getClock()).thenReturn(mock(Clock.class)); + when(mWifiInjector.getWifiLastResortWatchdog()).thenReturn(mWifiLastResortWatchdog); FrameworkFacade factory = getFrameworkFacade(); Context context = getContext(); @@ -378,7 +379,7 @@ public class WifiStateMachineTest { new UserInfo(11, "managed profile", 0))); mWsm = new WifiStateMachine(context, factory, mLooper.getLooper(), - mUserManager, wifiInjector, mBackupManagerProxy, mCountryCode); + mUserManager, mWifiInjector, mBackupManagerProxy, mCountryCode); mWsmThread = getWsmHandlerThread(mWsm); final AsyncChannel channel = new AsyncChannel(); |