diff options
| -rw-r--r-- | wifi/java/android/net/wifi/WifiStateMachine.java | 206 |
1 files changed, 191 insertions, 15 deletions
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index aadcaadaa663..3ed9bd5ccbbf 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -123,6 +123,8 @@ public class WifiStateMachine extends StateMachine { private final LruCache<String, ScanResult> mScanResultCache; private String mInterfaceName; + /* Tethering interface could be seperate from wlan interface */ + private String mTetherInterfaceName; private int mLastSignalLevel = -1; private String mLastBssid; @@ -156,6 +158,14 @@ public class WifiStateMachine extends StateMachine { /* Tracks sequence number on stop failure message */ private int mSupplicantStopFailureToken = 0; + /** + * Tether state change notification time out + */ + private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; + + /* Tracks sequence number on a tether notification time out */ + private int mTetherToken = 0; + private LinkProperties mLinkProperties; // Wakelock held during wifi start/stop and driver load/unload @@ -240,10 +250,12 @@ public class WifiStateMachine extends StateMachine { static final int CMD_REQUEST_AP_CONFIG = BASE + 27; /* Response to access point configuration request */ static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; - /* Set configuration on tether interface */ - static final int CMD_TETHER_INTERFACE = BASE + 29; + /* Invoked when getting a tether state change notification */ + static final int CMD_TETHER_STATE_CHANGE = BASE + 29; + /* A delayed message sent to indicate tether state change failed to arrive */ + static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; - static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 30; + static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; /* Supplicant commands */ /* Is supplicant alive ? */ @@ -455,12 +467,25 @@ public class WifiStateMachine extends StateMachine { private State mSoftApStartingState = new SoftApStartingState(); /* Soft ap is running */ private State mSoftApStartedState = new SoftApStartedState(); + /* Soft ap is running and we are waiting for tether notification */ + private State mTetheringState = new TetheringState(); /* Soft ap is running and we are tethered through connectivity service */ private State mTetheredState = new TetheredState(); + /* Waiting for untether confirmation to stop soft Ap */ + private State mSoftApStoppingState = new SoftApStoppingState(); /* Wait till p2p is disabled */ private State mWaitForP2pDisableState = new WaitForP2pDisableState(); + private class TetherStateChange { + ArrayList<String> available; + ArrayList<String> active; + TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { + available = av; + active = ac; + } + } + /** * One of {@link WifiManager#WIFI_STATE_DISABLED}, @@ -562,7 +587,9 @@ public class WifiStateMachine extends StateMachine { public void onReceive(Context context, Intent intent) { ArrayList<String> available = intent.getStringArrayListExtra( ConnectivityManager.EXTRA_AVAILABLE_TETHER); - sendMessage(CMD_TETHER_INTERFACE, available); + ArrayList<String> active = intent.getStringArrayListExtra( + ConnectivityManager.EXTRA_ACTIVE_TETHER); + sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); } },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); @@ -603,7 +630,9 @@ public class WifiStateMachine extends StateMachine { addState(mSupplicantStoppingState, mDefaultState); addState(mSoftApStartingState, mDefaultState); addState(mSoftApStartedState, mDefaultState); + addState(mTetheringState, mSoftApStartedState); addState(mTetheredState, mSoftApStartedState); + addState(mSoftApStoppingState, mDefaultState); addState(mWaitForP2pDisableState, mDefaultState); setInitialState(mInitialState); @@ -1139,6 +1168,7 @@ public class WifiStateMachine extends StateMachine { loge("Error tethering on " + intf); return false; } + mTetherInterfaceName = intf; return true; } } @@ -1165,11 +1195,27 @@ public class WifiStateMachine extends StateMachine { loge("Error resetting interface " + mInterfaceName + ", :" + e); } - if (mCm.untether(mInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { + if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { loge("Untether initiate failed!"); } } + private boolean isWifiTethered(ArrayList<String> active) { + + checkAndSetConnectivityInstance(); + + String[] wifiRegexs = mCm.getTetherableWifiRegexs(); + for (String intf : active) { + for (String regex : wifiRegexs) { + if (intf.matches(regex)) { + return true; + } + } + } + // We found no interfaces that are tethered + return false; + } + /** * Set the country code from the system setting value, if any. */ @@ -1800,7 +1846,8 @@ public class WifiStateMachine extends StateMachine { case CMD_START_AP_SUCCESS: case CMD_START_AP_FAILURE: case CMD_STOP_AP: - case CMD_TETHER_INTERFACE: + case CMD_TETHER_STATE_CHANGE: + case CMD_TETHER_NOTIFICATION_TIMED_OUT: case CMD_START_SCAN: case CMD_DISCONNECT: case CMD_RECONNECT: @@ -3284,7 +3331,7 @@ public class WifiStateMachine extends StateMachine { case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: case CMD_STOP_PACKET_FILTERING: - case CMD_TETHER_INTERFACE: + case CMD_TETHER_STATE_CHANGE: case WifiP2pService.P2P_ENABLE_PENDING: deferMessage(message); break; @@ -3326,7 +3373,8 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_AP: if (DBG) log("Stopping Soft AP"); setWifiApState(WIFI_AP_STATE_DISABLING); - stopTethering(); + + /* We have not tethered at this point, so we just shutdown soft Ap */ try { mNwService.stopAccessPoint(mInterfaceName); } catch(Exception e) { @@ -3342,10 +3390,10 @@ public class WifiStateMachine extends StateMachine { loge("Cannot start supplicant with a running soft AP"); setWifiState(WIFI_STATE_UNKNOWN); break; - case CMD_TETHER_INTERFACE: - ArrayList<String> available = (ArrayList<String>) message.obj; - if (startTethering(available)) { - transitionTo(mTetheredState); + case CMD_TETHER_STATE_CHANGE: + TetherStateChange stateChange = (TetherStateChange) message.obj; + if (startTethering(stateChange.available)) { + transitionTo(mTetheringState); } break; case WifiP2pService.P2P_ENABLE_PENDING: @@ -3405,6 +3453,58 @@ public class WifiStateMachine extends StateMachine { } } + class TetheringState extends State { + @Override + public void enter() { + if (DBG) log(getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + + /* Send ourselves a delayed message to shut down if tethering fails to notify */ + sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, + ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); + } + @Override + public boolean processMessage(Message message) { + if (DBG) log(getName() + message.toString() + "\n"); + switch(message.what) { + case CMD_TETHER_STATE_CHANGE: + TetherStateChange stateChange = (TetherStateChange) message.obj; + if (isWifiTethered(stateChange.active)) { + transitionTo(mTetheredState); + } + return HANDLED; + case CMD_TETHER_NOTIFICATION_TIMED_OUT: + if (message.arg1 == mTetherToken) { + loge("Failed to get tether update, shutdown soft access point"); + setWifiApEnabled(null, false); + } + break; + case CMD_LOAD_DRIVER: + case CMD_UNLOAD_DRIVER: + case CMD_START_SUPPLICANT: + case CMD_STOP_SUPPLICANT: + case CMD_START_AP: + case CMD_STOP_AP: + case CMD_START_DRIVER: + case CMD_STOP_DRIVER: + case CMD_SET_SCAN_MODE: + case CMD_SET_SCAN_TYPE: + case CMD_SET_HIGH_PERF_MODE: + case CMD_SET_COUNTRY_CODE: + case CMD_SET_FREQUENCY_BAND: + case CMD_START_PACKET_FILTERING: + case CMD_STOP_PACKET_FILTERING: + case WifiP2pService.P2P_ENABLE_PENDING: + deferMessage(message); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + class TetheredState extends State { @Override public void enter() { @@ -3415,13 +3515,89 @@ public class WifiStateMachine extends StateMachine { public boolean processMessage(Message message) { if (DBG) log(getName() + message.toString() + "\n"); switch(message.what) { - case CMD_TETHER_INTERFACE: - // Ignore any duplicate interface available notifications - // when in tethered state + case CMD_TETHER_STATE_CHANGE: + TetherStateChange stateChange = (TetherStateChange) message.obj; + if (!isWifiTethered(stateChange.active)) { + loge("Tethering reports wifi as untethered!, shut down soft Ap"); + setWifiApEnabled(null, false); + } return HANDLED; + case CMD_STOP_AP: + if (DBG) log("Untethering before stopping AP"); + setWifiApState(WIFI_AP_STATE_DISABLING); + stopTethering(); + transitionTo(mSoftApStoppingState); + break; default: return NOT_HANDLED; } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class SoftApStoppingState extends State { + @Override + public void enter() { + if (DBG) log(getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + + /* Send ourselves a delayed message to shut down if tethering fails to notify */ + sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, + ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); + + } + @Override + public boolean processMessage(Message message) { + if (DBG) log(getName() + message.toString() + "\n"); + switch(message.what) { + case CMD_TETHER_STATE_CHANGE: + TetherStateChange stateChange = (TetherStateChange) message.obj; + + /* Wait till wifi is untethered */ + if (isWifiTethered(stateChange.active)) break; + + try { + mNwService.stopAccessPoint(mInterfaceName); + } catch(Exception e) { + loge("Exception in stopAccessPoint()"); + } + transitionTo(mDriverLoadedState); + break; + case CMD_TETHER_NOTIFICATION_TIMED_OUT: + if (message.arg1 == mTetherToken) { + loge("Failed to get tether update, force stop access point"); + try { + mNwService.stopAccessPoint(mInterfaceName); + } catch(Exception e) { + loge("Exception in stopAccessPoint()"); + } + transitionTo(mDriverLoadedState); + } + break; + case CMD_LOAD_DRIVER: + case CMD_UNLOAD_DRIVER: + case CMD_START_SUPPLICANT: + case CMD_STOP_SUPPLICANT: + case CMD_START_AP: + case CMD_STOP_AP: + case CMD_START_DRIVER: + case CMD_STOP_DRIVER: + case CMD_SET_SCAN_MODE: + case CMD_SET_SCAN_TYPE: + case CMD_SET_HIGH_PERF_MODE: + case CMD_SET_COUNTRY_CODE: + case CMD_SET_FREQUENCY_BAND: + case CMD_START_PACKET_FILTERING: + case CMD_STOP_PACKET_FILTERING: + case WifiP2pService.P2P_ENABLE_PENDING: + deferMessage(message); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; } } |