diff options
author | Glen Kuhne <kuh@google.com> | 2016-03-30 11:42:02 -0700 |
---|---|---|
committer | Glen Kuhne <kuh@google.com> | 2016-04-14 11:08:50 -0700 |
commit | 09abbe29be6e552a2531b0367bd6d29647d33767 (patch) | |
tree | a7f7d26414491754e55a4176f74e9a9358921841 /service | |
parent | 42396f489e485671100353beb6102d315ff3a542 (diff) |
Created LastResortWatchdog class
Created the WifiLastResortWatchdog class, that will handle restarting
the wifi stack as a last resort when wifi is failing.
Implemented the logic that tracks failure counts for all available
networks, and the maintaining of that list of available networks.
BUG=27856523
Change-Id: I8c944d033955ad7e5cc9484cce8f20cd3755312e
Diffstat (limited to 'service')
5 files changed, 215 insertions, 56 deletions
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java index 1ed257241..d80127488 100644 --- a/service/java/com/android/server/wifi/WifiConnectivityManager.java +++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java @@ -83,6 +83,7 @@ public class WifiConnectivityManager { private final AlarmManager mAlarmManager; private final LocalLog mLocalLog = new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 1024 : 16384); + private final WifiLastResortWatchdog mWifiLastResortWatchdog; private boolean mDbg = false; private boolean mWifiEnabled = false; private boolean mWifiConnectivityManagerEnabled = true; @@ -147,6 +148,28 @@ public class WifiConnectivityManager { } }; + /** + * Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener. + * Executes selection of potential network candidates, initiation of connection attempt to that + * network. + */ + private void handleScanResults(List<ScanDetail> scanDetails, String listenerName) { + localLog(listenerName + " onResults: start QNS"); + WifiConfiguration candidate = + mQualifiedNetworkSelector.selectQualifiedNetwork(mForceSelectNetwork, + mUntrustedConnectionAllowed, scanDetails, + mStateMachine.isLinkDebouncing(), mStateMachine.isConnected(), + mStateMachine.isDisconnected(), + mStateMachine.isSupplicantTransientState()); + mWifiLastResortWatchdog.updateAvailableNetworks( + mQualifiedNetworkSelector.getFilteredScanDetails()); + if (candidate != null) { + localLog(listenerName + ": QNS candidate-" + candidate.SSID); + connectToNetwork(candidate); + } + + } + // Periodic scan results listener. A periodic scan is initiated when // screen is on. private class PeriodicScanListener implements WifiScanner.ScanListener { @@ -188,21 +211,7 @@ public class WifiConnectivityManager { @Override public void onResults(WifiScanner.ScanData[] results) { - localLog("PeriodicScanListener onResults: start QNS"); - - WifiConfiguration candidate = - mQualifiedNetworkSelector.selectQualifiedNetwork(mForceSelectNetwork, - mUntrustedConnectionAllowed, mScanDetails, - mStateMachine.isLinkDebouncing(), mStateMachine.isConnected(), - mStateMachine.isDisconnected(), - mStateMachine.isSupplicantTransientState()); - - if (candidate != null) { - localLog("PeriodicScanListener: QNS candidate-" + candidate.SSID); - - connectToNetwork(candidate); - } - + handleScanResults(mScanDetails, "PeriodicScanListener"); clearScanDetails(); } @@ -262,19 +271,7 @@ public class WifiConnectivityManager { @Override public void onResults(WifiScanner.ScanData[] results) { - localLog("SingleScanListener onResults: start QNS"); - - WifiConfiguration candidate = - mQualifiedNetworkSelector.selectQualifiedNetwork(mForceSelectNetwork, - mUntrustedConnectionAllowed, mScanDetails, - mStateMachine.isLinkDebouncing(), mStateMachine.isConnected(), - mStateMachine.isDisconnected(), - mStateMachine.isSupplicantTransientState()); - - if (candidate != null) { - localLog("SingleScanListener: QNS candidate-" + candidate.SSID); - connectToNetwork(candidate); - } + handleScanResults(mScanDetails, "SingleScanListener"); } @Override @@ -349,20 +346,7 @@ public class WifiConnectivityManager { for (ScanResult result: results) { mScanDetails.add(ScanDetailUtil.toScanDetail(result)); } - - localLog("PnoScanListener: onPnoNetworkFound: start QNS"); - - WifiConfiguration candidate = - mQualifiedNetworkSelector.selectQualifiedNetwork(mForceSelectNetwork, - mUntrustedConnectionAllowed, mScanDetails, - mStateMachine.isLinkDebouncing(), mStateMachine.isConnected(), - mStateMachine.isDisconnected(), - mStateMachine.isSupplicantTransientState()); - - if (candidate != null) { - localLog("PnoScanListener: OnPnoNetworkFound: QNS candidate-" + candidate.SSID); - connectToNetwork(candidate); - } + handleScanResults(mScanDetails, "PnoScanListener"); } } @@ -373,13 +357,15 @@ public class WifiConnectivityManager { */ public WifiConnectivityManager(Context context, WifiStateMachine stateMachine, WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo, - WifiQualifiedNetworkSelector qualifiedNetworkSelector) { + WifiQualifiedNetworkSelector qualifiedNetworkSelector, + WifiInjector wifiInjector) { mStateMachine = stateMachine; mScanner = scanner; mConfigManager = configManager; mWifiInfo = wifiInfo; mQualifiedNetworkSelector = qualifiedNetworkSelector; mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + mWifiLastResortWatchdog = wifiInjector.getWifiLastResortWatchdog(); mMin5GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_5G_ACCEPT_RSSI; mMin24GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_2G_ACCEPT_RSSI; diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index b2792cb95..2419e19a5 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -31,8 +31,13 @@ public class WifiInjector { } private final WifiMetrics mWifiMetrics = new WifiMetrics(); + private final WifiLastResortWatchdog mWifiLastResortWatchdog = new WifiLastResortWatchdog(); public WifiMetrics getWifiMetrics() { return mWifiMetrics; } + + public WifiLastResortWatchdog getWifiLastResortWatchdog() { + return mWifiLastResortWatchdog; + } } diff --git a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java new file mode 100644 index 000000000..36f0656a8 --- /dev/null +++ b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2016 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.net.wifi.ScanResult; +import android.net.wifi.WifiConfiguration; +import android.util.Log; +import android.util.Pair; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * <TBD> Intended Purpose/Behavior of the class upon completion: + * 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; + /** + * 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; + + /** + * 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 + * candidates + */ + public void updateAvailableNetworks( + List<Pair<ScanDetail, WifiConfiguration>> availableNetworkFailureCounts) { + // Add new networks to mRecentAvailableNetworks + if (availableNetworkFailureCounts != null) { + for (Pair<ScanDetail, WifiConfiguration> pair : availableNetworkFailureCounts) { + ScanResult scanResult = pair.first.getScanResult(); + if (scanResult == null) continue; + String key = scanResult.BSSID; + + // 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 { + // New network is available + availableNetworkFailureCount = new AvailableNetworkFailureCount(pair.second); + availableNetworkFailureCount.Ssid = pair.first.getSSID(); + } + // If we saw a network, set its Age to -1 here, next incrementation will set it to 0 + availableNetworkFailureCount.age = -1; + mRecentAvailableNetworks.put(key, availableNetworkFailureCount); + } + } + + // Iterate through available networks updating timeout counts & removing networks. + Iterator<Map.Entry<String, AvailableNetworkFailureCount>> it = + mRecentAvailableNetworks.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, AvailableNetworkFailureCount> entry = it.next(); + if (entry.getValue().age < MAX_BSSID_AGE - 1) { + entry.getValue().age++; + } else { + it.remove(); + } + } + if (VDBG) Log.v(TAG, toString()); + } + + /** + * Gets the buffer of recently available networks + */ + Map<String, AvailableNetworkFailureCount> getRecentAvailableNetworks() { + return mRecentAvailableNetworks; + } + + /** + * Prints all networks & counts within mRecentAvailableNetworks to string + */ + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("WifiLastResortWatchdog: " + mRecentAvailableNetworks.size() + " networks..."); + for (Map.Entry<String, AvailableNetworkFailureCount> entry + : mRecentAvailableNetworks.entrySet()) { + sb.append("\n " + entry.getKey() + ": " + entry.getValue()); + } + return sb.toString(); + } + + static class AvailableNetworkFailureCount { + /** + * WifiConfiguration associated with this network. Can be null for Ephemeral networks + */ + public WifiConfiguration config; + /** + * SSID of the network (from ScanDetail) + */ + public String Ssid = ""; + /** + * Number of times network has failed for this reason + */ + public int associationRejection = 0; + /** + * Number of times network has failed for this reason + */ + public int authenticationRejection = 0; + /** + * Number of times network has failed for this reason + */ + public int dhcpFailure = 0; + /** + * Number of scanResults since this network was last seen + */ + public int age = 0; + + AvailableNetworkFailureCount(WifiConfiguration config) { + config = config; + } + + void resetCounts() { + associationRejection = 0; + authenticationRejection = 0; + dhcpFailure = 0; + } + + public String toString() { + return Ssid + ", HasEverConnected: " + ((config != null) + ? config.getNetworkSelectionStatus().getHasEverConnected() : false) + + ", Failures: {" + + "Assoc: " + associationRejection + + ", Auth: " + authenticationRejection + + ", Dhcp: " + dhcpFailure + + "}" + + ", Age: " + age; + } + } +} diff --git a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java index d8e5319d1..af2b16bbc 100644 --- a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java +++ b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java @@ -27,6 +27,7 @@ import android.net.wifi.WifiManager; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; +import android.util.Pair; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -57,8 +58,9 @@ public class WifiQualifiedNetworkSelector { private String mCurrentBssid = null; //buffer most recent scan results private List<ScanDetail> mScanDetails = null; - //buffer of filtered scan results (Scan results considered by network selection) - private volatile List<ScanDetail> mFilteredScanDetails = null; + //buffer of filtered scan results (Scan results considered by network selection) & associated + //WifiConfiguration (if any) + private volatile List<Pair<ScanDetail, WifiConfiguration>> mFilteredScanDetails = null; //Minimum time gap between last successful Qualified Network Selection and new selection attempt //usable only when current state is connected state default 10 s @@ -143,7 +145,7 @@ public class WifiQualifiedNetworkSelector { * run. This includes scan details of sufficient signal strength, and had an associated * WifiConfiguration. */ - public List<ScanDetail> getFilteredScanDetails() { + public List<Pair<ScanDetail, WifiConfiguration>> getFilteredScanDetails() { return mFilteredScanDetails; } @@ -606,7 +608,7 @@ public class WifiQualifiedNetworkSelector { boolean isSupplicantTransient) { localLog("==========start qualified Network Selection=========="); mScanDetails = scanDetails; - List<ScanDetail> filteredScanDetails = new ArrayList<>(); + List<Pair<ScanDetail, WifiConfiguration>> filteredScanDetails = new ArrayList<>(); if (mCurrentConnectedNetwork == null) { mCurrentConnectedNetwork = mWifiConfigManager.getWifiConfiguration(mWifiInfo.getNetworkId()); @@ -699,6 +701,8 @@ public class WifiQualifiedNetworkSelector { //check whether this scan result belong to a saved network boolean potentiallyEphemeral = false; + // This local only used to store ephemeral config for filtering scan results + WifiConfiguration filteredEphemeralConfig = null; List<WifiConfiguration> associatedWifiConfigurations = mWifiConfigManager.updateSavedNetworkWithNewScanDetail(scanDetail); if (associatedWifiConfigurations == null) { @@ -710,6 +714,7 @@ public class WifiQualifiedNetworkSelector { //if there are more than 1 associated network, it must be a passpoint network WifiConfiguration network = associatedWifiConfigurations.get(0); if (network.ephemeral) { + filteredEphemeralConfig = network; potentiallyEphemeral = true; } } @@ -726,15 +731,11 @@ public class WifiQualifiedNetworkSelector { localLog(scanId + " become the new untrusted candidate"); } // scanDetail is for available ephemeral network - filteredScanDetails.add(scanDetail); + filteredScanDetails.add(Pair.create(scanDetail, filteredEphemeralConfig)); } } continue; - } else { - // scanDetail is for available saved network - filteredScanDetails.add(scanDetail); } - // calculate the core of each scanresult whose associated network is not ephemeral. Due // to one scane result can associated with more than 1 network, we need calcualte all // the scores and use the highest one as the scanresults score @@ -770,6 +771,8 @@ public class WifiQualifiedNetworkSelector { status.setCandidateScore(score); } } + // Create potential filteredScanDetail entry + filteredScanDetails.add(Pair.create(scanDetail, configurationCandidateForThisScan)); if (highestScore > currentHighestScore || (highestScore == currentHighestScore && scanResultCandidate != null diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 19489bfe4..e2514fba2 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -182,8 +182,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss protected void log(String s) {; Log.d(getName(), s); } - + private WifiLastResortWatchdog mWifiLastResortWatchdog; private WifiMetrics mWifiMetrics; + private WifiInjector mWifiInjector; private WifiMonitor mWifiMonitor; private WifiNative mWifiNative; private WifiConfigManager mWifiConfigManager; @@ -1015,8 +1016,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss BackupManagerProxy backupManagerProxy, WifiCountryCode countryCode) { super("WifiStateMachine", looper); - - mWifiMetrics = wifiInjector.getWifiMetrics(); + mWifiInjector = wifiInjector; + mWifiMetrics = mWifiInjector.getWifiMetrics(); + mWifiLastResortWatchdog = wifiInjector.getWifiLastResortWatchdog(); mContext = context; mFacade = facade; mWifiNative = WifiNative.getWlanNativeInterface(); @@ -4671,7 +4673,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss (WifiScanner) mContext.getSystemService(Context.WIFI_SCANNING_SERVICE); mWifiConnectivityManager = new WifiConnectivityManager(mContext, WifiStateMachine.this, mWifiScanner, mWifiConfigManager, mWifiInfo, - mWifiQualifiedNetworkSelector); + mWifiQualifiedNetworkSelector, mWifiInjector); } mWifiLogger.startLogging(DBG); |