diff options
author | Rebecca Silberstein <silberst@google.com> | 2016-11-21 19:22:06 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-11-21 19:22:06 +0000 |
commit | 9dee6afa78e114fb6405746d3f40502a34978002 (patch) | |
tree | d3bbaaf8ef8675d8074beca2f299cac0e74fe12e /service | |
parent | 44a2888f8d4d213c013c9976fb4df1c9b9a99ff6 (diff) | |
parent | bfc30bd4c2ff0c62d6cfff22088a935878966a46 (diff) |
WifiStateMachinePrime: Implement SoftApMode path
am: bfc30bd4c2
Change-Id: I6ec7a1f7270387ba2faeee033b4464ba7169f757
Diffstat (limited to 'service')
-rw-r--r-- | service/java/com/android/server/wifi/WifiStateMachinePrime.java | 296 |
1 files changed, 278 insertions, 18 deletions
diff --git a/service/java/com/android/server/wifi/WifiStateMachinePrime.java b/service/java/com/android/server/wifi/WifiStateMachinePrime.java index 33cccbb88..dbb826293 100644 --- a/service/java/com/android/server/wifi/WifiStateMachinePrime.java +++ b/service/java/com/android/server/wifi/WifiStateMachinePrime.java @@ -16,8 +16,17 @@ package com.android.server.wifi; +import android.net.wifi.IApInterface; +import android.net.wifi.IWificond; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.os.INetworkManagementService; +import android.os.Looper; import android.os.Message; +import android.os.RemoteException; +import android.util.Log; +import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -32,8 +41,99 @@ public class WifiStateMachinePrime { private ModeStateMachine mModeStateMachine; - WifiStateMachinePrime() { - mModeStateMachine = new ModeStateMachine(TAG); + private final WifiInjector mWifiInjector; + private final Looper mLooper; + private final INetworkManagementService mNMService; + + private IWificond mWificond; + + /* The base for wifi message types */ + static final int BASE = Protocol.BASE_WIFI; + + /* 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; + + WifiStateMachinePrime(WifiInjector wifiInjector, + Looper looper, + INetworkManagementService nmService) { + mWifiInjector = wifiInjector; + mLooper = looper; + mNMService = nmService; + + // Clean up existing interfaces in wificond. + // This ensures that the framework and wificond are in a consistent state after a framework + // restart. + try { + mWificond = mWifiInjector.makeWificond(); + if (mWificond != null) { + mWificond.tearDownInterfaces(); + } + } catch (RemoteException e) { + Log.e(TAG, "wificond died during framework startup"); + } + } + + /** + * Method to switch wifi into client mode where connections to configured networks will be + * attempted. + */ + public void enterClientMode() { + changeMode(ModeStateMachine.CMD_START_CLIENT_MODE); + } + + /** + * Method to switch wifi into scan only mode where network connection attempts will not be made. + * + * This mode is utilized by location scans. If wifi is disabled by a user, but they have + * previously configured their device to perform location scans, this mode allows wifi to + * fulfill the location scan requests but will not be used for connectivity. + */ + public void enterScanOnlyMode() { + changeMode(ModeStateMachine.CMD_START_SCAN_ONLY_MODE); + } + + /** + * Method to enable soft ap for wifi hotspot. + */ + public void enterSoftAPMode() { + changeMode(ModeStateMachine.CMD_START_SOFT_AP_MODE); + } + + /** + * Method to fully disable wifi. + * + * This mode will completely shut down wifi and will not perform any network scans. + */ + public void disableWifi() { + changeMode(ModeStateMachine.CMD_DISABLE_WIFI); + } + + protected String getCurrentMode() { + if (mModeStateMachine != null) { + return mModeStateMachine.getCurrentMode(); + } + return "WifiDisabledState"; + } + + private void changeMode(int newMode) { + if (mModeStateMachine == null) { + if (newMode == ModeStateMachine.CMD_DISABLE_WIFI) { + // command is to disable wifi, but it is already disabled. + Log.e(TAG, "Received call to disable wifi when it is already disabled."); + return; + } + // state machine was not initialized yet, we must be starting up + mModeStateMachine = new ModeStateMachine(newMode); + } else { + // we have a current state, go ahead and prep for the new state + mModeStateMachine.sendMessage(newMode); + } } private class ModeStateMachine extends StateMachine { @@ -43,7 +143,6 @@ public class WifiStateMachinePrime { public static final int CMD_START_SOFT_AP_MODE = 2; public static final int CMD_DISABLE_WIFI = 3; - // Create the base modes for WSM. private final State mClientModeState = new ClientModeState(); private final State mScanOnlyModeState = new ScanOnlyModeState(); @@ -55,8 +154,8 @@ public class WifiStateMachinePrime { private final State mScanOnlyModeActiveState = new ScanOnlyModeActiveState(); private final State mSoftAPModeActiveState = new SoftAPModeActiveState(); - ModeStateMachine(String name) { - super(name); + ModeStateMachine(int initialMode) { + super(TAG, mLooper); // CHECKSTYLE:OFF IndentationCheck addState(mClientModeState); @@ -67,54 +166,168 @@ public class WifiStateMachinePrime { addState(mSoftAPModeActiveState, mSoftAPModeState); addState(mWifiDisabledState); // CHECKSTYLE:ON IndentationCheck + + State startingState; + switch(initialMode) { + case CMD_START_CLIENT_MODE: + startingState = mClientModeState; + break; + case CMD_START_SCAN_ONLY_MODE: + startingState = mScanOnlyModeState; + break; + case CMD_START_SOFT_AP_MODE: + startingState = mSoftAPModeState; + break; + default: + Log.e(TAG, "Attempting to start WifiStateMachinePrime " + + "in an invalid operating mode: " + initialMode); + throw new IllegalArgumentException("Invalid wifi operating mode"); + } + Log.d(TAG, "Switching from WifiDisabled to " + startingState.getName()); + setInitialState(startingState); + start(); } private String getCurrentMode() { - try { - return getCurrentState().getName(); - } catch (NullPointerException e) { - // current state is not set - return null; + return getCurrentState().getName(); + } + + private boolean checkForAndHandleModeChange(Message message) { + switch(message.what) { + case ModeStateMachine.CMD_START_CLIENT_MODE: + Log.d(TAG, "Switching from " + getCurrentMode() + " to ClientMode"); + mModeStateMachine.transitionTo(mClientModeState); + break; + case ModeStateMachine.CMD_START_SCAN_ONLY_MODE: + Log.d(TAG, "Switching from " + getCurrentMode() + " to ScanOnlyMode"); + mModeStateMachine.transitionTo(mScanOnlyModeState); + break; + case ModeStateMachine.CMD_START_SOFT_AP_MODE: + Log.d(TAG, "Switching from " + getCurrentMode() + " to SoftApMode"); + mModeStateMachine.transitionTo(mSoftAPModeState); + break; + case ModeStateMachine.CMD_DISABLE_WIFI: + Log.d(TAG, "Switching from " + getCurrentMode() + " to WifiDisabled"); + mModeStateMachine.transitionTo(mWifiDisabledState); + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + + private void tearDownInterfaces() { + if (mWificond != null) { + try { + mWificond.tearDownInterfaces(); + } catch (RemoteException e) { + // There is very little we can do here + Log.e(TAG, "Failed to tear down interfaces via wificond"); + } + mWificond = null; } + return; } class ClientModeState extends State { + @Override + public void enter() { + mWificond = mWifiInjector.makeWificond(); + } @Override public boolean processMessage(Message message) { + if (checkForAndHandleModeChange(message)) { + return HANDLED; + } return NOT_HANDLED; } @Override public void exit() { - + tearDownInterfaces(); } } class ScanOnlyModeState extends State { + @Override + public void enter() { + } @Override public boolean processMessage(Message message) { - // handle Mode changes and any events requiring setup or restarting services - + if (checkForAndHandleModeChange(message)) { + return HANDLED; + } return NOT_HANDLED; } @Override public void exit() { - // tear down running services + // Do not tear down interfaces yet since this mode is not actively controlled or + // used in tests at this time. + // tearDownInterfaces(); } } class SoftAPModeState extends State { + IApInterface mApInterface = null; + + @Override + public void enter() { + mApInterface = null; + mWificond = mWifiInjector.makeWificond(); + if (mWificond == null) { + Log.e(TAG, "Failed to get reference to wificond"); + mModeStateMachine.sendMessage(CMD_START_AP_FAILURE); + return; + } + + try { + mApInterface = mWificond.createApInterface(); + } catch (RemoteException e1) { } + + if (mApInterface == null) { + Log.e(TAG, "Could not get IApInterface instance from wificond"); + mModeStateMachine.sendMessage(CMD_START_AP_FAILURE); + return; + } + mModeStateMachine.sendMessage(CMD_START_AP); + } @Override public boolean processMessage(Message message) { - return NOT_HANDLED; + if (checkForAndHandleModeChange(message)) { + return HANDLED; + } + + switch(message.what) { + case CMD_START_AP: + Log.d(TAG, "Transitioning to softapmodeactivestate"); + mModeStateMachine.transitionTo(mSoftAPModeActiveState); + break; + case CMD_STOP_AP: + // not in active state, nothing to stop. + break; + case CMD_START_AP_FAILURE: + Log.e(TAG, "Failed to start SoftApMode. Wait for next mode command."); + break; + case CMD_AP_STOPPED: + Log.d(TAG, "SoftApModeActiveState stopped. Wait for next mode command."); + break; + default: + return NOT_HANDLED; + } + return HANDLED; } @Override public void exit() { + tearDownInterfaces(); + } + + protected IApInterface getInterface() { + return mApInterface; } } @@ -163,11 +376,58 @@ public class WifiStateMachinePrime { } class SoftAPModeActiveState extends ModeActiveState { + private class SoftApListener implements SoftApManager.Listener { + @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); + } + } + } + @Override public void enter() { - // The SoftApManager is not empty at this time, will populate in later CLs. - //this.mActiveModeManager = new SoftApManager(); + Log.d(TAG, "Entering SoftApModeActiveState"); + final Message message = mModeStateMachine.getCurrentMessage(); + if (message.what != CMD_START_AP) { + throw new RuntimeException("Illegal transition to SoftApState: " + message); + } + // The WifiConfiguration is generally going to be null to indicate that the + // currently saved config in WifiApConfigManager should be used. When the config is + // not null, it will be saved in the WifiApConfigManager. This save is performed in + // the constructor of SoftApManager. + WifiConfiguration config = (WifiConfiguration) message.obj; + this.mActiveModeManager = mWifiInjector.makeSoftApManager(mNMService, + new SoftApListener(), ((SoftAPModeState) mSoftAPModeState).getInterface(), + config); + mActiveModeManager.start(); + } + + @Override + public boolean processMessage(Message message) { + switch(message.what) { + case CMD_START_AP: + Log.d(TAG, "Received CMD_START_AP with SoftApMode already active. drop"); + break; + case CMD_STOP_AP: + mActiveModeManager.stop(); + break; + case CMD_START_AP_FAILURE: + Log.d(TAG, "Failed to start SoftApMode. Return to SoftApMode (inactive)."); + mModeStateMachine.transitionTo(mSoftAPModeState); + break; + case CMD_AP_STOPPED: + Log.d(TAG, "SoftApModeActiveState stopped." + + " Return to SoftApMode (inactive)."); + mModeStateMachine.transitionTo(mSoftAPModeState); + break; + default: + return NOT_HANDLED; + } + return HANDLED; } } - } // class ModeStateMachine + } // class ModeStateMachine } |