summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRebecca Silberstein <silberst@google.com>2018-04-03 15:59:39 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2018-04-03 15:59:39 +0000
commitbd0ca3759ab4cbee1ffaf772702a1b2e783a5952 (patch)
treeb29a9e9930821c3fbb01e9ae9603fb1ddb3c6578
parent85fa6ab417f39148fceee1b7262063249600c0a2 (diff)
parent48aeddaf3b150d810f2a93da658e40824a99ae2a (diff)
Merge changes Ie8265bde,Ic42964e0,I13282eb1,Ifb7fc528 into pi-dev
* changes: WifiStateMachine: remove SupplicantStartingState WifiController: disable wifi when recovery throttled WifiStateMachine: remove supplicant disconnect handling WifiStateMachine: onDown triggers wifi off
-rw-r--r--service/java/com/android/server/wifi/SelfRecovery.java29
-rw-r--r--service/java/com/android/server/wifi/WifiController.java42
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java180
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SelfRecoveryTest.java62
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java43
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java141
6 files changed, 342 insertions, 155 deletions
diff --git a/service/java/com/android/server/wifi/SelfRecovery.java b/service/java/com/android/server/wifi/SelfRecovery.java
index d3985f5fd..c9e95a77f 100644
--- a/service/java/com/android/server/wifi/SelfRecovery.java
+++ b/service/java/com/android/server/wifi/SelfRecovery.java
@@ -38,11 +38,13 @@ public class SelfRecovery {
*/
public static final int REASON_LAST_RESORT_WATCHDOG = 0;
public static final int REASON_WIFINATIVE_FAILURE = 1;
+ public static final int REASON_STA_IFACE_DOWN = 2;
public static final long MAX_RESTARTS_IN_TIME_WINDOW = 2; // 2 restarts per hour
public static final long MAX_RESTARTS_TIME_WINDOW_MILLIS = 60 * 60 * 1000; // 1 hour
protected static final String[] REASON_STRINGS = {
- "Last Resort Watchdog", // REASON_LAST_RESORT_WATCHDOG
- "WifiNative Failure" // REASON_WIFINATIVE_FAILURE
+ "Last Resort Watchdog", // REASON_LAST_RESORT_WATCHDOG
+ "WifiNative Failure", // REASON_WIFINATIVE_FAILURE
+ "Sta Interface Down" // REASON_STA_IFACE_DOWN
};
private final WifiController mWifiController;
@@ -59,28 +61,39 @@ public class SelfRecovery {
* Trigger recovery.
*
* This method does the following:
- * 1. Raises a wtf.
- * 2. Sends {@link WifiController#CMD_RESTART_WIFI} to {@link WifiController} to initiate the
- * stack restart.
+ * 1. Checks reason code used to trigger recovery
+ * 2. Checks for sta iface down triggers and disables wifi by sending {@link
+ * WifiController#CMD_RECOVERY_DISABLE_WIFI} to {@link WifiController} to disable wifi.
+ * 3. Throttles restart calls for underlying native failures
+ * 4. Sends {@link WifiController#CMD_RECOVERY_RESTART_WIFI} to {@link WifiController} to
+ * initiate the stack restart.
* @param reason One of the above |REASON_*| codes.
*/
public void trigger(int reason) {
- if (!(reason == REASON_LAST_RESORT_WATCHDOG || reason == REASON_WIFINATIVE_FAILURE)) {
+ if (!(reason == REASON_LAST_RESORT_WATCHDOG || reason == REASON_WIFINATIVE_FAILURE
+ || reason == REASON_STA_IFACE_DOWN)) {
Log.e(TAG, "Invalid trigger reason. Ignoring...");
return;
}
+ if (reason == REASON_STA_IFACE_DOWN) {
+ Log.e(TAG, "STA interface down, disable wifi");
+ mWifiController.sendMessage(WifiController.CMD_RECOVERY_DISABLE_WIFI);
+ return;
+ }
+
Log.e(TAG, "Triggering recovery for reason: " + REASON_STRINGS[reason]);
if (reason == REASON_WIFINATIVE_FAILURE) {
trimPastRestartTimes();
// Ensure there haven't been too many restarts within MAX_RESTARTS_TIME_WINDOW
if (mPastRestartTimes.size() >= MAX_RESTARTS_IN_TIME_WINDOW) {
Log.e(TAG, "Already restarted wifi (" + MAX_RESTARTS_IN_TIME_WINDOW + ") times in"
- + " last (" + MAX_RESTARTS_TIME_WINDOW_MILLIS + "ms ). Ignoring...");
+ + " last (" + MAX_RESTARTS_TIME_WINDOW_MILLIS + "ms ). Disabling wifi");
+ mWifiController.sendMessage(WifiController.CMD_RECOVERY_DISABLE_WIFI);
return;
}
mPastRestartTimes.add(mClock.getElapsedSinceBootMillis());
}
- mWifiController.sendMessage(WifiController.CMD_RESTART_WIFI, reason);
+ mWifiController.sendMessage(WifiController.CMD_RECOVERY_RESTART_WIFI, reason);
}
/**
diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java
index 5cc0306e1..3db804b9b 100644
--- a/service/java/com/android/server/wifi/WifiController.java
+++ b/service/java/com/android/server/wifi/WifiController.java
@@ -76,21 +76,23 @@ public class WifiController extends StateMachine {
private static final int BASE = Protocol.BASE_WIFI_CONTROLLER;
- static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1;
- static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7;
- static final int CMD_WIFI_TOGGLED = BASE + 8;
- static final int CMD_AIRPLANE_TOGGLED = BASE + 9;
- static final int CMD_SET_AP = BASE + 10;
- static final int CMD_DEFERRED_TOGGLE = BASE + 11;
- static final int CMD_USER_PRESENT = BASE + 12;
- static final int CMD_AP_START_FAILURE = BASE + 13;
- static final int CMD_EMERGENCY_CALL_STATE_CHANGED = BASE + 14;
- static final int CMD_AP_STOPPED = BASE + 15;
- static final int CMD_STA_START_FAILURE = BASE + 16;
+ static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1;
+ static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7;
+ static final int CMD_WIFI_TOGGLED = BASE + 8;
+ static final int CMD_AIRPLANE_TOGGLED = BASE + 9;
+ static final int CMD_SET_AP = BASE + 10;
+ static final int CMD_DEFERRED_TOGGLE = BASE + 11;
+ static final int CMD_USER_PRESENT = BASE + 12;
+ static final int CMD_AP_START_FAILURE = BASE + 13;
+ static final int CMD_EMERGENCY_CALL_STATE_CHANGED = BASE + 14;
+ static final int CMD_AP_STOPPED = BASE + 15;
+ static final int CMD_STA_START_FAILURE = BASE + 16;
// Command used to trigger a wifi stack restart when in active mode
- static final int CMD_RESTART_WIFI = BASE + 17;
+ static final int CMD_RECOVERY_RESTART_WIFI = BASE + 17;
// Internal command used to complete wifi stack restart
- private static final int CMD_RESTART_WIFI_CONTINUE = BASE + 18;
+ private static final int CMD_RECOVERY_RESTART_WIFI_CONTINUE = BASE + 18;
+ // Command to disable wifi when SelfRecovery is throttled or otherwise not doing full recovery
+ static final int CMD_RECOVERY_DISABLE_WIFI = BASE + 19;
private DefaultState mDefaultState = new DefaultState();
private StaEnabledState mStaEnabledState = new StaEnabledState();
@@ -215,8 +217,9 @@ public class WifiController extends StateMachine {
case CMD_AP_START_FAILURE:
case CMD_AP_STOPPED:
case CMD_STA_START_FAILURE:
- case CMD_RESTART_WIFI:
- case CMD_RESTART_WIFI_CONTINUE:
+ case CMD_RECOVERY_RESTART_WIFI:
+ case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
+ case CMD_RECOVERY_DISABLE_WIFI:
break;
case CMD_USER_PRESENT:
mFirstUserSignOnSeen = true;
@@ -297,7 +300,7 @@ public class WifiController extends StateMachine {
log("DEFERRED_TOGGLE handled");
sendMessage((Message)(msg.obj));
break;
- case CMD_RESTART_WIFI_CONTINUE:
+ case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
transitionTo(mDeviceActiveState);
break;
default:
@@ -649,7 +652,7 @@ public class WifiController extends StateMachine {
}
mFirstUserSignOnSeen = true;
return HANDLED;
- } else if (msg.what == CMD_RESTART_WIFI) {
+ } else if (msg.what == CMD_RECOVERY_RESTART_WIFI) {
final String bugTitle = "Wi-Fi BugReport";
final String bugDetail;
if (msg.obj != null && msg.arg1 < SelfRecovery.REASON_STRINGS.length
@@ -663,9 +666,12 @@ public class WifiController extends StateMachine {
mWifiStateMachine.takeBugReport(bugTitle, bugDetail);
});
}
- deferMessage(obtainMessage(CMD_RESTART_WIFI_CONTINUE));
+ deferMessage(obtainMessage(CMD_RECOVERY_RESTART_WIFI_CONTINUE));
transitionTo(mApStaDisabledState);
return HANDLED;
+ } else if (msg.what == CMD_RECOVERY_DISABLE_WIFI) {
+ loge("Recovery has been throttled, disable wifi");
+ transitionTo(mApStaDisabledState);
}
return NOT_HANDLED;
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index eb3848dc6..e2345e9b1 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -229,15 +229,23 @@ public class WifiStateMachine extends StateMachine {
private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback() {
@Override
public void onDestroyed(String ifaceName) {
- sendMessage(CMD_INTERFACE_DESTROYED);
+ if (mInterfaceName != null && mInterfaceName.equals(ifaceName)) {
+ sendMessage(CMD_INTERFACE_DESTROYED);
+ }
}
@Override
public void onUp(String ifaceName) {
+ if (mInterfaceName != null && mInterfaceName.equals(ifaceName)) {
+ sendMessage(CMD_INTERFACE_STATUS_CHANGED, 1);
+ }
}
@Override
public void onDown(String ifaceName) {
+ if (mInterfaceName != null && mInterfaceName.equals(ifaceName)) {
+ sendMessage(CMD_INTERFACE_STATUS_CHANGED, 0);
+ }
}
};
private boolean mIpReachabilityDisconnectEnabled = true;
@@ -326,8 +334,6 @@ public class WifiStateMachine extends StateMachine {
*/
public static final String SUPPLICANT_BSSID_ANY = "any";
- private int mSupplicantRestartCount = 0;
-
/**
* The link properties of the wifi interface.
* Do not modify this directly; use updateLinkProperties instead.
@@ -459,12 +465,14 @@ public class WifiStateMachine extends StateMachine {
static final int CMD_STOP_SUPPLICANT = BASE + 12;
/* STA interface destroyed */
static final int CMD_INTERFACE_DESTROYED = BASE + 13;
+ /* STA interface down */
+ static final int CMD_INTERFACE_DOWN = BASE + 14;
/* Indicates Static IP succeeded */
static final int CMD_STATIC_IP_SUCCESS = BASE + 15;
/* Indicates Static IP failed */
static final int CMD_STATIC_IP_FAILURE = BASE + 16;
- /* A delayed message sent to start driver when it fail to come up */
- static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19;
+ /* Interface status change */
+ static final int CMD_INTERFACE_STATUS_CHANGED = BASE + 20;
/* Start the soft access point */
static final int CMD_START_AP = BASE + 21;
@@ -769,8 +777,6 @@ public class WifiStateMachine extends StateMachine {
private State mDefaultState = new DefaultState();
/* Temporary initial state */
private State mInitialState = new InitialState();
- /* Driver loaded, waiting for supplicant to start */
- private State mSupplicantStartingState = new SupplicantStartingState();
/* Driver loaded and supplicant ready */
private State mSupplicantStartedState = new SupplicantStartedState();
/* Scan for networks, no connection will be established */
@@ -992,7 +998,6 @@ public class WifiStateMachine extends StateMachine {
// CHECKSTYLE:OFF IndentationCheck
addState(mDefaultState);
addState(mInitialState, mDefaultState);
- addState(mSupplicantStartingState, mInitialState);
addState(mSupplicantStartedState, mInitialState);
addState(mConnectModeState, mSupplicantStartedState);
addState(mL2ConnectedState, mConnectModeState);
@@ -1045,9 +1050,6 @@ public class WifiStateMachine extends StateMachine {
getHandler());
mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.RX_HS20_ANQP_ICON_EVENT,
getHandler());
- mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_CONNECTION_EVENT, getHandler());
- mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_DISCONNECTION_EVENT,
- getHandler());
mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,
getHandler());
mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_REQUEST_IDENTITY,
@@ -3380,6 +3382,25 @@ public class WifiStateMachine extends StateMachine {
+ macRandomizationEnabled);
}
+ /**
+ * Handle the error case where our underlying interface went down (if we do not have mac
+ * randomization enabled (b/72459123).
+ *
+ * This method triggers SelfRecovery with the error of REASON_STA_IFACE_DOWN. SelfRecovery then
+ * decides if wifi should be restarted or disabled.
+ */
+ private void handleInterfaceDown() {
+ if (mEnableConnectedMacRandomization.get()) {
+ // interface will go down when mac randomization is active, skip
+ Log.d(TAG, "MacRandomization enabled, ignoring iface down");
+ return;
+ }
+
+ Log.e(TAG, "Detected an interface down, report failure to SelfRecovery");
+ // report a failure
+ mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_STA_IFACE_DOWN);
+ }
+
/********************************************************
* HSM states
*******************************************************/
@@ -3488,7 +3509,6 @@ public class WifiStateMachine extends StateMachine {
break;
case CMD_START_SUPPLICANT:
case CMD_STOP_SUPPLICANT:
- case CMD_DRIVER_START_TIMED_OUT:
case CMD_START_AP_FAILURE:
case CMD_STOP_AP:
case CMD_AP_STOPPED:
@@ -3496,8 +3516,6 @@ public class WifiStateMachine extends StateMachine {
case CMD_RECONNECT:
case CMD_REASSOCIATE:
case CMD_RELOAD_TLS_AND_RECONNECT:
- case WifiMonitor.SUP_CONNECTION_EVENT:
- case WifiMonitor.SUP_DISCONNECTION_EVENT:
case WifiMonitor.NETWORK_CONNECTION_EVENT:
case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
@@ -3524,6 +3542,8 @@ public class WifiStateMachine extends StateMachine {
case CMD_SELECT_TX_POWER_SCENARIO:
case CMD_WIFINATIVE_FAILURE:
case CMD_INTERFACE_DESTROYED:
+ case CMD_INTERFACE_DOWN:
+ case CMD_INTERFACE_STATUS_CHANGED:
messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
break;
case CMD_START_AP:
@@ -3712,6 +3732,23 @@ public class WifiStateMachine extends StateMachine {
}
class InitialState extends State {
+ private boolean mIfaceIsUp;
+
+ private void onUpChanged(boolean isUp) {
+ if (isUp == mIfaceIsUp) {
+ return; // no change
+ }
+ mIfaceIsUp = isUp;
+ if (isUp) {
+ Log.d(TAG, "Client mode interface is up");
+ // for now, do nothing - client mode has never waited for iface up
+ } else {
+ // A driver/firmware hang can now put the interface in a down state.
+ // We detect the interface going down and recover from it
+ handleInterfaceDown();
+ }
+ }
+
private void cleanup() {
// tell scanning service that scans are not available - about to kill the interface and
// supplicant
@@ -3727,10 +3764,12 @@ public class WifiStateMachine extends StateMachine {
// TODO: Remove this big hammer. We cannot support concurrent interfaces with this!
mWifiNative.teardownAllInterfaces();
mInterfaceName = null;
+ mIfaceIsUp = false;
}
@Override
public void enter() {
+ mIfaceIsUp = false;
mWifiMonitor.stopAllMonitoring();
mWifiStateTracker.updateState(WifiStateTracker.INVALID);
cleanup();
@@ -3751,6 +3790,9 @@ public class WifiStateMachine extends StateMachine {
transitionTo(mDefaultState);
break;
}
+ // now that we have the interface, initialize our up/down status
+ onUpChanged(mWifiNative.isInterfaceUp(mInterfaceName));
+
mIpClient = mFacade.makeIpClient(
mContext, mInterfaceName, new IpClientCallback());
mIpClient.setMulticastFilter(true);
@@ -3759,7 +3801,7 @@ public class WifiStateMachine extends StateMachine {
mWifiMonitor.startMonitoring(mInterfaceName);
mWifiInjector.getWifiLastResortWatchdog().clearAllFailureCounts();
setSupplicantLogLevel();
- transitionTo(mSupplicantStartingState);
+ transitionTo(mSupplicantStartedState);
break;
case CMD_SET_OPERATIONAL_MODE:
if (message.arg1 == CONNECT_MODE) {
@@ -3773,46 +3815,20 @@ public class WifiStateMachine extends StateMachine {
WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE);
mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE);
break;
- default:
- return NOT_HANDLED;
- }
- return HANDLED;
- }
- }
-
- class SupplicantStartingState extends State {
-
- @Override
- public boolean processMessage(Message message) {
- logStateAndMessage(message, this);
-
- switch(message.what) {
- case WifiMonitor.SUP_CONNECTION_EVENT:
- if (mVerboseLoggingEnabled) log("Supplicant connection established");
-
- mSupplicantRestartCount = 0;
- /* Reset the supplicant state to indicate the supplicant
- * state is not known at this time */
- mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
- /* Initialize data structures */
- mLastBssid = null;
- mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
- mLastSignalLevel = -1;
- mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
- // Attempt to migrate data out of legacy store.
- if (!mWifiConfigManager.migrateFromLegacyStore()) {
- Log.e(TAG, "Failed to migrate from legacy config store");
+ case CMD_INTERFACE_STATUS_CHANGED:
+ boolean isUp = message.arg1 == 1;
+ // For now, this message can be triggered due to link state and/or interface
+ // status changes (b/77218676). First check if we really see an iface down by
+ // consulting our view of supplicant state.
+ if (!isUp && SupplicantState.isDriverActive(mWifiInfo.getSupplicantState())) {
+ // the driver is active, so this could just be part of normal operation, do
+ // not disable wifi in these cases (ex, a network was removed) or worry
+ // about the link status
+ break;
}
- sendSupplicantConnectionChangedBroadcast(true);
- transitionTo(mSupplicantStartedState);
- break;
- case WifiMonitor.SUP_DISCONNECTION_EVENT:
- // since control is split between WSM and WSMP - do not worry about supplicant
- // dying if we haven't seen it up yet
+
+ onUpChanged(isUp);
break;
- case CMD_START_SUPPLICANT:
- case CMD_STOP_SUPPLICANT:
- case CMD_STOP_AP:
default:
return NOT_HANDLED;
}
@@ -3827,6 +3843,19 @@ public class WifiStateMachine extends StateMachine {
logd("SupplicantStartedState enter");
}
+ // reset state related to supplicant starting
+ mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
+ // Initialize data structures
+ mLastBssid = null;
+ mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
+ mLastSignalLevel = -1;
+ mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
+ // Attempt to migrate data out of legacy store.
+ if (!mWifiConfigManager.migrateFromLegacyStore()) {
+ Log.e(TAG, "Failed to migrate from legacy config store");
+ }
+ sendSupplicantConnectionChangedBroadcast(true);
+
mWifiNative.setExternalSim(mInterfaceName, true);
setRandomMacOui();
@@ -3897,19 +3926,6 @@ public class WifiStateMachine extends StateMachine {
logStateAndMessage(message, this);
switch(message.what) {
- case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */
- // first check if we are expecting a mode switch
- if (mModeChange) {
- logd("expecting a mode change, do not restart supplicant");
- return HANDLED;
- }
- loge("Connection lost, restart supplicant");
- handleSupplicantConnectionLoss(true);
- handleNetworkDisconnect();
- mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
- sendMessage(CMD_START_SUPPLICANT);
- transitionTo(mInitialState);
- break;
case CMD_TARGET_BSSID:
// Trying to associate to this BSSID
if (message.obj != null) {
@@ -4082,12 +4098,6 @@ public class WifiStateMachine extends StateMachine {
case WifiManager.FORGET_NETWORK:
s = "FORGET_NETWORK";
break;
- case WifiMonitor.SUP_CONNECTION_EVENT:
- s = "SUP_CONNECTION_EVENT";
- break;
- case WifiMonitor.SUP_DISCONNECTION_EVENT:
- s = "SUP_DISCONNECTION_EVENT";
- break;
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
s = "SUPPLICANT_STATE_CHANGE_EVENT";
break;
@@ -4336,20 +4346,6 @@ public class WifiStateMachine extends StateMachine {
break;
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
SupplicantState state = handleSupplicantStateChange(message);
- // A driver/firmware hang can now put the interface in a down state.
- // We detect the interface going down and recover from it
- if (!SupplicantState.isDriverActive(state) && !mModeChange
- && !mEnableConnectedMacRandomization.get()) {
- if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
- handleNetworkDisconnect();
- }
- log("Detected an interface down, restart driver");
- // Rely on the fact that this will force us into killing supplicant and then
- // restart supplicant from a clean state.
- sendMessage(CMD_START_SUPPLICANT);
- transitionTo(mInitialState);
- break;
- }
// Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
// when authentication times out after a successful connection,
@@ -4371,6 +4367,18 @@ public class WifiStateMachine extends StateMachine {
if (state == SupplicantState.COMPLETED) {
mIpClient.confirmConfiguration();
}
+
+ if (!SupplicantState.isDriverActive(state)) {
+ // still use supplicant to detect interface down while work to
+ // mitigate b/77218676 is in progress
+ // note: explicitly using this command to dedup iface down notification
+ // paths (onUpChanged filters out duplicate updates)
+ sendMessage(CMD_INTERFACE_STATUS_CHANGED, 0);
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "detected interface down via supplicant");
+ }
+ }
+
break;
case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
if (message.arg1 == 1) {
diff --git a/tests/wifitests/src/com/android/server/wifi/SelfRecoveryTest.java b/tests/wifitests/src/com/android/server/wifi/SelfRecoveryTest.java
index c8dafdd69..9b50517f8 100644
--- a/tests/wifitests/src/com/android/server/wifi/SelfRecoveryTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SelfRecoveryTest.java
@@ -47,13 +47,13 @@ public class SelfRecoveryTest {
@Test
public void testValidTriggerReasonsSendMessageToWifiController() {
mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
- verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI), anyInt());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI), anyInt());
reset(mWifiController);
when(mClock.getElapsedSinceBootMillis())
.thenReturn(SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1);
mSelfRecovery.trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE);
- verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI), anyInt());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI), anyInt());
reset(mWifiController);
}
@@ -71,6 +71,15 @@ public class SelfRecoveryTest {
}
/**
+ * Verifies that a STA interface down event will trigger WifiController to disable wifi.
+ */
+ @Test
+ public void testStaIfaceDownDisablesWifi() {
+ mSelfRecovery.trigger(SelfRecovery.REASON_STA_IFACE_DOWN);
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_DISABLE_WIFI));
+ }
+
+ /**
* Verifies that invocations of {@link SelfRecovery#trigger(int)} for REASON_HAL_CRASH &
* REASON_WIFICOND_CRASH are limited to {@link SelfRecovery#MAX_RESTARTS_IN_TIME_WINDOW} in a
* {@link SelfRecovery#MAX_RESTARTS_TIME_WINDOW_MILLIS} millisecond time window.
@@ -82,46 +91,57 @@ public class SelfRecoveryTest {
// aren't ignored
for (int i = 0; i < SelfRecovery.MAX_RESTARTS_IN_TIME_WINDOW / 2; i++) {
mSelfRecovery.trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE);
- verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI), anyInt());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI),
+ anyInt());
reset(mWifiController);
mSelfRecovery.trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE);
- verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI), anyInt());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI),
+ anyInt());
reset(mWifiController);
}
if ((SelfRecovery.MAX_RESTARTS_IN_TIME_WINDOW % 2) == 1) {
mSelfRecovery.trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE);
- verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI), anyInt());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI),
+ anyInt());
reset(mWifiController);
}
- // Verify that further attempts to trigger restarts for are ignored
+ // Verify that further attempts to trigger restarts disable wifi
mSelfRecovery.trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE);
- verify(mWifiController, never()).sendMessage(eq(WifiController.CMD_RESTART_WIFI),
+ verify(mWifiController, never()).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI),
anyString());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_DISABLE_WIFI));
reset(mWifiController);
mSelfRecovery.trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE);
- verify(mWifiController, never()).sendMessage(eq(WifiController.CMD_RESTART_WIFI),
+ verify(mWifiController, never()).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI),
anyString());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_DISABLE_WIFI));
reset(mWifiController);
// Verify L.R.Watchdog can still restart things (It has its own complex limiter)
mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
- verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI), anyInt());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI),
+ anyInt());
+ reset(mWifiController);
+
+ // Verify Sta Interface Down will still disable wifi
+ mSelfRecovery.trigger(SelfRecovery.REASON_STA_IFACE_DOWN);
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_DISABLE_WIFI));
reset(mWifiController);
// now TRAVEL FORWARDS IN TIME and ensure that more restarts can occur
when(mClock.getElapsedSinceBootMillis())
.thenReturn(SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1);
mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
- verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI), anyInt());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI), anyInt());
reset(mWifiController);
when(mClock.getElapsedSinceBootMillis())
.thenReturn(SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1);
mSelfRecovery.trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE);
- verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI), anyInt());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI), anyInt());
reset(mWifiController);
}
@@ -136,7 +156,25 @@ public class SelfRecoveryTest {
for (int i = 0; i < SelfRecovery.MAX_RESTARTS_IN_TIME_WINDOW * 2; i++) {
// Verify L.R.Watchdog can still restart things (It has it's own complex limiter)
mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
- verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI), anyInt());
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI),
+ anyInt());
+ reset(mWifiController);
+ }
+ }
+
+ /**
+ * Verifies that invocations of {@link SelfRecovery#trigger(int)} for
+ * REASON_STA_IFACE_DOWN are NOT limited to
+ * {@link SelfRecovery#MAX_RESTARTS_IN_TIME_WINDOW} in a
+ * {@link SelfRecovery#MAX_RESTARTS_TIME_WINDOW_MILLIS} millisecond time window.
+ */
+ @Test
+ public void testTimeWindowLimiting_staIfaceDown_noEffect() {
+ for (int i = 0; i < SelfRecovery.MAX_RESTARTS_IN_TIME_WINDOW * 2; i++) {
+ mSelfRecovery.trigger(SelfRecovery.REASON_STA_IFACE_DOWN);
+ verify(mWifiController).sendMessage(eq(WifiController.CMD_RECOVERY_DISABLE_WIFI));
+ verify(mWifiController, never())
+ .sendMessage(eq(WifiController.CMD_RECOVERY_RESTART_WIFI), anyInt());
reset(mWifiController);
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
index 50be8e44b..279fb670b 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
@@ -19,7 +19,8 @@ package com.android.server.wifi;
import static com.android.server.wifi.WifiController.CMD_AP_STOPPED;
import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED;
import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
-import static com.android.server.wifi.WifiController.CMD_RESTART_WIFI;
+import static com.android.server.wifi.WifiController.CMD_RECOVERY_DISABLE_WIFI;
+import static com.android.server.wifi.WifiController.CMD_RECOVERY_RESTART_WIFI;
import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED;
import static com.android.server.wifi.WifiController.CMD_SET_AP;
import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
@@ -402,7 +403,8 @@ public class WifiControllerTest {
@Test
public void testRestartWifiStackInStaEnabledStateTriggersBugReport() throws Exception {
enableWifi();
- mWifiController.sendMessage(CMD_RESTART_WIFI, SelfRecovery.REASON_WIFINATIVE_FAILURE);
+ mWifiController.sendMessage(CMD_RECOVERY_RESTART_WIFI,
+ SelfRecovery.REASON_WIFINATIVE_FAILURE);
mLooper.dispatchAll();
verify(mWifiStateMachine).takeBugReport(anyString(), anyString());
}
@@ -410,12 +412,37 @@ public class WifiControllerTest {
@Test
public void testRestartWifiWatchdogDoesNotTriggerBugReport() throws Exception {
enableWifi();
- mWifiController.sendMessage(CMD_RESTART_WIFI, SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
+ mWifiController.sendMessage(CMD_RECOVERY_RESTART_WIFI,
+ SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
mLooper.dispatchAll();
verify(mWifiStateMachine, never()).takeBugReport(anyString(), anyString());
}
/**
+ * When in sta mode, CMD_RECOVERY_DISABLE_WIFI messages should trigger wifi to disable.
+ */
+ @Test
+ public void testRecoveryDisabledTurnsWifiOff() throws Exception {
+ enableWifi();
+ reset(mWifiStateMachine);
+ mWifiController.sendMessage(CMD_RECOVERY_DISABLE_WIFI);
+ mLooper.dispatchAll();
+ verify(mWifiStateMachine).setOperationalMode(WifiStateMachine.DISABLED_MODE);
+ }
+
+ /**
+ * When wifi is disabled, CMD_RECOVERY_DISABLE_WIFI should not trigger a state change.
+ */
+ @Test
+ public void testRecoveryDisabledWhenWifiAlreadyOff() throws Exception {
+ reset(mWifiStateMachine, mWifiStateMachinePrime);
+ assertEquals("StaDisabledWithScanState", getCurrentState().getName());
+ mWifiController.sendMessage(CMD_RECOVERY_DISABLE_WIFI);
+ mLooper.dispatchAll();
+ verifyZeroInteractions(mWifiStateMachine, mWifiStateMachinePrime);
+ }
+
+ /**
* The command to trigger a WiFi reset should not trigger any action by WifiController if we
* are not in STA mode.
* WiFi is not in connect mode, so any calls to reset the wifi stack due to connection failures
@@ -439,7 +466,7 @@ public class WifiControllerTest {
reset(mWifiStateMachine);
assertEquals("ApStaDisabledState", getCurrentState().getName());
- mWifiController.sendMessage(CMD_RESTART_WIFI);
+ mWifiController.sendMessage(CMD_RECOVERY_RESTART_WIFI);
mLooper.dispatchAll();
verifyZeroInteractions(mWifiStateMachine);
}
@@ -457,7 +484,7 @@ public class WifiControllerTest {
public void testRestartWifiStackInStaDisabledWithScanState() throws Exception {
reset(mWifiStateMachine);
assertEquals("StaDisabledWithScanState", getCurrentState().getName());
- mWifiController.sendMessage(CMD_RESTART_WIFI);
+ mWifiController.sendMessage(CMD_RECOVERY_RESTART_WIFI);
mLooper.dispatchAll();
verifyZeroInteractions(mWifiStateMachine);
}
@@ -478,7 +505,7 @@ public class WifiControllerTest {
reset(mWifiStateMachine);
assertEquals("DeviceActiveState", getCurrentState().getName());
- mWifiController.sendMessage(CMD_RESTART_WIFI);
+ mWifiController.sendMessage(CMD_RECOVERY_RESTART_WIFI);
mLooper.dispatchAll();
InOrder inOrder = inOrder(mWifiStateMachine);
inOrder.verify(mWifiStateMachine).setOperationalMode(WifiStateMachine.CONNECT_MODE);
@@ -503,7 +530,7 @@ public class WifiControllerTest {
assertInEcm(true);
reset(mWifiStateMachine);
- mWifiController.sendMessage(CMD_RESTART_WIFI);
+ mWifiController.sendMessage(CMD_RECOVERY_RESTART_WIFI);
mLooper.dispatchAll();
assertInEcm(true);
verifyZeroInteractions(mWifiStateMachine);
@@ -524,7 +551,7 @@ public class WifiControllerTest {
assertEquals("ApEnabledState", getCurrentState().getName());
reset(mWifiStateMachine);
- mWifiController.sendMessage(CMD_RESTART_WIFI);
+ mWifiController.sendMessage(CMD_RECOVERY_RESTART_WIFI);
mLooper.dispatchAll();
verifyZeroInteractions(mWifiStateMachine);
verify(mWifiStateMachinePrime, never()).disableWifi();
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index 2768af6db..c90bde3bb 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -638,7 +638,7 @@ public class WifiStateMachineTest {
// But if someone tells us to enter connect mode, we start up supplicant
mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
mLooper.dispatchAll();
- assertEquals("SupplicantStartingState", getCurrentState().getName());
+ assertEquals("DisconnectedState", getCurrentState().getName());
}
/**
@@ -853,7 +853,7 @@ public class WifiStateMachineTest {
}
/**
- * Helper method to move through SupplicantStarting and SupplicantStarted states.
+ * Helper method to move through startup states.
*/
private void startSupplicantAndDispatchMessages() throws Exception {
mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
@@ -862,25 +862,11 @@ public class WifiStateMachineTest {
// this will be removed when interface management is dynamic
verify(mWifiNative, atLeastOnce()).teardownAllInterfaces();
- assertEquals("SupplicantStartingState", getCurrentState().getName());
-
- when(mWifiNative.setDeviceName(eq(WIFI_IFACE_NAME), anyString())).thenReturn(true);
- when(mWifiNative.setManufacturer(eq(WIFI_IFACE_NAME), anyString())).thenReturn(true);
- when(mWifiNative.setModelName(eq(WIFI_IFACE_NAME), anyString())).thenReturn(true);
- when(mWifiNative.setModelNumber(eq(WIFI_IFACE_NAME), anyString())).thenReturn(true);
- when(mWifiNative.setSerialNumber(eq(WIFI_IFACE_NAME), anyString())).thenReturn(true);
- when(mWifiNative.setConfigMethods(eq(WIFI_IFACE_NAME), anyString())).thenReturn(true);
- when(mWifiNative.setDeviceType(eq(WIFI_IFACE_NAME), anyString())).thenReturn(true);
- when(mWifiNative.setSerialNumber(eq(WIFI_IFACE_NAME), anyString())).thenReturn(true);
- when(mWifiNative.setScanningMacOui(eq(WIFI_IFACE_NAME), any(byte[].class)))
- .thenReturn(true);
-
- mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
- mLooper.dispatchAll();
-
verify(mWifiNative, atLeastOnce())
.setupInterfaceForClientMode(eq(false), mInterfaceCallbackCaptor.capture());
verify(mWifiLastResortWatchdog, atLeastOnce()).clearAllFailureCounts();
+
+ assertEquals("DisconnectedState", getCurrentState().getName());
}
private void addNetworkAndVerifySuccess(boolean isHidden) throws Exception {
@@ -1834,18 +1820,127 @@ public class WifiStateMachineTest {
}
/**
- * Test verifying that interface onDown callbacks are not currently hooked up.
+ * Test verifying that interface onDown callback triggers SelfRecovery when Supplicant has
+ * already reported the driver is not active.
*/
@Test
- public void testInterfaceOnDownDoesNotTriggerClientModeShutdown() throws Exception {
- connect();
+ public void testInterfaceOnDownInClientModeTriggersSelfRecovery() throws Exception {
+ // Trigger initialize to capture the death handler registration.
+ loadComponentsInStaMode();
+
+ // make sure we mark the iface up
+ mInterfaceCallbackCaptor.getValue().onUp(WIFI_IFACE_NAME);
+
+ // make sure supplicant has been reported as inactive
+ when(mWifiNative.isInterfaceUp(eq(WIFI_IFACE_NAME))).thenReturn(true);
+ mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
+ new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(""), null,
+ SupplicantState.INTERFACE_DISABLED));
+ mLooper.dispatchAll();
// trigger onDown for the client interface
mInterfaceCallbackCaptor.getValue().onDown(WIFI_IFACE_NAME);
mLooper.dispatchAll();
- // since this is not handled yet, should not trigger a disconnect
- assertEquals("ConnectedState", getCurrentState().getName());
+ // WSM should trigger self recovery, but not disconnect until externally triggered
+ verify(mSelfRecovery).trigger(eq(SelfRecovery.REASON_STA_IFACE_DOWN));
+ }
+
+ /**
+ * Test verifying that interface onDown callback does not trigger SelfRecovery when
+ * Supplicant reports that the driver is active.
+ */
+ @Test
+ public void testInterfaceOnDownInClientModeDoesNotTriggerSelfRecoveryIfDriverActive()
+ throws Exception {
+ // Trigger initialize to capture the death handler registration.
+ loadComponentsInStaMode();
+
+ // make sure we mark the iface up
+ mInterfaceCallbackCaptor.getValue().onUp(WIFI_IFACE_NAME);
+ mLooper.dispatchAll();
+
+ // make sure supplicant has been reported as active
+ mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
+ new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(""), null,
+ SupplicantState.DISCONNECTED));
+ mLooper.dispatchAll();
+
+ // trigger onDown for the client interface
+ mInterfaceCallbackCaptor.getValue().onDown(WIFI_IFACE_NAME);
+ mLooper.dispatchAll();
+
+ // WSM should trigger self recovery, but not disconnect until externally triggered
+ verify(mSelfRecovery, never()).trigger(eq(SelfRecovery.REASON_STA_IFACE_DOWN));
+ }
+
+ /**
+ * Test verifying that Supplicant update for inactive driver does not trigger SelfRecovery
+ * when the interface is reported down.
+ */
+ @Test
+ public void testSupplicantUpdateDriverInactiveInClientModeTriggersSelfRecovery()
+ throws Exception {
+ // Trigger initialize to capture the death handler registration.
+ loadComponentsInStaMode();
+
+ when(mWifiNative.isInterfaceUp(eq(WIFI_IFACE_NAME))).thenReturn(false);
+
+ mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
+ new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(""), null,
+ SupplicantState.INTERFACE_DISABLED));
+ mLooper.dispatchAll();
+
+ // WSM should trigger self recovery, but not disconnect until externally triggered
+ verify(mSelfRecovery, never()).trigger(eq(SelfRecovery.REASON_STA_IFACE_DOWN));
+ }
+
+ /**
+ * Test verifying that interface Supplicant update for inactive driver does not trigger
+ * SelfRecovery when WifiNative reports the interface is up.
+ */
+ @Test
+ public void testSupplicantUpdateDriverInactiveIfaceUpClientModeDoesNotTriggerSelfRecovery()
+ throws Exception {
+ // Trigger initialize to capture the death handler registration.
+ loadComponentsInStaMode();
+
+ when(mWifiNative.isInterfaceUp(eq(WIFI_IFACE_NAME))).thenReturn(true);
+
+ // make sure supplicant has been reported as inactive
+ mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
+ new StateChangeResult(0, WifiSsid.createFromAsciiEncoded(""), null,
+ SupplicantState.INTERFACE_DISABLED));
+ mLooper.dispatchAll();
+
+ // WSM should trigger self recovery, but not disconnect until externally triggered
+ verify(mSelfRecovery, never()).trigger(eq(SelfRecovery.REASON_STA_IFACE_DOWN));
+ }
+
+ /**
+ * Test verifying that interface onDown callback does not trigger SelfRecovery when
+ * MacRandomization is enabled.
+ */
+ @Test
+ public void testInterfaceOnDownInClientModeDoesNotTriggerSelfRecoveryWithMacRand()
+ throws Exception {
+ when(mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, 0)).thenReturn(1);
+ mContentObserver.onChange(false);
+
+ // Trigger initialize to capture the death handler registration.
+ loadComponentsInStaMode();
+
+ // make sure we mark the iface up
+ mInterfaceCallbackCaptor.getValue().onUp(WIFI_IFACE_NAME);
+ mLooper.dispatchAll();
+
+ // trigger onDown for the client interface
+ mInterfaceCallbackCaptor.getValue().onDown(WIFI_IFACE_NAME);
+ mLooper.dispatchAll();
+
+ // WSM should trigger self recovery, but not disconnect until externally triggered
+ verify(mSelfRecovery, never()).trigger(eq(SelfRecovery.REASON_STA_IFACE_DOWN));
}
/**