summaryrefslogtreecommitdiff
path: root/service/java/com/android/server/wifi/WifiLastResortWatchdog.java
diff options
context:
space:
mode:
Diffstat (limited to 'service/java/com/android/server/wifi/WifiLastResortWatchdog.java')
-rw-r--r--service/java/com/android/server/wifi/WifiLastResortWatchdog.java831
1 files changed, 0 insertions, 831 deletions
diff --git a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java b/service/java/com/android/server/wifi/WifiLastResortWatchdog.java
deleted file mode 100644
index 9846747f6..000000000
--- a/service/java/com/android/server/wifi/WifiLastResortWatchdog.java
+++ /dev/null
@@ -1,831 +0,0 @@
-/*
- * 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.content.Context;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.wifi.resources.R;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * 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 ClientModeImpl to InitialState.
- */
-public class WifiLastResortWatchdog {
- private static final String TAG = "WifiLastResortWatchdog";
- private boolean mVerboseLoggingEnabled = false;
- /**
- * 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;
- public static final String BUGREPORT_TITLE = "Wifi watchdog triggered";
- public static final double PROB_TAKE_BUGREPORT_DEFAULT = 1;
-
- // Number of milliseconds to wait before re-enable Watchdog triger
- @VisibleForTesting
- public static final long LAST_TRIGGER_TIMEOUT_MILLIS = 2 * 3600 * 1000; // 2 hours
-
-
- /**
- * 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<>();
-
- /**
- * 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<>();
-
- /* List of failure BSSID */
- private Set<String> mBssidFailureList = new HashSet<>();
-
- // Tracks: if ClientModeImpl is in ConnectedState
- private boolean mWifiIsConnected = false;
- // Is Watchdog allowed to trigger now? Set to false after triggering. Set to true after
- // successfully connecting or a new network (SSID) becomes available to connect to.
- private boolean mWatchdogAllowedToTrigger = true;
- private long mTimeLastTrigger = 0;
- private String mSsidLastTrigger = null;
-
- private WifiInjector mWifiInjector;
- private WifiMetrics mWifiMetrics;
- private ClientModeImpl mClientModeImpl;
- private Looper mClientModeImplLooper;
- private double mBugReportProbability = PROB_TAKE_BUGREPORT_DEFAULT;
- private Clock mClock;
- private Context mContext;
- private DeviceConfigFacade mDeviceConfigFacade;
- // If any connection failure happened after watchdog triggering restart then assume watchdog
- // did not fix the problem
- private boolean mWatchdogFixedWifi = true;
- private long mLastStartConnectTime = 0;
- private final Handler mHandler;
- private final WifiThreadRunner mWifiThreadRunner;
-
- private Boolean mWatchdogFeatureEnabled = null;
-
- /**
- * Local log used for debugging any WifiLastResortWatchdog issues.
- */
- private final LocalLog mLocalLog = new LocalLog(100);
-
- WifiLastResortWatchdog(WifiInjector wifiInjector, Context context, Clock clock,
- WifiMetrics wifiMetrics, ClientModeImpl clientModeImpl, Looper clientModeImplLooper,
- DeviceConfigFacade deviceConfigFacade, WifiThreadRunner wifiThreadRunner) {
- mWifiInjector = wifiInjector;
- mClock = clock;
- mWifiMetrics = wifiMetrics;
- mClientModeImpl = clientModeImpl;
- mClientModeImplLooper = clientModeImplLooper;
- mContext = context;
- mDeviceConfigFacade = deviceConfigFacade;
- mWifiThreadRunner = wifiThreadRunner;
- mHandler = new Handler(clientModeImplLooper) {
- public void handleMessage(Message msg) {
- processMessage(msg);
- }
- };
- }
-
- /**
- * Returns handler for L2 events from supplicant.
- * @return Handler
- */
- public Handler getHandler() {
- return mHandler;
- }
-
- /**
- * Refreshes when the last CMD_START_CONNECT is triggered.
- */
- public void noteStartConnectTime() {
- mHandler.post(() -> {
- mLastStartConnectTime = mClock.getElapsedSinceBootMillis();
- });
- }
-
- private void processMessage(Message msg) {
- switch (msg.what) {
- case WifiMonitor.NETWORK_CONNECTION_EVENT:
- // Trigger bugreport for successful connections that take abnormally long
- if (mDeviceConfigFacade.isAbnormalConnectionBugreportEnabled()
- && mLastStartConnectTime > 0) {
- long durationMs = mClock.getElapsedSinceBootMillis() - mLastStartConnectTime;
- long abnormalConnectionDurationMs =
- mDeviceConfigFacade.getAbnormalConnectionDurationMs();
- if (durationMs > abnormalConnectionDurationMs) {
- final String bugTitle = "Wi-Fi Bugreport: Abnormal connection time";
- final String bugDetail = "Expected connection to take less than "
- + abnormalConnectionDurationMs + " milliseconds. "
- + "Actually took " + durationMs + " milliseconds.";
- logv("Triggering bug report for abnormal connection time.");
- mWifiThreadRunner.post(() ->
- mClientModeImpl.takeBugReport(bugTitle, bugDetail));
- }
- }
- // Should reset last connection time after each connection regardless if bugreport
- // is enabled or not.
- mLastStartConnectTime = 0;
- break;
- default:
- return;
- }
- }
-
- /**
- * 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 availableNetworks ScanDetail & Config list of potential connection
- * candidates
- */
- public void updateAvailableNetworks(
- List<Pair<ScanDetail, WifiConfiguration>> availableNetworks) {
- // Add new networks to mRecentAvailableNetworks
- if (availableNetworks != null) {
- if (mVerboseLoggingEnabled) {
- Log.v(TAG, "updateAvailableNetworks: size = " + availableNetworks.size());
- }
- 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 bssid = scanResult.BSSID;
- String ssid = "\"" + scanDetail.getSSID() + "\"";
- if (mVerboseLoggingEnabled) {
- Log.v(TAG, " " + bssid + ": " + scanDetail.getSSID());
- }
- // Cache the scanResult & WifiConfig
- AvailableNetworkFailureCount availableNetworkFailureCount =
- mRecentAvailableNetworks.get(bssid);
- if (availableNetworkFailureCount == null) {
- // New network is available
- 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);
- // Do not re-enable Watchdog in LAST_TRIGGER_TIMEOUT_MILLIS
- // after last time Watchdog be triggered
- if (!mWatchdogAllowedToTrigger && (mTimeLastTrigger == 0
- || (mClock.getElapsedSinceBootMillis() - mTimeLastTrigger)
- >= LAST_TRIGGER_TIMEOUT_MILLIS)) {
- localLog("updateAvailableNetworks: setWatchdogTriggerEnabled to true");
- setWatchdogTriggerEnabled(true);
- }
- } 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);
- }
- // refresh config if it is not null
- if (config != null) {
- 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(bssid, 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 {
- // 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 {
- Log.d(TAG, "updateAvailableNetworks: SSID to AP count mismatch for " + ssid);
- }
- it.remove();
- }
- }
- if (mVerboseLoggingEnabled) Log.v(TAG, toString());
- }
-
- /**
- * 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 ClientModeImpl for this failure
- * @return true if watchdog triggers, returned for test visibility
- */
- public boolean noteConnectionFailureAndTriggerIfNeeded(String ssid, String bssid, int reason) {
- if (mVerboseLoggingEnabled) {
- Log.v(TAG, "noteConnectionFailureAndTriggerIfNeeded: [" + ssid + ", " + bssid + ", "
- + reason + "]");
- }
-
- // Update failure count for the failing network
- updateFailureCountForNetwork(ssid, bssid, reason);
-
- // If watchdog is not allowed to trigger it means a wifi restart is already triggered
- if (!mWatchdogAllowedToTrigger) {
- mWifiMetrics.incrementWatchdogTotalConnectionFailureCountAfterTrigger();
- mWatchdogFixedWifi = false;
- }
- // Have we met conditions to trigger the Watchdog Wifi restart?
- boolean isRestartNeeded = checkTriggerCondition();
- if (mVerboseLoggingEnabled) {
- Log.v(TAG, "isRestartNeeded = " + isRestartNeeded);
- }
- if (isRestartNeeded) {
- if (getWifiWatchdogFeature()) {
- // Stop the watchdog from triggering until re-enabled
- localLog("Trigger recovery: setWatchdogTriggerEnabled to false");
- setWatchdogTriggerEnabled(false);
- mWatchdogFixedWifi = true;
- loge("Watchdog triggering recovery");
- mSsidLastTrigger = ssid;
- mTimeLastTrigger = mClock.getElapsedSinceBootMillis();
- localLog(toString());
- mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
- incrementWifiMetricsTriggerCounts();
- } else {
- // auto bugreport if issue happens
- loge("bugreport notification");
- setWatchdogTriggerEnabled(false);
- takeBugReportWithCurrentProbability("Wifi Watchdog bite");
- }
- }
- return isRestartNeeded;
- }
-
- /**
- * Handles transitions entering and exiting ClientModeImpl ConnectedState
- * Used to track wifistate, and perform watchdog count resetting
- * @param isEntering true if called from ConnectedState.enter(), false for exit()
- */
- public void connectedStateTransition(boolean isEntering) {
- logv("connectedStateTransition: isEntering = " + isEntering);
-
- mWifiIsConnected = isEntering;
- if (!isEntering) {
- return;
- }
- if (!mWatchdogAllowedToTrigger && mWatchdogFixedWifi
- && getWifiWatchdogFeature()
- && checkIfAtleastOneNetworkHasEverConnected()
- && checkIfConnectedBackToSameSsid()
- && checkIfConnectedBssidHasEverFailed()) {
- takeBugReportWithCurrentProbability("Wifi fixed after restart");
- // WiFi has connected after a Watchdog trigger, without any new networks becoming
- // available, log a Watchdog success in wifi metrics
- mWifiMetrics.incrementNumLastResortWatchdogSuccesses();
- long durationMs = mClock.getElapsedSinceBootMillis() - mTimeLastTrigger;
- mWifiMetrics.setWatchdogSuccessTimeDurationMs(durationMs);
- }
- // If the watchdog trigger was disabled (it triggered), connecting means we did
- // something right, re-enable it so it can fire again.
- localLog("connectedStateTransition: setWatchdogTriggerEnabled to true");
- setWatchdogTriggerEnabled(true);
- }
-
- /**
- * Helper function to check if device connected to BSSID
- * which is in BSSID failure list after watchdog trigger.
- */
- private boolean checkIfConnectedBssidHasEverFailed() {
- return mBssidFailureList.contains(mClientModeImpl.getWifiInfo().getBSSID());
- }
-
- /**
- * Helper function to check if device connect back to same
- * SSID after watchdog trigger
- */
- private boolean checkIfConnectedBackToSameSsid() {
- if (TextUtils.equals(mSsidLastTrigger, mClientModeImpl.getWifiInfo().getSSID())) {
- return true;
- }
- localLog("checkIfConnectedBackToSameSsid: different SSID be connected");
- return false;
- }
-
- /**
- * Triggers a wifi specific bugreport with a based on the current trigger probability.
- * @param bugDetail description of the bug
- */
- private void takeBugReportWithCurrentProbability(String bugDetail) {
- if (mBugReportProbability <= Math.random()) {
- return;
- }
- (new Handler(mClientModeImplLooper)).post(() -> {
- mClientModeImpl.takeBugReport(BUGREPORT_TITLE, bugDetail);
- });
- }
-
- /**
- * 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 ClientModeImpl for this failure
- */
- private void updateFailureCountForNetwork(String ssid, String bssid, int reason) {
- logv("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);
- mBssidFailureList.add(bssid);
- }
- }
-
- /**
- * 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) {
- Log.d(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) {
- Log.d(TAG, "updateFailureCountForNetwork: Unable to find Network [" + ssid
- + ", " + bssid + "]");
- return;
- }
- if (!availableNetworkFailureCount.ssid.equals(ssid)) {
- Log.d(TAG, "updateFailureCountForNetwork: Failed connection attempt has"
- + " wrong ssid. Failed [" + ssid + ", " + bssid + "], buffered ["
- + availableNetworkFailureCount.ssid + ", " + bssid + "]");
- return;
- }
- if (availableNetworkFailureCount.config == null) {
- if (mVerboseLoggingEnabled) {
- Log.v(TAG, "updateFailureCountForNetwork: network has no config ["
- + ssid + ", " + bssid + "]");
- }
- }
- availableNetworkFailureCount.incrementFailureCount(reason);
- incrementSsidFailureCount(ssid, reason);
- }
-
- /**
- * Helper function to check if we should ignore BSSID update.
- * @param bssid BSSID of the access point
- * @return true if we should ignore BSSID update
- */
- public boolean shouldIgnoreBssidUpdate(String bssid) {
- return mWatchdogAllowedToTrigger
- && isBssidOnlyApOfSsid(bssid)
- && isSingleSsidRecorded()
- && checkIfAtleastOneNetworkHasEverConnected();
- }
-
- /**
- * Helper function to check if we should ignore SSID update.
- * @return true if should ignore SSID update
- */
- public boolean shouldIgnoreSsidUpdate() {
- return mWatchdogAllowedToTrigger
- && isSingleSsidRecorded()
- && checkIfAtleastOneNetworkHasEverConnected();
- }
-
- /**
- * Check the specified BSSID is the only BSSID for its corresponding SSID.
- * @param bssid BSSID of the access point
- * @return true if only BSSID for its corresponding SSID be observed
- */
- private boolean isBssidOnlyApOfSsid(String bssid) {
- AvailableNetworkFailureCount availableNetworkFailureCount =
- mRecentAvailableNetworks.get(bssid);
- if (availableNetworkFailureCount == null) {
- return false;
- }
- String ssid = availableNetworkFailureCount.ssid;
- Pair<AvailableNetworkFailureCount, Integer> ssidFails = mSsidFailureCount.get(ssid);
- if (ssidFails == null) {
- Log.d(TAG, "isOnlyBssidAvailable: Could not find SSID count for " + ssid);
- return false;
- }
- if (ssidFails.second != 1) {
- return false;
- }
- return true;
- }
-
- /**
- * Check there is only single SSID be observed.
- * @return true if only single SSID be observed.
- */
- private boolean isSingleSsidRecorded() {
- return (mSsidFailureCount.size() == 1);
- }
-
- /**
- * Check trigger condition: For all available networks, have we met a failure threshold for each
- * of them, and have previously connected to at-least one of the available networks
- * @return is the trigger condition true
- */
- private boolean checkTriggerCondition() {
- if (mVerboseLoggingEnabled) Log.v(TAG, "checkTriggerCondition.");
- // Don't check Watchdog trigger if wifi is in a connected state
- // (This should not occur, but we want to protect against any race conditions)
- if (mWifiIsConnected) return false;
- // Don't check Watchdog trigger if trigger is not enabled
- if (!mWatchdogAllowedToTrigger) return false;
-
- for (Map.Entry<String, AvailableNetworkFailureCount> entry
- : mRecentAvailableNetworks.entrySet()) {
- if (!isOverFailureThreshold(entry.getKey())) {
- // This available network is not over failure threshold, meaning we still have a
- // network to try connecting to
- return false;
- }
- }
- // We have met the failure count for every available network.
- // Trigger restart if there exists at-least one network that we have previously connected.
- boolean atleastOneNetworkHasEverConnected = checkIfAtleastOneNetworkHasEverConnected();
- logv("checkTriggerCondition: return = " + atleastOneNetworkHasEverConnected);
- return checkIfAtleastOneNetworkHasEverConnected();
- }
-
- private boolean checkIfAtleastOneNetworkHasEverConnected() {
- for (Map.Entry<String, AvailableNetworkFailureCount> entry
- : mRecentAvailableNetworks.entrySet()) {
- if (entry.getValue().config != null
- && entry.getValue().config.getNetworkSelectionStatus().hasEverConnected()) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Update WifiMetrics with various Watchdog stats (trigger counts, failed network counts)
- */
- private void incrementWifiMetricsTriggerCounts() {
- if (mVerboseLoggingEnabled) Log.v(TAG, "incrementWifiMetricsTriggerCounts.");
- mWifiMetrics.incrementNumLastResortWatchdogTriggers();
- mWifiMetrics.addCountToNumLastResortWatchdogAvailableNetworksTotal(
- mSsidFailureCount.size());
- // Number of networks over each failure type threshold, present at trigger time
- int badAuth = 0;
- int badAssoc = 0;
- int badDhcp = 0;
- int badSum = 0;
- for (Map.Entry<String, Pair<AvailableNetworkFailureCount, Integer>> entry
- : mSsidFailureCount.entrySet()) {
- badSum = entry.getValue().first.associationRejection
- + entry.getValue().first.authenticationFailure
- + entry.getValue().first.dhcpFailure;
- // count as contributor if over half of badSum.
- if (badSum >= FAILURE_THRESHOLD) {
- badAssoc += (entry.getValue().first.associationRejection >= badSum / 2) ? 1 : 0;
- badAuth += (entry.getValue().first.authenticationFailure >= badSum / 2) ? 1 : 0;
- badDhcp += (entry.getValue().first.dhcpFailure >= badSum / 2) ? 1 : 0;
- }
- }
- if (badAuth > 0) {
- mWifiMetrics.addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(badAuth);
- mWifiMetrics.incrementNumLastResortWatchdogTriggersWithBadAuthentication();
- }
- if (badAssoc > 0) {
- mWifiMetrics.addCountToNumLastResortWatchdogBadAssociationNetworksTotal(badAssoc);
- mWifiMetrics.incrementNumLastResortWatchdogTriggersWithBadAssociation();
- }
- if (badDhcp > 0) {
- mWifiMetrics.addCountToNumLastResortWatchdogBadDhcpNetworksTotal(badDhcp);
- mWifiMetrics.incrementNumLastResortWatchdogTriggersWithBadDhcp();
- }
- }
-
- /**
- * Clear all failure counts
- */
- public void clearAllFailureCounts() {
- if (mVerboseLoggingEnabled) Log.v(TAG, "clearAllFailureCounts.");
- for (Map.Entry<String, AvailableNetworkFailureCount> entry
- : mRecentAvailableNetworks.entrySet()) {
- final AvailableNetworkFailureCount failureCount = entry.getValue();
- failureCount.resetCounts();
- }
- for (Map.Entry<String, Pair<AvailableNetworkFailureCount, Integer>> entry
- : mSsidFailureCount.entrySet()) {
- final AvailableNetworkFailureCount failureCount = entry.getValue().first;
- failureCount.resetCounts();
- }
- mBssidFailureList.clear();
- }
- /**
- * Gets the buffer of recently available networks
- */
- Map<String, AvailableNetworkFailureCount> getRecentAvailableNetworks() {
- return mRecentAvailableNetworks;
- }
-
- /**
- * Activates or deactivates the Watchdog trigger. Counting and network buffering still occurs
- * @param enable true to enable the Watchdog trigger, false to disable it
- */
- private void setWatchdogTriggerEnabled(boolean enable) {
- if (mVerboseLoggingEnabled) Log.v(TAG, "setWatchdogTriggerEnabled: enable = " + enable);
- // Reset failure counts before actives watchdog
- if (enable) {
- clearAllFailureCounts();
- }
- mWatchdogAllowedToTrigger = enable;
- }
-
- /**
- * Prints all networks & counts within mRecentAvailableNetworks to string
- */
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("mWatchdogFeatureEnabled: ").append(getWifiWatchdogFeature());
- sb.append("\nmWatchdogAllowedToTrigger: ").append(mWatchdogAllowedToTrigger);
- sb.append("\nmWifiIsConnected: ").append(mWifiIsConnected);
- sb.append("\nmRecentAvailableNetworks: ").append(mRecentAvailableNetworks.size());
- for (Map.Entry<String, AvailableNetworkFailureCount> entry
- : mRecentAvailableNetworks.entrySet()) {
- sb.append("\n ").append(entry.getKey()).append(": ").append(entry.getValue())
- .append(", Age: ").append(entry.getValue().age);
- }
- 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").append(entry.getKey()).append(": ").append(apCount).append(",")
- .append(failureCount.toString());
- }
- return sb.toString();
- }
-
- /**
- * @param bssid bssid to check the failures for
- * @return true if sum of failure count is over FAILURE_THRESHOLD
- */
- public boolean isOverFailureThreshold(String bssid) {
- return (getFailureCount(bssid, FAILURE_CODE_ASSOCIATION)
- + getFailureCount(bssid, FAILURE_CODE_AUTHENTICATION)
- + getFailureCount(bssid, FAILURE_CODE_DHCP)) >= FAILURE_THRESHOLD;
- }
-
- /**
- * 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) {
- 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;
- }
- }
-
- /**
- * Sets whether wifi watchdog should trigger recovery
- */
- public void setWifiWatchdogFeature(boolean enable) {
- logv("setWifiWatchdogFeature: " + enable);
- mWatchdogFeatureEnabled = enable;
- // for debugging purpose, reset mWatchdogAllowedToTrigger as well
- setWatchdogTriggerEnabled(true);
- }
-
- /**
- * Returns whether wifi watchdog should trigger recovery.
- */
- public boolean getWifiWatchdogFeature() {
- if (mWatchdogFeatureEnabled == null) {
- mWatchdogFeatureEnabled = mContext.getResources().getBoolean(
- R.bool.config_wifi_watchdog_enabled);
- }
- return mWatchdogFeatureEnabled;
- }
-
- protected void enableVerboseLogging(int verbose) {
- if (verbose > 0) {
- mVerboseLoggingEnabled = true;
- } else {
- mVerboseLoggingEnabled = false;
- }
- }
-
- @VisibleForTesting
- protected void setBugReportProbability(double newProbability) {
- mBugReportProbability = newProbability;
- }
-
- /**
- * 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
- */
- public WifiConfiguration config;
- /**
- * SSID of the network (from ScanDetail)
- */
- public String ssid = "";
- /**
- * Number of times network has failed due to Association Rejection
- */
- public int associationRejection = 0;
- /**
- * Number of times network has failed due to Authentication Failure or SSID_TEMP_DISABLED
- */
- public int authenticationFailure = 0;
- /**
- * Number of times network has failed due to DHCP failure
- */
- public int dhcpFailure = 0;
- /**
- * Number of scanResults since this network was last seen
- */
- public int age = 0;
-
- AvailableNetworkFailureCount(WifiConfiguration configParam) {
- this.config = configParam;
- }
-
- /**
- * @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;
- authenticationFailure = 0;
- dhcpFailure = 0;
- }
-
- public String toString() {
- return ssid + " HasEverConnected: " + ((config != null)
- ? config.getNetworkSelectionStatus().hasEverConnected() : "null_config")
- + ", Failures: {"
- + "Assoc: " + associationRejection
- + ", Auth: " + authenticationFailure
- + ", Dhcp: " + dhcpFailure
- + "}";
- }
- }
-
- /**
- * Helper function for logging into local log buffer.
- */
- private void localLog(String s) {
- mLocalLog.log(s);
- }
-
- private void logv(String s) {
- mLocalLog.log(s);
- if (mVerboseLoggingEnabled) {
- Log.v(TAG, s);
- }
- }
-
- private void loge(String s) {
- mLocalLog.log(s);
- Log.e(TAG, s);
- }
-
- /**
- * Dump the local log buffer and other internal state of WifiLastResortWatchdog.
- */
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("Dump of WifiLastResortWatchdog");
- pw.println("WifiLastResortWatchdog - Log Begin ----");
- mLocalLog.dump(fd, pw, args);
- pw.println("WifiLastResortWatchdog - Log End ----");
- }
-}