summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorGlen Kuhne <kuh@google.com>2016-03-30 11:42:02 -0700
committerGlen Kuhne <kuh@google.com>2016-04-14 11:08:50 -0700
commit09abbe29be6e552a2531b0367bd6d29647d33767 (patch)
treea7f7d26414491754e55a4176f74e9a9358921841 /service
parent42396f489e485671100353beb6102d315ff3a542 (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')
-rw-r--r--service/java/com/android/server/wifi/WifiConnectivityManager.java72
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java5
-rw-r--r--service/java/com/android/server/wifi/WifiLastResortWatchdog.java163
-rw-r--r--service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java21
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java10
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);