diff options
author | Rebecca Silberstein <silberst@google.com> | 2018-04-18 18:50:16 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-04-18 18:50:16 +0000 |
commit | 2a78fd6b8dd165346650ed56335b2f0774baa553 (patch) | |
tree | 5d91cd72050abbba216d66a9c37bc51e5fe7d95f /service | |
parent | 3a48dfd8ab53cf4050a17009afd829e6483369bb (diff) | |
parent | 1c5f984de5c482992943b7e5a4869f24b5072d27 (diff) |
Merge changes Ieed3609a,I0a9a5241,Ie6857478,I5c1e4378,Id01c9a28, ... into pi-dev
* changes:
ClientModeManager: control WifiStateMachine
WifiStateMachinePrime: separate softap mode
ActiveModeManager: add default scan available bcast
WifiStateMachine: remove unused states
WifiStateMachine: remove supplicant specific states
WifiController: use callbacks instead of bcasts
WifiStateMachinePrime: centralize native failure handling
Diffstat (limited to 'service')
8 files changed, 634 insertions, 875 deletions
diff --git a/service/java/com/android/server/wifi/ActiveModeManager.java b/service/java/com/android/server/wifi/ActiveModeManager.java index 00ae7b3c2..6669e32f7 100644 --- a/service/java/com/android/server/wifi/ActiveModeManager.java +++ b/service/java/com/android/server/wifi/ActiveModeManager.java @@ -16,6 +16,12 @@ package com.android.server.wifi; +import android.content.Context; +import android.content.Intent; +import android.net.wifi.WifiManager; +import android.os.UserHandle; +import android.util.Log; + /** * Base class for available WiFi operating modes. * @@ -33,4 +39,22 @@ public interface ActiveModeManager { * Method used to stop the Manager for a give Wifi operational mode. */ void stop(); + + /** + * Method that allows Mode Managers to update WifiScanner about the current state. + * + * @param context Context to use for the notification + * @param available boolean indicating if scanning is available + */ + default void sendScanAvailableBroadcast(Context context, boolean available) { + Log.d(TAG, "sending scan available broadcast: " + available); + final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + if (available) { + intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_ENABLED); + } else { + intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED); + } + context.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + } } diff --git a/service/java/com/android/server/wifi/ClientModeManager.java b/service/java/com/android/server/wifi/ClientModeManager.java index 14d55de1e..bd82876df 100644 --- a/service/java/com/android/server/wifi/ClientModeManager.java +++ b/service/java/com/android/server/wifi/ClientModeManager.java @@ -26,6 +26,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; +import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.wifi.WifiNative.InterfaceCallback; @@ -44,17 +45,20 @@ public class ClientModeManager implements ActiveModeManager { private final WifiMetrics mWifiMetrics; private final Listener mListener; private final ScanRequestProxy mScanRequestProxy; + private final WifiStateMachine mWifiStateMachine; private String mClientInterfaceName; - + private boolean mIfaceIsUp; ClientModeManager(Context context, @NonNull Looper looper, WifiNative wifiNative, - Listener listener, WifiMetrics wifiMetrics, ScanRequestProxy scanRequestProxy) { + Listener listener, WifiMetrics wifiMetrics, ScanRequestProxy scanRequestProxy, + WifiStateMachine wifiStateMachine) { mContext = context; mWifiNative = wifiNative; mListener = listener; mWifiMetrics = wifiMetrics; mScanRequestProxy = scanRequestProxy; + mWifiStateMachine = wifiStateMachine; mStateMachine = new ClientModeStateMachine(looper); } @@ -69,7 +73,20 @@ public class ClientModeManager implements ActiveModeManager { * Disconnect from any currently connected networks and stop client mode. */ public void stop() { - mStateMachine.sendMessage(ClientModeStateMachine.CMD_STOP); + IState currentState = mStateMachine.getCurrentState(); + Log.d(TAG, " currentstate: " + currentState); + if (mClientInterfaceName != null) { + if (mIfaceIsUp) { + updateWifiState(WifiManager.WIFI_STATE_DISABLING, + WifiManager.WIFI_STATE_ENABLED); + } else { + updateWifiState(WifiManager.WIFI_STATE_DISABLING, + WifiManager.WIFI_STATE_ENABLING); + } + } + if (currentState != null) { + currentState.exit(); + } } /** @@ -106,37 +123,35 @@ public class ClientModeManager implements ActiveModeManager { private class ClientModeStateMachine extends StateMachine { // Commands for the state machine. public static final int CMD_START = 0; - public static final int CMD_STOP = 1; - public static final int CMD_WIFINATIVE_FAILURE = 2; public static final int CMD_INTERFACE_STATUS_CHANGED = 3; public static final int CMD_INTERFACE_DESTROYED = 4; + public static final int CMD_INTERFACE_DOWN = 5; private final State mIdleState = new IdleState(); private final State mStartedState = new StartedState(); - private WifiNative.StatusListener mWifiNativeStatusListener = (boolean isReady) -> { - if (!isReady) { - sendMessage(CMD_WIFINATIVE_FAILURE); - } - }; private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback() { @Override public void onDestroyed(String ifaceName) { - sendMessage(CMD_INTERFACE_DESTROYED); + if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { + sendMessage(CMD_INTERFACE_DESTROYED); + } } @Override public void onUp(String ifaceName) { - sendMessage(CMD_INTERFACE_STATUS_CHANGED, 1); + if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { + sendMessage(CMD_INTERFACE_STATUS_CHANGED, 1); + } } @Override public void onDown(String ifaceName) { - sendMessage(CMD_INTERFACE_STATUS_CHANGED, 0); + if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { + sendMessage(CMD_INTERFACE_STATUS_CHANGED, 0); + } } }; - private boolean mIfaceIsUp = false; - ClientModeStateMachine(Looper looper) { super(TAG, looper); @@ -152,8 +167,8 @@ public class ClientModeManager implements ActiveModeManager { @Override public void enter() { Log.d(TAG, "entering IdleState"); - mWifiNative.registerStatusListener(mWifiNativeStatusListener); mClientInterfaceName = null; + mIfaceIsUp = false; } @Override @@ -167,17 +182,15 @@ public class ClientModeManager implements ActiveModeManager { false /* not low priority */, mWifiNativeInterfaceCallback); if (TextUtils.isEmpty(mClientInterfaceName)) { Log.e(TAG, "Failed to create ClientInterface. Sit in Idle"); - sendScanAvailableBroadcast(false); updateWifiState(WifiManager.WIFI_STATE_UNKNOWN, WifiManager.WIFI_STATE_ENABLING); + updateWifiState(WifiManager.WIFI_STATE_DISABLED, + WifiManager.WIFI_STATE_UNKNOWN); break; } + sendScanAvailableBroadcast(false); transitionTo(mStartedState); break; - case CMD_STOP: - // This should be safe to ignore. - Log.d(TAG, "received CMD_STOP when idle, ignoring"); - break; default: Log.d(TAG, "received an invalid message: " + message); return NOT_HANDLED; @@ -196,14 +209,21 @@ public class ClientModeManager implements ActiveModeManager { if (isUp) { Log.d(TAG, "Wifi is ready to use for client mode"); sendScanAvailableBroadcast(true); + mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE, + mClientInterfaceName); updateWifiState(WifiManager.WIFI_STATE_ENABLED, WifiManager.WIFI_STATE_ENABLING); } else { + if (mWifiStateMachine.isConnectedMacRandomizationEnabled()) { + // Handle the error case where our underlying interface went down if we + // do not have mac randomization enabled (b/72459123). + return; + } // if the interface goes down we should exit and go back to idle state. - Log.d(TAG, "interface down! may need to restart ClientMode"); + Log.d(TAG, "interface down!"); updateWifiState(WifiManager.WIFI_STATE_UNKNOWN, - WifiManager.WIFI_STATE_UNKNOWN); - mStateMachine.sendMessage(CMD_STOP); + WifiManager.WIFI_STATE_ENABLED); + mStateMachine.sendMessage(CMD_INTERFACE_DOWN); } } @@ -221,25 +241,18 @@ public class ClientModeManager implements ActiveModeManager { case CMD_START: // Already started, ignore this command. break; - case CMD_STOP: - Log.d(TAG, "Stopping client mode."); + case CMD_INTERFACE_DOWN: + Log.e(TAG, "Detected an interface down, reporting failure to SelfRecovery"); + mWifiStateMachine.failureDetected(SelfRecovery.REASON_STA_IFACE_DOWN); + updateWifiState(WifiManager.WIFI_STATE_DISABLING, - WifiManager.WIFI_STATE_ENABLED); - mWifiNative.teardownInterface(mClientInterfaceName); + WifiManager.WIFI_STATE_UNKNOWN); transitionTo(mIdleState); break; case CMD_INTERFACE_STATUS_CHANGED: boolean isUp = message.arg1 == 1; onUpChanged(isUp); break; - case CMD_WIFINATIVE_FAILURE: - Log.d(TAG, "WifiNative failure - may need to restart ClientMode!"); - updateWifiState(WifiManager.WIFI_STATE_UNKNOWN, - WifiManager.WIFI_STATE_UNKNOWN); - updateWifiState(WifiManager.WIFI_STATE_DISABLING, - WifiManager.WIFI_STATE_ENABLED); - transitionTo(mIdleState); - break; case CMD_INTERFACE_DESTROYED: Log.d(TAG, "interface destroyed - client mode stopping"); @@ -259,12 +272,19 @@ public class ClientModeManager implements ActiveModeManager { */ @Override public void exit() { + if (mClientInterfaceName == null) { + return; + } + mWifiStateMachine.setOperationalMode(WifiStateMachine.DISABLED_MODE, null); + mWifiNative.teardownInterface(mClientInterfaceName); // let WifiScanner know that wifi is down. sendScanAvailableBroadcast(false); updateWifiState(WifiManager.WIFI_STATE_DISABLED, WifiManager.WIFI_STATE_DISABLING); mScanRequestProxy.enableScanningForHiddenNetworks(false); mScanRequestProxy.clearScanResults(); + mClientInterfaceName = null; + mIfaceIsUp = false; } } diff --git a/service/java/com/android/server/wifi/ScanOnlyModeManager.java b/service/java/com/android/server/wifi/ScanOnlyModeManager.java index f1351b24f..4973de53d 100644 --- a/service/java/com/android/server/wifi/ScanOnlyModeManager.java +++ b/service/java/com/android/server/wifi/ScanOnlyModeManager.java @@ -18,14 +18,13 @@ package com.android.server.wifi; import android.annotation.NonNull; import android.content.Context; -import android.content.Intent; import android.net.wifi.WifiManager; import android.os.Looper; import android.os.Message; -import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; +import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.wifi.WifiNative.InterfaceCallback; @@ -49,7 +48,6 @@ public class ScanOnlyModeManager implements ActiveModeManager { private String mClientInterfaceName; - ScanOnlyModeManager(@NonNull Context context, @NonNull Looper looper, @NonNull WifiNative wifiNative, @NonNull Listener listener, @NonNull WifiMetrics wifiMetrics, @@ -75,7 +73,11 @@ public class ScanOnlyModeManager implements ActiveModeManager { * Cancel any pending scans and stop scan mode. */ public void stop() { - mStateMachine.sendMessage(ScanOnlyModeStateMachine.CMD_STOP); + IState currentState = mStateMachine.getCurrentState(); + Log.d(TAG, " currentstate: " + currentState); + if (currentState != null) { + currentState.exit(); + } } /** @@ -100,8 +102,6 @@ public class ScanOnlyModeManager implements ActiveModeManager { private class ScanOnlyModeStateMachine extends StateMachine { // Commands for the state machine. public static final int CMD_START = 0; - public static final int CMD_STOP = 1; - public static final int CMD_WIFINATIVE_FAILURE = 2; public static final int CMD_INTERFACE_STATUS_CHANGED = 3; public static final int CMD_INTERFACE_DESTROYED = 4; public static final int CMD_INTERFACE_DOWN = 5; @@ -109,12 +109,6 @@ public class ScanOnlyModeManager implements ActiveModeManager { private final State mIdleState = new IdleState(); private final State mStartedState = new StartedState(); - private final WifiNative.StatusListener mWifiNativeStatusListener = (boolean isReady) -> { - if (!isReady) { - sendMessage(CMD_WIFINATIVE_FAILURE); - } - }; - private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback() { @Override public void onDestroyed(String ifaceName) { @@ -154,7 +148,6 @@ public class ScanOnlyModeManager implements ActiveModeManager { @Override public void enter() { Log.d(TAG, "entering IdleState"); - mWifiNative.registerStatusListener(mWifiNativeStatusListener); mClientInterfaceName = null; } @@ -166,16 +159,14 @@ public class ScanOnlyModeManager implements ActiveModeManager { mWifiNativeInterfaceCallback); if (TextUtils.isEmpty(mClientInterfaceName)) { Log.e(TAG, "Failed to create ClientInterface. Sit in Idle"); - sendScanAvailableBroadcast(false); updateWifiState(WifiManager.WIFI_STATE_UNKNOWN); break; } + // we have a new scanning interface, make sure scanner knows we aren't + // ready yet + sendScanAvailableBroadcast(false); transitionTo(mStartedState); break; - case CMD_STOP: - // This should be safe to ignore. - Log.d(TAG, "received CMD_STOP when idle, ignoring"); - break; default: Log.d(TAG, "received an invalid message: " + message); return NOT_HANDLED; @@ -218,12 +209,9 @@ public class ScanOnlyModeManager implements ActiveModeManager { case CMD_START: // Already started, ignore this command. break; - case CMD_STOP: - Log.d(TAG, "Stopping scan mode."); - transitionTo(mIdleState); - break; case CMD_INTERFACE_DESTROYED: Log.d(TAG, "Interface cleanly destroyed, report scan mode stop."); + mClientInterfaceName = null; transitionTo(mIdleState); break; case CMD_INTERFACE_STATUS_CHANGED: @@ -231,8 +219,7 @@ public class ScanOnlyModeManager implements ActiveModeManager { onUpChanged(isUp); break; case CMD_INTERFACE_DOWN: - case CMD_WIFINATIVE_FAILURE: - Log.d(TAG, "native/interface failure! restart services?"); + Log.d(TAG, "interface down! stop mode"); updateWifiState(WifiManager.WIFI_STATE_UNKNOWN); transitionTo(mIdleState); break; @@ -249,24 +236,18 @@ public class ScanOnlyModeManager implements ActiveModeManager { @Override public void exit() { mWakeupController.stop(); - //mWifiNative.teardownInterface(mClientInterfaceName); - // let WifiScanner know that wifi is down. - sendScanAvailableBroadcast(false); + if (mClientInterfaceName == null) { + return; + } + mWifiNative.teardownInterface(mClientInterfaceName); + mClientInterfaceName = null; updateWifiState(WifiManager.WIFI_STATE_DISABLED); mScanRequestProxy.clearScanResults(); } } + } - private void sendScanAvailableBroadcast(boolean available) { - Log.d(TAG, "sending scan available broadcast: " + available); - final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - if (available) { - intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_ENABLED); - } else { - intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED); - } - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } + private void sendScanAvailableBroadcast(boolean available) { + sendScanAvailableBroadcast(mContext, available); } } diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java index d2d0c4a37..77c217ab2 100644 --- a/service/java/com/android/server/wifi/SoftApManager.java +++ b/service/java/com/android/server/wifi/SoftApManager.java @@ -37,12 +37,12 @@ import android.util.Log; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; import com.android.server.wifi.WifiNative.InterfaceCallback; import com.android.server.wifi.WifiNative.SoftApListener; -import com.android.server.wifi.WifiNative.StatusListener; import com.android.server.wifi.util.ApConfigUtil; import java.util.Locale; @@ -72,6 +72,7 @@ public class SoftApManager implements ActiveModeManager { private final WifiManager.SoftApCallback mCallback; private String mApInterfaceName; + private boolean mIfaceIsUp; private final WifiApConfigStore mWifiApConfigStore; @@ -134,7 +135,20 @@ public class SoftApManager implements ActiveModeManager { * Stop soft AP. */ public void stop() { - mStateMachine.sendMessage(SoftApStateMachine.CMD_STOP); + IState currentState = mStateMachine.getCurrentState(); + Log.d(TAG, " currentstate: " + currentState); + if (mApInterfaceName != null) { + if (mIfaceIsUp) { + updateApState(WifiManager.WIFI_AP_STATE_DISABLING, + WifiManager.WIFI_AP_STATE_ENABLED, 0); + } else { + updateApState(WifiManager.WIFI_AP_STATE_DISABLING, + WifiManager.WIFI_AP_STATE_ENABLING, 0); + } + } + if (currentState != null) { + currentState.exit(); + } } /** @@ -219,8 +233,6 @@ public class SoftApManager implements ActiveModeManager { private class SoftApStateMachine extends StateMachine { // Commands for the state machine. public static final int CMD_START = 0; - public static final int CMD_STOP = 1; - public static final int CMD_WIFINATIVE_FAILURE = 2; public static final int CMD_INTERFACE_STATUS_CHANGED = 3; public static final int CMD_NUM_ASSOCIATED_STATIONS_CHANGED = 4; public static final int CMD_NO_ASSOCIATED_STATIONS_TIMEOUT = 5; @@ -232,12 +244,6 @@ public class SoftApManager implements ActiveModeManager { private final State mIdleState = new IdleState(); private final State mStartedState = new StartedState(); - private final StatusListener mWifiNativeStatusListener = (boolean isReady) -> { - if (!isReady) { - sendMessage(CMD_WIFINATIVE_FAILURE); - } - }; - private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback() { @Override public void onDestroyed(String ifaceName) { @@ -274,8 +280,8 @@ public class SoftApManager implements ActiveModeManager { private class IdleState extends State { @Override public void enter() { - mWifiNative.registerStatusListener(mWifiNativeStatusListener); mApInterfaceName = null; + mIfaceIsUp = false; } @Override @@ -320,8 +326,6 @@ public class SoftApManager implements ActiveModeManager { } private class StartedState extends State { - private boolean mIfaceIsUp; - private int mNumAssociatedStations; private boolean mTimeoutEnabled; @@ -454,8 +458,10 @@ public class SoftApManager implements ActiveModeManager { @Override public void exit() { - // will trigger interface teardown when interface management is dynamic - // stopSoftAp(); + if (mApInterfaceName == null) { + return; + } + stopSoftAp(); if (mSettingObserver != null) { mSettingObserver.unregister(); } @@ -467,6 +473,8 @@ public class SoftApManager implements ActiveModeManager { mWifiMetrics.addSoftApUpChangedEvent(false, mMode); updateApState(WifiManager.WIFI_AP_STATE_DISABLED, WifiManager.WIFI_AP_STATE_DISABLING, 0); + mApInterfaceName = null; + mIfaceIsUp = false; } @Override @@ -517,12 +525,6 @@ public class SoftApManager implements ActiveModeManager { break; } Log.i(TAG, "Timeout message received. Stopping soft AP."); - stopSoftAp(); - updateApState(WifiManager.WIFI_AP_STATE_DISABLING, - WifiManager.WIFI_AP_STATE_ENABLED, 0); - transitionTo(mIdleState); - break; - case CMD_STOP: updateApState(WifiManager.WIFI_AP_STATE_DISABLING, WifiManager.WIFI_AP_STATE_ENABLED, 0); transitionTo(mIdleState); @@ -533,9 +535,8 @@ public class SoftApManager implements ActiveModeManager { WifiManager.WIFI_AP_STATE_ENABLED, 0); transitionTo(mIdleState); break; - case CMD_WIFINATIVE_FAILURE: case CMD_INTERFACE_DOWN: - Log.w(TAG, "native/interface error, stop and report failure"); + Log.w(TAG, "interface error, stop and report failure"); updateApState(WifiManager.WIFI_AP_STATE_FAILED, WifiManager.WIFI_AP_STATE_ENABLED, WifiManager.SAP_START_FAILURE_GENERAL); diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java index 76b44c82f..7fb223535 100644 --- a/service/java/com/android/server/wifi/WifiController.java +++ b/service/java/com/android/server/wifi/WifiController.java @@ -30,6 +30,7 @@ import android.os.Message; import android.os.SystemClock; import android.os.WorkSource; import android.provider.Settings; +import android.util.Log; import com.android.internal.util.Protocol; import com.android.internal.util.State; @@ -93,6 +94,8 @@ public class WifiController extends StateMachine { 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; + static final int CMD_STA_STOPPED = BASE + 20; + static final int CMD_SCANNING_STOPPED = BASE + 21; private DefaultState mDefaultState = new DefaultState(); private StaEnabledState mStaEnabledState = new StaEnabledState(); @@ -102,6 +105,9 @@ public class WifiController extends StateMachine { private DeviceActiveState mDeviceActiveState = new DeviceActiveState(); private EcmState mEcmState = new EcmState(); + private ScanOnlyModeManager.Listener mScanOnlyModeCallback = new ScanOnlyCallback(); + private ClientModeManager.Listener mClientModeCallback = new ClientModeCallback(); + WifiController(Context context, WifiStateMachine wsm, Looper wifiStateMachineLooper, WifiSettingsStore wss, Looper wifiServiceLooper, FrameworkFacade f, WifiStateMachinePrime wsmp) { @@ -113,6 +119,7 @@ public class WifiController extends StateMachine { mWifiStateMachinePrime = wsmp; mSettingsStore = wss; + // CHECKSTYLE:OFF IndentationCheck addState(mDefaultState); addState(mApStaDisabledState, mDefaultState); addState(mStaEnabledState, mDefaultState); @@ -120,6 +127,7 @@ public class WifiController extends StateMachine { addState(mStaDisabledWithScanState, mDefaultState); addState(mApEnabledState, mDefaultState); addState(mEcmState, mDefaultState); + // CHECKSTYLE:ON IndentationCheck boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn(); boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled(); @@ -142,6 +150,10 @@ public class WifiController extends StateMachine { setLogRecSize(100); setLogOnlyTransitions(false); + // register for state updates via callbacks (vs the intents registered below) + mWifiStateMachinePrime.registerScanOnlyCallback(mScanOnlyModeCallback); + mWifiStateMachinePrime.registerClientModeCallback(mClientModeCallback); + IntentFilter filter = new IntentFilter(); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); @@ -160,19 +172,11 @@ public class WifiController extends StateMachine { WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED); if (state == WifiManager.WIFI_AP_STATE_FAILED) { - loge(TAG + "SoftAP start failed"); + Log.e(TAG, "SoftAP start failed"); sendMessage(CMD_AP_START_FAILURE); } else if (state == WifiManager.WIFI_AP_STATE_DISABLED) { sendMessage(CMD_AP_STOPPED); } - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - int state = intent.getIntExtra( - WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN); - if (state == WifiManager.WIFI_STATE_UNKNOWN) { - loge(TAG + "Wifi turn on failed"); - sendMessage(CMD_STA_START_FAILURE); - } } else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) { // Location mode has been toggled... trigger with the scan change // update to make sure we are in the correct mode @@ -194,6 +198,48 @@ public class WifiController extends StateMachine { return mSettingsStore.isScanAlwaysAvailable(); } + /** + * Listener used to receive scan mode updates - really needed for disabled updates to trigger + * mode changes. + */ + private class ScanOnlyCallback implements ScanOnlyModeManager.Listener { + @Override + public void onStateChanged(int state) { + if (state == WifiManager.WIFI_STATE_UNKNOWN) { + Log.d(TAG, "ScanOnlyMode unexpected failure: state unknown"); + } else if (state == WifiManager.WIFI_STATE_DISABLED) { + Log.d(TAG, "ScanOnlyMode stopped"); + sendMessage(CMD_SCANNING_STOPPED); + } else if (state == WifiManager.WIFI_STATE_ENABLED) { + // scan mode is ready to go + Log.d(TAG, "scan mode active"); + } else { + Log.d(TAG, "unexpected state update: " + state); + } + } + } + + /** + * Listener used to receive client mode updates + */ + private class ClientModeCallback implements ClientModeManager.Listener { + @Override + public void onStateChanged(int state) { + if (state == WifiManager.WIFI_STATE_UNKNOWN) { + logd("ClientMode unexpected failure: state unknown"); + sendMessage(CMD_STA_START_FAILURE); + } else if (state == WifiManager.WIFI_STATE_DISABLED) { + logd("ClientMode stopped"); + sendMessage(CMD_STA_STOPPED); + } else if (state == WifiManager.WIFI_STATE_ENABLED) { + // scan mode is ready to go + logd("client mode active"); + } else { + logd("unexpected state update: " + state); + } + } + } + private void readWifiReEnableDelay() { mReEnableDelayMillis = mFacade.getLongSetting(mContext, Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS); @@ -216,11 +262,18 @@ public class WifiController extends StateMachine { case CMD_EMERGENCY_CALL_STATE_CHANGED: case CMD_AP_START_FAILURE: case CMD_AP_STOPPED: + case CMD_SCANNING_STOPPED: + case CMD_STA_STOPPED: case CMD_STA_START_FAILURE: - case CMD_RECOVERY_RESTART_WIFI: case CMD_RECOVERY_RESTART_WIFI_CONTINUE: case CMD_RECOVERY_DISABLE_WIFI: break; + case CMD_RECOVERY_RESTART_WIFI: + // TODO:b/72850700 : when softap is split out, we need to fully disable wifi + // here (like airplane mode toggle). + deferMessage(obtainMessage(CMD_RECOVERY_RESTART_WIFI_CONTINUE)); + transitionTo(mApStaDisabledState); + break; case CMD_USER_PRESENT: mFirstUserSignOnSeen = true; break; @@ -242,7 +295,6 @@ public class WifiController extends StateMachine { @Override public void enter() { - mWifiStateMachine.setOperationalMode(WifiStateMachine.DISABLED_MODE); mWifiStateMachinePrime.disableWifi(); // Supplicant can't restart right away, so note the time we switched off mDisabledTimestamp = SystemClock.elapsedRealtime(); @@ -264,11 +316,6 @@ public class WifiController extends StateMachine { mHaveDeferredEnable = !mHaveDeferredEnable; break; } - // wifi is toggled, we need to explicitly tell WifiStateMachine that we - // are headed to connect mode before going to the DeviceActiveState - // since that will start supplicant and WifiStateMachine may not know - // what state to head to (it might go to scan mode). - mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); transitionTo(mDeviceActiveState); } else if (checkScanOnlyModeAvailable()) { transitionTo(mStaDisabledWithScanState); @@ -279,15 +326,17 @@ public class WifiController extends StateMachine { transitionTo(mStaDisabledWithScanState); break; } - mWifiStateMachine.setOperationalMode(WifiStateMachine.DISABLED_MODE); break; case CMD_SET_AP: + // first make sure we aren't in airplane mode + if (mSettingsStore.isAirplaneModeOn()) { + log("drop softap requests when in airplane mode"); + break; + } if (msg.arg1 == 1) { if (msg.arg2 == 0) { // previous wifi state has not been saved yet mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED); } - mWifiStateMachine.setHostApRunning((SoftApModeConfiguration) msg.obj, - true); mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj); transitionTo(mApEnabledState); } @@ -301,7 +350,15 @@ public class WifiController extends StateMachine { sendMessage((Message)(msg.obj)); break; case CMD_RECOVERY_RESTART_WIFI_CONTINUE: - transitionTo(mDeviceActiveState); + if (mSettingsStore.isWifiToggleEnabled()) { + // wifi is currently disabled but the toggle is on, must have had an + // interface down before the recovery triggered + transitionTo(mDeviceActiveState); + break; + } else if (checkScanOnlyModeAvailable()) { + transitionTo(mStaDisabledWithScanState); + break; + } break; default: return NOT_HANDLED; @@ -372,15 +429,14 @@ public class WifiController extends StateMachine { break; case CMD_SET_AP: if (msg.arg1 == 1) { - // remeber that we were enabled + // remember that we were enabled mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_ENABLED); - mWifiStateMachine.setHostApRunning((SoftApModeConfiguration) msg.obj, true); + // since softap is not split out in WifiController, need to explicitly + // disable client and scan modes + mWifiStateMachinePrime.disableWifi(); + mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj); transitionTo(mApEnabledState); - // we should just go directly to ApEnabled since we will kill interfaces - // from WSMP - //deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj)); - //transitionTo(mApStaDisabledState); } break; default: @@ -398,9 +454,6 @@ public class WifiController extends StateMachine { @Override public void enter() { - // first send the message to WSM to trigger the transition and act as a shadow - mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE); - // now trigger the actual mode switch in WifiStateMachinePrime mWifiStateMachinePrime.enterScanOnlyMode(); @@ -424,8 +477,6 @@ public class WifiController extends StateMachine { mHaveDeferredEnable = !mHaveDeferredEnable; break; } - // transition from scan mode to initial state in WifiStateMachine - mWifiStateMachine.setOperationalMode(WifiStateMachine.DISABLED_MODE); transitionTo(mDeviceActiveState); } break; @@ -445,14 +496,12 @@ public class WifiController extends StateMachine { // Before starting tethering, turn off supplicant for scan mode if (msg.arg1 == 1) { mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED); + // since softap is not split out in WifiController, need to explicitly + // disable client and scan modes + mWifiStateMachinePrime.disableWifi(); - mWifiStateMachine.setHostApRunning((SoftApModeConfiguration) msg.obj, true); mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj); transitionTo(mApEnabledState); - // we should just go directly to ApEnabled since we will kill interfaces - // from WSMP - //deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj)); - //transitionTo(mApStaDisabledState); } break; case CMD_DEFERRED_TOGGLE: @@ -517,31 +566,29 @@ public class WifiController extends StateMachine { } @Override + public void exit() { + mWifiStateMachinePrime.stopSoftAPMode(); + } + + @Override public boolean processMessage(Message msg) { switch (msg.what) { case CMD_AIRPLANE_TOGGLED: if (mSettingsStore.isAirplaneModeOn()) { - mWifiStateMachine.setHostApRunning(null, false); - mWifiStateMachinePrime.disableWifi(); - mPendingState = mApStaDisabledState; + transitionTo(mApStaDisabledState); } break; case CMD_WIFI_TOGGLED: if (mSettingsStore.isWifiToggleEnabled()) { - mWifiStateMachine.setHostApRunning(null, false); - mWifiStateMachinePrime.disableWifi(); - mPendingState = mDeviceActiveState; + transitionTo(mDeviceActiveState); } break; case CMD_SET_AP: if (msg.arg1 == 0) { - mWifiStateMachine.setHostApRunning(null, false); - mWifiStateMachinePrime.disableWifi(); - mPendingState = getNextWifiState(); + transitionTo(getNextWifiState()); } break; case CMD_AP_STOPPED: - mWifiStateMachine.setHostApRunning(null, false); if (mPendingState == null) { /** * Stop triggered internally, either tether notification @@ -554,13 +601,18 @@ public class WifiController extends StateMachine { case CMD_EMERGENCY_CALL_STATE_CHANGED: case CMD_EMERGENCY_MODE_CHANGED: if (msg.arg1 == 1) { - mWifiStateMachine.setHostApRunning(null, false); - mWifiStateMachinePrime.disableWifi(); - mPendingState = mEcmState; + transitionTo(mEcmState); } break; case CMD_AP_START_FAILURE: - mWifiStateMachine.setHostApRunning(null, false); + transitionTo(getNextWifiState()); + break; + case CMD_RECOVERY_RESTART_WIFI: + case CMD_RECOVERY_DISABLE_WIFI: + // note: this will need to fully shutdown wifi when softap mode is removed from + // the state machine + loge("Recovery triggered while in softap active, disable"); + mWifiStateMachinePrime.disableWifi(); transitionTo(getNextWifiState()); break; default: @@ -578,7 +630,6 @@ public class WifiController extends StateMachine { private int mEcmEntryCount; @Override public void enter() { - mWifiStateMachine.setOperationalMode(WifiStateMachine.DISABLED_MODE); mWifiStateMachinePrime.disableWifi(); mWifiStateMachine.clearANQPCache(); mEcmEntryCount = 1; @@ -605,6 +656,10 @@ public class WifiController extends StateMachine { decrementCountAndReturnToAppropriateState(); } return HANDLED; + } else if (msg.what == CMD_RECOVERY_RESTART_WIFI + || msg.what == CMD_RECOVERY_DISABLE_WIFI) { + // do not want to restart wifi if we are in emergency mode + return HANDLED; } else { return NOT_HANDLED; } @@ -636,7 +691,6 @@ public class WifiController extends StateMachine { class DeviceActiveState extends State { @Override public void enter() { - mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); mWifiStateMachinePrime.enterClientMode(); mWifiStateMachine.setHighPerfModeEnabled(false); } diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 82f7d6cb2..cdde22268 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -257,7 +257,7 @@ public class WifiInjector { this, mBackupManagerProxy, mCountryCode, mWifiNative, new WrongPasswordNotifier(mContext, mFrameworkFacade)); IBinder b = mFrameworkFacade.getService(Context.NETWORKMANAGEMENT_SERVICE); - mWifiStateMachinePrime = new WifiStateMachinePrime(this, wifiStateMachineLooper, + mWifiStateMachinePrime = new WifiStateMachinePrime(this, mContext, wifiStateMachineLooper, mWifiNative, new DefaultModeManager(mContext, wifiStateMachineLooper), mBatteryStats); mOpenNetworkNotifier = new OpenNetworkNotifier(mContext, @@ -474,7 +474,7 @@ public class WifiInjector { */ public ClientModeManager makeClientModeManager(ClientModeManager.Listener listener) { return new ClientModeManager(mContext, mWifiStateMachineHandlerThread.getLooper(), - mWifiNative, listener, mWifiMetrics, mScanRequestProxy); + mWifiNative, listener, mWifiMetrics, mScanRequestProxy, mWifiStateMachine); } /** diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index dbb83609b..32427c92c 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -96,8 +96,6 @@ import com.android.internal.util.MessageUtils; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; -import com.android.server.wifi.WifiNative.InterfaceCallback; -import com.android.server.wifi.WifiNative.StatusListener; import com.android.server.wifi.hotspot2.AnqpEvent; import com.android.server.wifi.hotspot2.IconEvent; import com.android.server.wifi.hotspot2.NetworkDetail; @@ -130,17 +128,12 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** - * TODO: - * Deprecate WIFI_STATE_UNKNOWN - */ - -/** * Track the state of Wifi connectivity. All event handling is done here, * and all changes in connectivity state are initiated here. * * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p * In the current implementation, we support concurrent wifi p2p and wifi operation. - * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService + * The WifiStateMachine handles Client operations while WifiP2pService * handles p2p operation. * * @hide @@ -196,7 +189,6 @@ public class WifiStateMachine extends StateMachine { private ConnectivityManager mCm; private BaseWifiDiagnostics mWifiDiagnostics; private ScanRequestProxy mScanRequestProxy; - private WifiApConfigStore mWifiApConfigStore; private final boolean mP2pSupported; private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); private boolean mTemporarilyDisconnectWifi = false; @@ -221,45 +213,8 @@ public class WifiStateMachine extends StateMachine { private String mLastBssid; private int mLastNetworkId; // The network Id we successfully joined - private final StatusListener mWifiNativeStatusListener = (boolean isReady) -> { - if (!isReady) { - sendMessage(CMD_WIFINATIVE_FAILURE); - } - }; - - private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback() { - @Override - public void onDestroyed(String ifaceName) { - 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; - private WifiManager.SoftApCallback mSoftApCallback; - - /** - * Called from WifiServiceImpl to register a callback for notifications from SoftApManager - */ - public void registerSoftApCallback(WifiManager.SoftApCallback callback) { - mSoftApCallback = callback; - } - private void processRssiThreshold(byte curRssi, int reason, WifiNative.WifiRssiEventHandler rssiHandler) { if (curRssi == Byte.MAX_VALUE || curRssi == Byte.MIN_VALUE) { @@ -303,6 +258,8 @@ public class WifiStateMachine extends StateMachine { // variable indicating we are expecting a mode switch - do not attempt recovery for failures private boolean mModeChange = false; + private ClientModeManager.Listener mClientModeCallback = null; + private boolean mBluetoothConnectionActive = false; private PowerManager.WakeLock mSuspendWakeLock; @@ -460,29 +417,10 @@ public class WifiStateMachine extends StateMachine { /* The base for wifi message types */ static final int BASE = Protocol.BASE_WIFI; - /* Start the STA interface */ - static final int CMD_START_SUPPLICANT = BASE + 11; - /* Stop the STA interface */ - 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; - /* 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; - /* Indicates soft ap start failed */ - static final int CMD_START_AP_FAILURE = BASE + 22; - /* Stop the soft access point */ - static final int CMD_STOP_AP = BASE + 23; - /* Soft access point teardown is completed. */ - static final int CMD_AP_STOPPED = BASE + 24; static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; @@ -698,9 +636,6 @@ public class WifiStateMachine extends StateMachine { /* used to indicate that the foreground user was switched */ static final int CMD_USER_STOP = BASE + 207; - /* Signals that one of the native daemons is dead. */ - private static final int CMD_WIFINATIVE_FAILURE = BASE + 250; - /* Indicates that diagnostics should time out a connection start event. */ private static final int CMD_DIAGS_CONNECT_TIMEOUT = BASE + 252; @@ -776,12 +711,6 @@ public class WifiStateMachine extends StateMachine { /* Default parent state */ private State mDefaultState = new DefaultState(); - /* Temporary initial state */ - private State mInitialState = new InitialState(); - /* Driver loaded and supplicant ready */ - private State mSupplicantStartedState = new SupplicantStartedState(); - /* Scan for networks, no connection will be established */ - private State mScanModeState = new ScanModeState(); /* Connecting to an access point */ private State mConnectModeState = new ConnectModeState(); /* Connected at 802.11 (L2) level */ @@ -796,8 +725,6 @@ public class WifiStateMachine extends StateMachine { private State mDisconnectingState = new DisconnectingState(); /* Network is not connected, supplicant assoc+auth is not complete */ private State mDisconnectedState = new DisconnectedState(); - /* Soft ap state */ - private State mSoftApState = new SoftApState(); /** * One of {@link WifiManager#WIFI_STATE_DISABLED}, @@ -998,17 +925,13 @@ public class WifiStateMachine extends StateMachine { // CHECKSTYLE:OFF IndentationCheck addState(mDefaultState); - addState(mInitialState, mDefaultState); - addState(mSupplicantStartedState, mInitialState); - addState(mConnectModeState, mSupplicantStartedState); - addState(mL2ConnectedState, mConnectModeState); - addState(mObtainingIpState, mL2ConnectedState); - addState(mConnectedState, mL2ConnectedState); - addState(mRoamingState, mL2ConnectedState); - addState(mDisconnectingState, mConnectModeState); - addState(mDisconnectedState, mConnectModeState); - addState(mScanModeState, mDefaultState); - addState(mSoftApState, mDefaultState); + addState(mConnectModeState, mDefaultState); + addState(mL2ConnectedState, mConnectModeState); + addState(mObtainingIpState, mL2ConnectedState); + addState(mConnectedState, mL2ConnectedState); + addState(mRoamingState, mL2ConnectedState); + addState(mDisconnectingState, mConnectModeState); + addState(mDisconnectedState, mConnectModeState); // CHECKSTYLE:ON IndentationCheck setInitialState(mDefaultState); @@ -1022,13 +945,6 @@ public class WifiStateMachine extends StateMachine { // Learn the initial state of whether the screen is on. // We update this field when we receive broadcasts from the system. handleScreenStateChanged(powerManager.isInteractive()); - - final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - - sendWifiScanAvailable(false); } private void registerForWifiMonitorEvents() { @@ -1457,28 +1373,6 @@ public class WifiStateMachine extends StateMachine { /** * TODO: doc */ - public void setSupplicantRunning(boolean enable) { - if (enable) { - sendMessage(CMD_START_SUPPLICANT); - } else { - sendMessage(CMD_STOP_SUPPLICANT); - } - } - - /** - * TODO: doc - */ - public void setHostApRunning(SoftApModeConfiguration wifiConfig, boolean enable) { - if (enable) { - sendMessage(CMD_START_AP, wifiConfig); - } else { - sendMessage(CMD_STOP_AP); - } - } - - /** - * TODO: doc - */ public int syncGetWifiState() { return mWifiState.get(); } @@ -1554,9 +1448,12 @@ public class WifiStateMachine extends StateMachine { /** * TODO: doc */ - public void setOperationalMode(int mode) { - if (mVerboseLoggingEnabled) log("setting operational mode to " + String.valueOf(mode)); + public void setOperationalMode(int mode, String ifaceName) { + if (mVerboseLoggingEnabled) { + log("setting operational mode to " + String.valueOf(mode) + " for iface: " + ifaceName); + } mModeChange = true; + mInterfaceName = ifaceName; sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); } @@ -2532,17 +2429,6 @@ public class WifiStateMachine extends StateMachine { if (mVerboseLoggingEnabled) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); } - private void sendWifiScanAvailable(boolean available) { - int state = WIFI_STATE_DISABLED; - if (available) { - state = WIFI_STATE_ENABLED; - } - final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, state); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - private void setWifiState(int wifiState) { final int previousWifiState = mWifiState.get(); @@ -2550,6 +2436,17 @@ public class WifiStateMachine extends StateMachine { if (mVerboseLoggingEnabled) log("setWifiState: " + syncGetWifiStateByName()); + // first let WifiController know what is going on + if (mClientModeCallback != null) { + mClientModeCallback.onStateChanged(wifiState); + // once this instance of client mode is complete, remove the callback so we don't + // confuse ourselves + if (wifiState == WifiManager.WIFI_STATE_UNKNOWN + || wifiState == WifiManager.WIFI_STATE_DISABLED) { + mClientModeCallback = null; + } + } + final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); @@ -3373,20 +3270,22 @@ public class WifiStateMachine extends StateMachine { } /** - * Handle the error case where our underlying interface went down (if we do not have mac - * randomization enabled (b/72459123). + * Helper method to check if Connected MAC Randomization is enabled - onDown events are skipped + * if this feature is 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. + * @return boolean true if Connected MAC randomization is enabled, false otherwise */ - 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; - } + public boolean isConnectedMacRandomizationEnabled() { + return mEnableConnectedMacRandomization.get(); + } - Log.e(TAG, "Detected an interface down, report failure to SelfRecovery"); + /** + * Helper method allowing ClientModeManager to report an error (interface went down) and trigger + * recovery. + * + * @param reason int indicating the SelfRecovery failure type. + */ + public void failureDetected(int reason) { // report a failure mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_STA_IFACE_DOWN); } @@ -3497,11 +3396,6 @@ public class WifiStateMachine extends StateMachine { case CMD_SCREEN_STATE_CHANGED: handleScreenStateChanged(message.arg1 != 0); break; - case CMD_START_SUPPLICANT: - case CMD_STOP_SUPPLICANT: - case CMD_START_AP_FAILURE: - case CMD_STOP_AP: - case CMD_AP_STOPPED: case CMD_DISCONNECT: case CMD_RECONNECT: case CMD_REASSOCIATE: @@ -3530,15 +3424,8 @@ public class WifiStateMachine extends StateMachine { case CMD_DISABLE_P2P_WATCHDOG_TIMER: case CMD_DISABLE_EPHEMERAL_NETWORK: 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: - transitionTo(mSoftApState); - break; case CMD_SET_OPERATIONAL_MODE: mOperationalMode = message.arg1; // now processing the mode change - we will start setting up new state and want @@ -3549,10 +3436,7 @@ public class WifiStateMachine extends StateMachine { transitionTo(mDefaultState); break; } else if (mOperationalMode == CONNECT_MODE) { - transitionTo(mInitialState); - } else if (mOperationalMode == SCAN_ONLY_MODE - || mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { - transitionTo(mScanModeState); + transitionTo(mDisconnectedState); } else { Log.e(TAG, "set operational mode with invalid mode: " + mOperationalMode); mOperationalMode = DISABLED_MODE; @@ -3721,337 +3605,6 @@ 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 - sendWifiScanAvailable(false); - - mWifiNative.registerStatusListener(mWifiNativeStatusListener); - // TODO: This teardown should ideally be handled in STOP_SUPPLICANT to be consistent - // with other mode managers. But, client mode is not yet controlled by - // WifiStateMachinePrime. - // TODO: Remove this big hammer. We cannot support concurrent interfaces with this! - mWifiNative.teardownAllInterfaces(); - mInterfaceName = null; - mIfaceIsUp = false; - } - - @Override - public void enter() { - mIfaceIsUp = false; - mWifiStateTracker.updateState(WifiStateTracker.INVALID); - cleanup(); - sendMessage(CMD_START_SUPPLICANT); - setWifiState(WIFI_STATE_ENABLING); - } - - @Override - public boolean processMessage(Message message) { - logStateAndMessage(message, this); - switch (message.what) { - case CMD_START_SUPPLICANT: - mInterfaceName = mWifiNative.setupInterfaceForClientMode(false, - mWifiNativeInterfaceCallback); - if (TextUtils.isEmpty(mInterfaceName)) { - Log.e(TAG, "setup failure when creating client interface."); - setWifiState(WifiManager.WIFI_STATE_UNKNOWN); - 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); - if (mVerboseLoggingEnabled) log("Supplicant start successful"); - registerForWifiMonitorEvents(); - mWifiInjector.getWifiLastResortWatchdog().clearAllFailureCounts(); - setSupplicantLogLevel(); - transitionTo(mSupplicantStartedState); - break; - case CMD_SET_OPERATIONAL_MODE: - if (message.arg1 == CONNECT_MODE) { - break; - } else { - return NOT_HANDLED; - } - case CMD_WIFINATIVE_FAILURE: - Log.e(TAG, "One of the native daemons died unexpectedly. Triggering recovery"); - mWifiDiagnostics.captureBugReportData( - WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE); - mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE); - break; - 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; - } - - onUpChanged(isUp); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class SupplicantStartedState extends State { - @Override - public void enter() { - if (mVerboseLoggingEnabled) { - 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(); - mCountryCode.setReadyForChange(true); - - if (mWifiConnectivityManager == null) { - synchronized (mWifiReqCountLock) { - mWifiConnectivityManager = - mWifiInjector.makeWifiConnectivityManager(mWifiInfo, - hasConnectionRequests()); - mWifiConnectivityManager.setUntrustedConnectionAllowed(mUntrustedReqCount > 0); - mWifiConnectivityManager.handleScreenStateChanged(mScreenOn); - } - } - - mWifiDiagnostics.startLogging(mVerboseLoggingEnabled); - mIsRunning = true; - updateBatteryWorkSource(null); - /** - * Enable bluetooth coexistence scan mode when bluetooth connection is active. - * When this mode is on, some of the low-level scan parameters used by the - * driver are changed to reduce interference with bluetooth - */ - mWifiNative.setBluetoothCoexistenceScanMode(mInterfaceName, mBluetoothConnectionActive); - // Check if there is a voice call on-going and set/reset the tx power limit - // appropriately. - if (mEnableVoiceCallSarTxPowerLimit) { - if (getTelephonyManager().isOffhook()) { - sendMessage(CMD_SELECT_TX_POWER_SCENARIO, - WifiNative.TX_POWER_SCENARIO_VOICE_CALL); - } else { - sendMessage(CMD_SELECT_TX_POWER_SCENARIO, - WifiNative.TX_POWER_SCENARIO_NORMAL); - } - } - - // initialize network state - setNetworkDetailedState(DetailedState.DISCONNECTED); - - // Disable legacy multicast filtering, which on some chipsets defaults to enabled. - // Legacy IPv6 multicast filtering blocks ICMPv6 router advertisements which breaks IPv6 - // provisioning. Legacy IPv4 multicast filtering may be re-enabled later via - // IpClient.Callback.setFallbackMulticastFilter() - mWifiNative.stopFilteringMulticastV4Packets(mInterfaceName); - mWifiNative.stopFilteringMulticastV6Packets(mInterfaceName); - - // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin - transitionTo(mDisconnectedState); - - // Set the right suspend mode settings - mWifiNative.setSuspendOptimizations(mInterfaceName, mSuspendOptNeedsDisabled == 0 - && mUserWantsSuspendOpt.get()); - - mWifiNative.setPowerSave(mInterfaceName, true); - - if (mP2pSupported) { - p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P); - } - - // Disable wpa_supplicant from auto reconnecting. - mWifiNative.enableStaAutoReconnect(mInterfaceName, false); - // STA has higher priority over P2P - mWifiNative.setConcurrencyPriority(true); - } - - @Override - public boolean processMessage(Message message) { - logStateAndMessage(message, this); - - switch(message.what) { - case CMD_TARGET_BSSID: - // Trying to associate to this BSSID - if (message.obj != null) { - mTargetRoamBSSID = (String) message.obj; - } - break; - case CMD_GET_LINK_LAYER_STATS: - WifiLinkLayerStats stats = getWifiLinkLayerStats(); - replyToMessage(message, message.what, stats); - break; - case CMD_RESET_SIM_NETWORKS: - log("resetting EAP-SIM/AKA/AKA' networks since SIM was changed"); - mWifiConfigManager.resetSimNetworks(message.arg1 == 1); - break; - case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: - mBluetoothConnectionActive = (message.arg1 != - BluetoothAdapter.STATE_DISCONNECTED); - mWifiNative.setBluetoothCoexistenceScanMode( - mInterfaceName, mBluetoothConnectionActive); - break; - case CMD_SET_SUSPEND_OPT_ENABLED: - if (message.arg1 == 1) { - setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); - if (message.arg2 == 1) { - mSuspendWakeLock.release(); - } - } else { - setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); - } - break; - case CMD_SET_HIGH_PERF_MODE: - if (message.arg1 == 1) { - setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); - } else { - setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); - } - break; - case CMD_ENABLE_TDLS: - if (message.obj != null) { - String remoteAddress = (String) message.obj; - boolean enable = (message.arg1 == 1); - mWifiNative.startTdls(mInterfaceName, remoteAddress, enable); - } - break; - case WifiMonitor.ANQP_DONE_EVENT: - // TODO(zqiu): remove this when switch over to wificond for ANQP requests. - mPasspointManager.notifyANQPDone((AnqpEvent) message.obj); - break; - case CMD_STOP_IP_PACKET_OFFLOAD: { - int slot = message.arg1; - int ret = stopWifiIPPacketOffload(slot); - if (mNetworkAgent != null) { - mNetworkAgent.onPacketKeepaliveEvent(slot, ret); - } - break; - } - case WifiMonitor.RX_HS20_ANQP_ICON_EVENT: - // TODO(zqiu): remove this when switch over to wificond for icon requests. - mPasspointManager.notifyIconDone((IconEvent) message.obj); - break; - case WifiMonitor.HS20_REMEDIATION_EVENT: - // TODO(zqiu): remove this when switch over to wificond for WNM frames - // monitoring. - mPasspointManager.receivedWnmFrame((WnmData) message.obj); - break; - case CMD_CONFIG_ND_OFFLOAD: - final boolean enabled = (message.arg1 > 0); - mWifiNative.configureNeighborDiscoveryOffload(mInterfaceName, enabled); - break; - case CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER: - mWifiConnectivityManager.enable(message.arg1 == 1 ? true : false); - break; - case CMD_SELECT_TX_POWER_SCENARIO: - int txPowerScenario = message.arg1; - logd("Setting Tx power scenario to " + txPowerScenario); - if (!mWifiNative.selectTxPowerScenario(txPowerScenario)) { - loge("Failed to set TX power scenario"); - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - @Override - public void exit() { - setWifiState(WIFI_STATE_DISABLING); - // when client mode is moved to WSMP, cleanup will be done on exit. For now, cleanup is - // done when entering a mode. - - // exiting supplicant started state is now only applicable to client mode - mWifiDiagnostics.stopLogging(); - - if (mP2pSupported) { - // we are not going to wait for a response - will still temporarily send the - // disable command until p2p can detect the interface up/down on its own. - p2pSendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); - } - - handleNetworkDisconnect(); - - mIsRunning = false; - updateBatteryWorkSource(null); - - mNetworkInfo.setIsAvailable(false); - if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); - mCountryCode.setReadyForChange(false); - setWifiState(WIFI_STATE_DISABLED); - } - } - - class ScanModeState extends State { - private int mLastOperationMode; - @Override - public void enter() { - logd("entering ScanModeState"); - mWifiStateTracker.updateState(WifiStateTracker.SCAN_MODE); - } - - @Override - public void exit() {} - - @Override - public boolean processMessage(Message message) { - logStateAndMessage(message, this); - - if (message.what == CMD_SET_OPERATIONAL_MODE) { - int operationMode = message.arg1; - if (operationMode == SCAN_ONLY_MODE - || operationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { - // nothing to do, stay here... - return HANDLED; - } - return NOT_HANDLED; - } - return NOT_HANDLED; - } - } - - String smToString(Message message) { return smToString(message.what); } @@ -4141,6 +3694,113 @@ public class WifiStateMachine extends StateMachine { return s; } + /** + * Helper method to start other services and get state ready for client mode + */ + private void setupClientMode() { + mWifiStateTracker.updateState(WifiStateTracker.INVALID); + + if (mWifiConnectivityManager == null) { + synchronized (mWifiReqCountLock) { + mWifiConnectivityManager = + mWifiInjector.makeWifiConnectivityManager(mWifiInfo, + hasConnectionRequests()); + mWifiConnectivityManager.setUntrustedConnectionAllowed(mUntrustedReqCount > 0); + mWifiConnectivityManager.handleScreenStateChanged(mScreenOn); + } + } + + mIpClient = mFacade.makeIpClient(mContext, mInterfaceName, new IpClientCallback()); + mIpClient.setMulticastFilter(true); + registerForWifiMonitorEvents(); + mWifiInjector.getWifiLastResortWatchdog().clearAllFailureCounts(); + setSupplicantLogLevel(); + + // 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(); + mCountryCode.setReadyForChange(true); + + mWifiDiagnostics.startLogging(mVerboseLoggingEnabled); + mIsRunning = true; + updateBatteryWorkSource(null); + + /** + * Enable bluetooth coexistence scan mode when bluetooth connection is active. + * When this mode is on, some of the low-level scan parameters used by the + * driver are changed to reduce interference with bluetooth + */ + mWifiNative.setBluetoothCoexistenceScanMode(mInterfaceName, mBluetoothConnectionActive); + // Check if there is a voice call on-going and set/reset the tx power limit appropriately. + if (mEnableVoiceCallSarTxPowerLimit) { + if (getTelephonyManager().isOffhook()) { + sendMessage(CMD_SELECT_TX_POWER_SCENARIO, WifiNative.TX_POWER_SCENARIO_VOICE_CALL); + } else { + sendMessage(CMD_SELECT_TX_POWER_SCENARIO, WifiNative.TX_POWER_SCENARIO_NORMAL); + } + } + + // initialize network state + setNetworkDetailedState(DetailedState.DISCONNECTED); + + // Disable legacy multicast filtering, which on some chipsets defaults to enabled. + // Legacy IPv6 multicast filtering blocks ICMPv6 router advertisements which breaks IPv6 + // provisioning. Legacy IPv4 multicast filtering may be re-enabled later via + // IpClient.Callback.setFallbackMulticastFilter() + mWifiNative.stopFilteringMulticastV4Packets(mInterfaceName); + mWifiNative.stopFilteringMulticastV6Packets(mInterfaceName); + + // Set the right suspend mode settings + mWifiNative.setSuspendOptimizations(mInterfaceName, mSuspendOptNeedsDisabled == 0 + && mUserWantsSuspendOpt.get()); + + mWifiNative.setPowerSave(mInterfaceName, true); + + if (mP2pSupported) { + p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P); + } + + // Disable wpa_supplicant from auto reconnecting. + mWifiNative.enableStaAutoReconnect(mInterfaceName, false); + // STA has higher priority over P2P + mWifiNative.setConcurrencyPriority(true); + } + + /** + * Helper method to stop external services and clean up state from client mode. + */ + private void stopClientMode() { + // exiting supplicant started state is now only applicable to client mode + mWifiDiagnostics.stopLogging(); + + if (mP2pSupported) { + // we are not going to wait for a response - will still temporarily send the + // disable command until p2p can detect the interface up/down on its own. + p2pSendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); + } + + mIsRunning = false; + updateBatteryWorkSource(null); + + mNetworkInfo.setIsAvailable(false); + if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); + mCountryCode.setReadyForChange(false); + setWifiState(WIFI_STATE_DISABLED); + } + void registerConnected() { if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { mWifiConfigManager.updateNetworkAfterConnect(mLastNetworkId); @@ -4201,13 +3861,13 @@ public class WifiStateMachine extends StateMachine { @Override public void enter() { + setupClientMode(); if (!mWifiNative.removeAllNetworks(mInterfaceName)) { loge("Failed to remove networks on entering connect mode"); } mScanRequestProxy.enableScanningForHiddenNetworks(true); mWifiInfo.reset(); mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED); - sendWifiScanAvailable(true); // Let the system know that wifi is available in client mode. setWifiState(WIFI_STATE_ENABLED); @@ -4247,6 +3907,7 @@ public class WifiStateMachine extends StateMachine { mWifiInfo.reset(); mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED); setWifiState(WIFI_STATE_DISABLED); + stopClientMode(); } @Override @@ -4264,6 +3925,12 @@ public class WifiStateMachine extends StateMachine { logStateAndMessage(message, this); switch (message.what) { + case CMD_SET_OPERATIONAL_MODE: + if (message.arg1 == CONNECT_MODE) { + break; + } else { + return NOT_HANDLED; + } case WifiMonitor.ASSOCIATION_REJECTION_EVENT: mWifiDiagnostics.captureBugReportData( WifiDiagnostics.REPORT_REASON_ASSOC_FAILURE); @@ -4355,18 +4022,6 @@ public class WifiStateMachine extends StateMachine { mIpClient.confirmConfiguration(); mWifiScoreReport.noteIpCheck(); } - - 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) { @@ -4791,6 +4446,86 @@ public class WifiStateMachine extends StateMachine { replyToMessage(message, message.what, mPasspointManager.getAllMatchingWifiConfigs((ScanResult) message.obj)); break; + case CMD_TARGET_BSSID: + // Trying to associate to this BSSID + if (message.obj != null) { + mTargetRoamBSSID = (String) message.obj; + } + break; + case CMD_GET_LINK_LAYER_STATS: + WifiLinkLayerStats stats = getWifiLinkLayerStats(); + replyToMessage(message, message.what, stats); + break; + case CMD_RESET_SIM_NETWORKS: + log("resetting EAP-SIM/AKA/AKA' networks since SIM was changed"); + mWifiConfigManager.resetSimNetworks(message.arg1 == 1); + break; + case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: + mBluetoothConnectionActive = (message.arg1 + != BluetoothAdapter.STATE_DISCONNECTED); + mWifiNative.setBluetoothCoexistenceScanMode( + mInterfaceName, mBluetoothConnectionActive); + break; + case CMD_SET_SUSPEND_OPT_ENABLED: + if (message.arg1 == 1) { + setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); + if (message.arg2 == 1) { + mSuspendWakeLock.release(); + } + } else { + setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); + } + break; + case CMD_SET_HIGH_PERF_MODE: + if (message.arg1 == 1) { + setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); + } else { + setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); + } + break; + case CMD_ENABLE_TDLS: + if (message.obj != null) { + String remoteAddress = (String) message.obj; + boolean enable = (message.arg1 == 1); + mWifiNative.startTdls(mInterfaceName, remoteAddress, enable); + } + break; + case WifiMonitor.ANQP_DONE_EVENT: + // TODO(zqiu): remove this when switch over to wificond for ANQP requests. + mPasspointManager.notifyANQPDone((AnqpEvent) message.obj); + break; + case CMD_STOP_IP_PACKET_OFFLOAD: { + int slot = message.arg1; + int ret = stopWifiIPPacketOffload(slot); + if (mNetworkAgent != null) { + mNetworkAgent.onPacketKeepaliveEvent(slot, ret); + } + break; + } + case WifiMonitor.RX_HS20_ANQP_ICON_EVENT: + // TODO(zqiu): remove this when switch over to wificond for icon requests. + mPasspointManager.notifyIconDone((IconEvent) message.obj); + break; + case WifiMonitor.HS20_REMEDIATION_EVENT: + // TODO(zqiu): remove this when switch over to wificond for WNM frames + // monitoring. + mPasspointManager.receivedWnmFrame((WnmData) message.obj); + break; + case CMD_CONFIG_ND_OFFLOAD: + final boolean enabled = (message.arg1 > 0); + mWifiNative.configureNeighborDiscoveryOffload(mInterfaceName, enabled); + break; + case CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER: + mWifiConnectivityManager.enable(message.arg1 == 1 ? true : false); + break; + case CMD_SELECT_TX_POWER_SCENARIO: + int txPowerScenario = message.arg1; + logd("Setting Tx power scenario to " + txPowerScenario); + if (!mWifiNative.selectTxPowerScenario(txPowerScenario)) { + loge("Failed to set TX power scenario"); + } + break; + default: return NOT_HANDLED; } @@ -5900,115 +5635,6 @@ public class WifiStateMachine extends StateMachine { } } - class SoftApState extends State { - private SoftApManager mSoftApManager; - private String mIfaceName; - private int mMode; - - /* - private class SoftApCallbackImpl implements WifiManager.SoftApCallback { - @Override - public void onStateChanged(int state, int reason) { - if (state == WIFI_AP_STATE_DISABLED) { - sendMessage(CMD_AP_STOPPED); - } else if (state == WIFI_AP_STATE_FAILED) { - sendMessage(CMD_START_AP_FAILURE); - } - - setWifiApState(state, reason, mIfaceName, mMode); - - if (mSoftApCallback != null) { - mSoftApCallback.onStateChanged(state, reason); - } - } - - @Override - public void onNumClientsChanged(int numClients) { - if (mSoftApCallback != null) { - mSoftApCallback.onNumClientsChanged(numClients); - } - } - } - */ - - @Override - public void enter() { - final Message message = getCurrentMessage(); - if (message.what != CMD_START_AP) { - throw new RuntimeException("Illegal transition to SoftApState: " + message); - } - /* - SoftApModeConfiguration config = (SoftApModeConfiguration) message.obj; - mMode = config.getTargetMode(); - - IApInterface apInterface = null; - Pair<Integer, IApInterface> statusAndInterface = - mWifiNative.setupForSoftApMode(mInterfaceName); - if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) { - apInterface = statusAndInterface.second; - } else { - incrementMetricsForSetupFailure(statusAndInterface.first); - } - if (apInterface == null) { - setWifiApState(WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL, null, mMode); - // Transition to InitialState to reset the driver/HAL back to the initial state. - transitionTo(mInitialState); - return; - } - - try { - mIfaceName = apInterface.getInterfaceName(); - } catch (RemoteException e) { - // Failed to get the interface name. This is not a good sign and we should report - // a failure and switch back to the initial state to reset the driver and HAL. - setWifiApState(WIFI_AP_STATE_FAILED, - WifiManager.SAP_START_FAILURE_GENERAL, null, mMode); - transitionTo(mInitialState); - return; - } - - checkAndSetConnectivityInstance(); - mSoftApManager = mWifiInjector.makeSoftApManager(mNwService, - new SoftApCallbackImpl(), - config); - mSoftApManager.start(); - mWifiStateTracker.updateState(WifiStateTracker.SOFT_AP); - */ - } - - @Override - public void exit() { - mSoftApManager = null; - mIfaceName = null; - mMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED; - } - - @Override - public boolean processMessage(Message message) { - logStateAndMessage(message, this); - - switch(message.what) { - case CMD_START_AP: - /* Ignore start command when it is starting/started. */ - break; - case CMD_STOP_AP: - //mSoftApManager.stop(); - transitionTo(mDefaultState); - break; - case CMD_START_AP_FAILURE: - transitionTo(mDefaultState); - break; - case CMD_AP_STOPPED: - transitionTo(mDefaultState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - /** * State machine initiated requests can have replyTo set to null indicating * there are no recepients, we ignore those reply actions. diff --git a/service/java/com/android/server/wifi/WifiStateMachinePrime.java b/service/java/com/android/server/wifi/WifiStateMachinePrime.java index 8eb521cbb..fea191614 100644 --- a/service/java/com/android/server/wifi/WifiStateMachinePrime.java +++ b/service/java/com/android/server/wifi/WifiStateMachinePrime.java @@ -17,8 +17,11 @@ package com.android.server.wifi; import android.annotation.NonNull; +import android.content.Context; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; +import android.os.BatteryStats; +import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; @@ -29,9 +32,7 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; - -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; +import com.android.server.wifi.WifiNative.StatusListener; /** * This class provides the implementation for different WiFi operating modes. @@ -50,11 +51,13 @@ public class WifiStateMachinePrime { private DefaultModeManager mDefaultModeManager; private final WifiInjector mWifiInjector; + private final Context mContext; private final Looper mLooper; + private final Handler mHandler; private final WifiNative mWifiNative; private final IBatteryStats mBatteryStats; - - private Queue<SoftApModeConfiguration> mApConfigQueue = new ConcurrentLinkedQueue<>(); + private final SelfRecovery mSelfRecovery; + private BaseWifiDiagnostics mWifiDiagnostics; // The base for wifi message types static final int BASE = Protocol.BASE_WIFI; @@ -91,27 +94,52 @@ public class WifiStateMachinePrime { // Client mode failed static final int CMD_CLIENT_MODE_FAILED = BASE + 304; + private StatusListener mWifiNativeStatusListener; + private WifiManager.SoftApCallback mSoftApCallback; + private ScanOnlyModeManager.Listener mScanOnlyCallback; + private ClientModeManager.Listener mClientModeCallback; /** * Called from WifiServiceImpl to register a callback for notifications from SoftApManager */ - public void registerSoftApCallback(WifiManager.SoftApCallback callback) { + public void registerSoftApCallback(@NonNull WifiManager.SoftApCallback callback) { mSoftApCallback = callback; } + /** + * Called from WifiController to register a callback for notifications from ScanOnlyModeManager + */ + public void registerScanOnlyCallback(@NonNull ScanOnlyModeManager.Listener callback) { + mScanOnlyCallback = callback; + } + + /** + * Called from WifiController to register a callback for notifications from ClientModeManager + */ + public void registerClientModeCallback(@NonNull ClientModeManager.Listener callback) { + mClientModeCallback = callback; + } + WifiStateMachinePrime(WifiInjector wifiInjector, + Context context, Looper looper, WifiNative wifiNative, DefaultModeManager defaultModeManager, IBatteryStats batteryStats) { mWifiInjector = wifiInjector; + mContext = context; mLooper = looper; + mHandler = new Handler(looper); mWifiNative = wifiNative; mActiveModeManagers = new ArraySet(); mDefaultModeManager = defaultModeManager; mBatteryStats = batteryStats; + mSelfRecovery = mWifiInjector.getSelfRecovery(); + mWifiDiagnostics = mWifiInjector.makeWifiDiagnostics(mWifiNative); mModeStateMachine = new ModeStateMachine(); + mWifiNativeStatusListener = new WifiNativeStatusListener(); + mWifiNative.registerStatusListener(mWifiNativeStatusListener); } /** @@ -143,19 +171,50 @@ public class WifiStateMachinePrime { * @param wifiConfig SoftApModeConfiguration for the hostapd softap */ public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) { - mApConfigQueue.offer(wifiConfig); - changeMode(ModeStateMachine.CMD_START_SOFT_AP_MODE); + mHandler.post(() -> { + startSoftAp(wifiConfig); + }); } /** - * Method to fully disable wifi. + * Method to stop soft ap for wifi hotspot. * - * This mode will completely shut down wifi and will not perform any network scans. + * This method will stop any active softAp mode managers, if there is one. + */ + public void stopSoftAPMode() { + mHandler.post(() -> { + for (ActiveModeManager manager : mActiveModeManagers) { + if (manager instanceof SoftApManager) { + Log.d(TAG, "Stopping SoftApModeManager"); + manager.stop(); + mActiveModeManagers.remove(manager); + } + } + updateBatteryStatsWifiState(false); + }); + } + + /** + * Method to disable wifi in sta/client mode scenarios. + * + * This mode will stop any client/scan modes and will not perform any network scans. */ public void disableWifi() { changeMode(ModeStateMachine.CMD_DISABLE_WIFI); } + /** + * Method to stop all active modes, for example, when toggling airplane mode. + */ + public void shutdownWifi() { + mHandler.post(() -> { + for (ActiveModeManager manager : mActiveModeManagers) { + manager.stop(); + } + updateBatteryStatsWifiState(false); + }); + } + protected String getCurrentMode() { return mModeStateMachine.getCurrentMode(); } @@ -164,27 +223,38 @@ public class WifiStateMachinePrime { mModeStateMachine.sendMessage(newMode); } + /** + * Helper class to wrap the ActiveModeManager callback objects. + */ + private class ModeCallback { + ActiveModeManager mActiveManager; + + void setActiveModeManager(ActiveModeManager manager) { + mActiveManager = manager; + } + + ActiveModeManager getActiveModeManager() { + return mActiveManager; + } + } + private class ModeStateMachine extends StateMachine { - // Commands for the state machine. + // Commands for the state machine - these will be removed, + // along with the StateMachine itself public static final int CMD_START_CLIENT_MODE = 0; public static final int CMD_START_SCAN_ONLY_MODE = 1; - public static final int CMD_START_SOFT_AP_MODE = 2; public static final int CMD_DISABLE_WIFI = 3; private final State mWifiDisabledState = new WifiDisabledState(); private final State mClientModeActiveState = new ClientModeActiveState(); private final State mScanOnlyModeActiveState = new ScanOnlyModeActiveState(); - private final State mSoftAPModeActiveState = new SoftAPModeActiveState(); ModeStateMachine() { super(TAG, mLooper); - // CHECKSTYLE:OFF IndentationCheck addState(mClientModeActiveState); addState(mScanOnlyModeActiveState); - addState(mSoftAPModeActiveState); addState(mWifiDisabledState); - // CHECKSTYLE:ON IndentationCheck Log.d(TAG, "Starting Wifi in WifiDisabledState"); setInitialState(mWifiDisabledState); @@ -205,10 +275,6 @@ public class WifiStateMachinePrime { Log.d(TAG, "Switching from " + getCurrentMode() + " to ScanOnlyMode"); mModeStateMachine.transitionTo(mScanOnlyModeActiveState); break; - case ModeStateMachine.CMD_START_SOFT_AP_MODE: - Log.d(TAG, "Switching from " + getCurrentMode() + " to SoftApMode"); - mModeStateMachine.transitionTo(mSoftAPModeActiveState); - break; case ModeStateMachine.CMD_DISABLE_WIFI: Log.d(TAG, "Switching from " + getCurrentMode() + " to WifiDisabled"); mModeStateMachine.transitionTo(mWifiDisabledState); @@ -219,11 +285,6 @@ public class WifiStateMachinePrime { return HANDLED; } - private void cleanup() { - // TODO: Remove this big hammer. We cannot support concurrent interfaces with this! - mWifiNative.teardownAllInterfaces(); - } - class ModeActiveState extends State { ActiveModeManager mManager; @Override @@ -249,8 +310,7 @@ public class WifiStateMachinePrime { @Override public void enter() { Log.d(TAG, "Entering WifiDisabledState"); - // make sure everything is torn down - remove when client mode is moved here - cleanup(); + mDefaultModeManager.sendScanAvailableBroadcast(mContext, false); } @Override @@ -294,23 +354,13 @@ public class WifiStateMachinePrime { Log.d(TAG, "Entering ClientModeActiveState"); mManager = mWifiInjector.makeClientModeManager(new ClientListener()); - // DO NOT CALL START YET - // mActiveModemanager.start(); + mManager.start(); mActiveModeManagers.add(mManager); updateBatteryStatsWifiState(true); } @Override - public void exit() { - Log.d(TAG, "Exiting ClientModeActiveState"); - - // OVERRIDE exit() SO WE DO NOT CALL STOP (but we do need to report wifi off) - - updateBatteryStatsWifiState(false); - } - - @Override public boolean processMessage(Message message) { if (checkForAndHandleModeChange(message)) { return HANDLED; @@ -323,11 +373,12 @@ public class WifiStateMachinePrime { private class ScanOnlyListener implements ScanOnlyModeManager.Listener { @Override public void onStateChanged(int state) { - Log.d(TAG, "State changed from scan only mode."); if (state == WifiManager.WIFI_STATE_UNKNOWN) { + Log.d(TAG, "ScanOnlyMode mode failed"); // error while setting up scan mode or an unexpected failure. mModeStateMachine.sendMessage(CMD_SCAN_ONLY_MODE_FAILED); } else if (state == WifiManager.WIFI_STATE_DISABLED) { + Log.d(TAG, "ScanOnlyMode stopped"); //scan only mode stopped mModeStateMachine.sendMessage(CMD_SCAN_ONLY_MODE_STOPPED); } else if (state == WifiManager.WIFI_STATE_ENABLED) { @@ -343,13 +394,12 @@ public class WifiStateMachinePrime { public void enter() { Log.d(TAG, "Entering ScanOnlyModeActiveState"); - // make sure everything is torn down - remove when client mode is moved here - cleanup(); - mManager = mWifiInjector.makeScanOnlyModeManager(new ScanOnlyListener()); mManager.start(); mActiveModeManagers.add(mManager); + updateBatteryStatsWifiState(true); + updateBatteryStatsScanModeActive(); } @Override @@ -364,10 +414,14 @@ public class WifiStateMachinePrime { break; case CMD_SCAN_ONLY_MODE_FAILED: Log.d(TAG, "ScanOnlyMode failed, return to WifiDisabledState."); + // notify WifiController that ScanOnlyMode failed + mScanOnlyCallback.onStateChanged(WifiManager.WIFI_STATE_UNKNOWN); mModeStateMachine.transitionTo(mWifiDisabledState); break; case CMD_SCAN_ONLY_MODE_STOPPED: Log.d(TAG, "ScanOnlyMode stopped, return to WifiDisabledState."); + // notify WifiController that ScanOnlyMode stopped + mScanOnlyCallback.onStateChanged(WifiManager.WIFI_STATE_DISABLED); mModeStateMachine.transitionTo(mWifiDisabledState); break; default: @@ -376,101 +430,100 @@ public class WifiStateMachinePrime { return HANDLED; } } + } // class ModeStateMachine - class SoftAPModeActiveState extends ModeActiveState { - private class SoftApCallbackImpl implements WifiManager.SoftApCallback { - @Override - public void onStateChanged(int state, int reason) { - if (state == WifiManager.WIFI_AP_STATE_DISABLED) { - mModeStateMachine.sendMessage(CMD_AP_STOPPED); - } else if (state == WifiManager.WIFI_AP_STATE_FAILED) { - mModeStateMachine.sendMessage(CMD_START_AP_FAILURE); - } - - if (mSoftApCallback != null) { - mSoftApCallback.onStateChanged(state, reason); - } else { - Log.wtf(TAG, "SoftApCallback is null. Dropping StateChanged event."); - } - } + private class SoftApCallbackImpl extends ModeCallback implements WifiManager.SoftApCallback { + @Override + public void onStateChanged(int state, int reason) { + if (state == WifiManager.WIFI_AP_STATE_DISABLED) { + mActiveModeManagers.remove(getActiveModeManager()); + updateBatteryStatsWifiState(false); + } else if (state == WifiManager.WIFI_AP_STATE_FAILED) { + mActiveModeManagers.remove(getActiveModeManager()); + updateBatteryStatsWifiState(false); + } - @Override - public void onNumClientsChanged(int numClients) { - if (mSoftApCallback != null) { - mSoftApCallback.onNumClientsChanged(numClients); - } else { - Log.d(TAG, "SoftApCallback is null. Dropping NumClientsChanged event."); - } - } + if (mSoftApCallback != null) { + mSoftApCallback.onStateChanged(state, reason); } + } - @Override - public void enter() { - Log.d(TAG, "Entering SoftApModeActiveState"); - - // make sure everything is torn down - remove when client mode is moved here - cleanup(); - - SoftApModeConfiguration softApModeConfig = mApConfigQueue.poll(); - WifiConfiguration config = softApModeConfig.getWifiConfiguration(); - // TODO (b/67601382): add checks for valid softap configs - if (config != null && config.SSID != null) { - Log.d(TAG, "Passing config to SoftApManager! " + config); - } else { - config = null; - } - mManager = mWifiInjector.makeSoftApManager( - new SoftApCallbackImpl(), softApModeConfig); - mManager.start(); - mActiveModeManagers.add(mManager); - updateBatteryStatsWifiState(true); + @Override + public void onNumClientsChanged(int numClients) { + if (mSoftApCallback != null) { + mSoftApCallback.onNumClientsChanged(numClients); + } else { + Log.d(TAG, "SoftApCallback is null. Dropping NumClientsChanged event."); } + } + } - @Override - public boolean processMessage(Message message) { - if (checkForAndHandleModeChange(message)) { - return HANDLED; - } + private void startSoftAp(SoftApModeConfiguration softapConfig) { + Log.d(TAG, "Starting SoftApModeManager"); - switch(message.what) { - case CMD_START_AP: - Log.d(TAG, "Received CMD_START_AP when active - invalid message - drop"); - break; - case CMD_STOP_AP: - mManager.stop(); - break; - case CMD_START_AP_FAILURE: - Log.d(TAG, "Failed to start SoftApMode. Return to WifiDisabledState."); - mModeStateMachine.transitionTo(mWifiDisabledState); - break; - case CMD_AP_STOPPED: - Log.d(TAG, "SoftApModeActiveState stopped. Return to WifiDisabledState."); - mModeStateMachine.transitionTo(mWifiDisabledState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } + WifiConfiguration config = softapConfig.getWifiConfiguration(); + // TODO (b/67601382): add checks for valid softap configs + if (config != null && config.SSID != null) { + Log.d(TAG, "Passing config to SoftApManager! " + config); + } else { + config = null; } - } // class ModeStateMachine + SoftApCallbackImpl callback = new SoftApCallbackImpl(); + ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig); + callback.setActiveModeManager(manager); + manager.start(); + mActiveModeManagers.add(manager); + updateBatteryStatsWifiState(true); + } /** * Helper method to report wifi state as on/off (doesn't matter which mode). * - * @param enabled boolean indicating if wifi is on or off + * @param enabled boolean indicating that some mode has been turned on or off */ private void updateBatteryStatsWifiState(boolean enabled) { try { if (enabled) { - mBatteryStats.noteWifiOn(); + if (mActiveModeManagers.size() == 1) { + // only report wifi on if we haven't already + mBatteryStats.noteWifiOn(); + } } else { - mBatteryStats.noteWifiOff(); + if (mActiveModeManagers.size() == 0) { + // only report if we don't have any active modes + mBatteryStats.noteWifiOff(); + } } } catch (RemoteException e) { Log.e(TAG, "Failed to note battery stats in wifi"); } } + private void updateBatteryStatsScanModeActive() { + try { + mBatteryStats.noteWifiState(BatteryStats.WIFI_STATE_OFF_SCANNING, null); + } catch (RemoteException e) { + Log.e(TAG, "Failed to note battery stats in wifi"); + } + } + + // callback used to receive callbacks about underlying native failures + private final class WifiNativeStatusListener implements StatusListener { + + @Override + public void onStatusChanged(boolean isReady) { + if (!isReady) { + mHandler.post(() -> { + Log.e(TAG, "One of the native daemons died. Triggering recovery"); + mWifiDiagnostics.captureBugReportData( + WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE); + + // immediately trigger SelfRecovery if we receive a notice about an + // underlying daemon failure + mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE); + }); + } + } + }; } |