diff options
author | Irfan Sheriff <isheriff@google.com> | 2010-07-28 09:35:20 -0700 |
---|---|---|
committer | Irfan Sheriff <isheriff@google.com> | 2010-08-10 15:18:25 -0700 |
commit | 0d25534fed91f636def5776ddc4605005bd7471c (patch) | |
tree | f1fa39d0989049137c8150f22abe1307bf7b73a3 /wifi | |
parent | 926bd956d6d149c12ddfe92d55d4a1de705861ec (diff) | |
download | frameworks_base-0d25534fed91f636def5776ddc4605005bd7471c.zip frameworks_base-0d25534fed91f636def5776ddc4605005bd7471c.tar.gz frameworks_base-0d25534fed91f636def5776ddc4605005bd7471c.tar.bz2 |
Split WifiStateMachine from WifiStateTracker
Notifications handled in WifiService. WifiStateTracker tracks
state for connectivity service
Change-Id: Idb0cf494898d28712af0f95f9e60c5417cd4a053
Diffstat (limited to 'wifi')
-rw-r--r-- | wifi/java/android/net/wifi/IWifiManager.aidl | 8 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiManager.java | 91 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiMonitor.java | 33 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiStateMachine.java | 3572 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiStateTracker.java | 3812 |
5 files changed, 3727 insertions, 3789 deletions
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 6e0bc9d..3426af7 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -85,5 +85,13 @@ interface IWifiManager WifiConfiguration getWifiApConfiguration(); void setWifiApConfiguration(in WifiConfiguration wifiConfig); + + void startWifi(); + + void stopWifi(); + + void addToBlacklist(String bssid); + + void clearBlacklist(); } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 6fac902..339763a 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -293,6 +293,21 @@ public class WifiManager { public static final String EXTRA_NEW_RSSI = "newRssi"; /** + * Broadcast intent action indicating that the IP configuration + * changed on wifi. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String CONFIG_CHANGED_ACTION = "android.net.wifi.CONFIG_CHANGED"; + /** + * The lookup key for a {@link android.net.NetworkProperties} object associated with the + * Wi-Fi network. Retrieve with + * {@link android.content.Intent#getParcelableExtra(String)}. + * @hide + */ + public static final String EXTRA_NETWORK_PROPERTIES = "networkProperties"; + + /** * The network IDs of the configured networks could have changed. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @@ -838,6 +853,82 @@ public class WifiManager { } } + /** + * Start the driver and connect to network. + * + * This function will over-ride WifiLock and device idle status. For example, + * even if the device is idle or there is only a scan-only lock held, + * a start wifi would mean that wifi connection is kept active until + * a stopWifi() is sent. + * + * This API is used by WifiStateTracker + * + * @return {@code true} if the operation succeeds else {@code false} + * @hide + */ + public boolean startWifi() { + try { + mService.startWifi(); + return true; + } catch (RemoteException e) { + return false; + } + } + + /** + * Disconnect from a network (if any) and stop the driver. + * + * This function will over-ride WifiLock and device idle status. Wi-Fi + * stays inactive until a startWifi() is issued. + * + * This API is used by WifiStateTracker + * + * @return {@code true} if the operation succeeds else {@code false} + * @hide + */ + public boolean stopWifi() { + try { + mService.stopWifi(); + return true; + } catch (RemoteException e) { + return false; + } + } + + /** + * Add a bssid to the supplicant blacklist + * + * This API is used by WifiWatchdogService + * + * @return {@code true} if the operation succeeds else {@code false} + * @hide + */ + public boolean addToBlacklist(String bssid) { + try { + mService.addToBlacklist(bssid); + return true; + } catch (RemoteException e) { + return false; + } + } + + /** + * Clear the supplicant blacklist + * + * This API is used by WifiWatchdogService + * + * @return {@code true} if the operation succeeds else {@code false} + * @hide + */ + public boolean clearBlacklist() { + try { + mService.clearBlacklist(); + return true; + } catch (RemoteException e) { + return false; + } + } + /** * Allows an application to keep the Wi-Fi radio awake. * Normally the Wi-Fi radio may turn off when the user has not used the device in a while. diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java index f2f8343..af3132f 100644 --- a/wifi/java/android/net/wifi/WifiMonitor.java +++ b/wifi/java/android/net/wifi/WifiMonitor.java @@ -19,14 +19,13 @@ package android.net.wifi; import android.util.Log; import android.util.Config; import android.net.NetworkInfo; -import android.net.NetworkStateTracker; import java.util.regex.Pattern; import java.util.regex.Matcher; /** * Listens for events from the wpa_supplicant server, and passes them on - * to the {@link WifiStateTracker} for handling. Runs in its own thread. + * to the {@link WifiStateMachine} for handling. Runs in its own thread. * * @hide */ @@ -117,7 +116,7 @@ public class WifiMonitor { private static Pattern mConnectedEventPattern = Pattern.compile("((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) .* \\[id=([0-9]+) "); - private final WifiStateTracker mWifiStateTracker; + private final WifiStateMachine mWifiStateMachine; /** * This indicates the supplicant connection for the monitor is closed @@ -139,18 +138,14 @@ public class WifiMonitor { */ private static final int MAX_RECV_ERRORS = 10; - public WifiMonitor(WifiStateTracker tracker) { - mWifiStateTracker = tracker; + public WifiMonitor(WifiStateMachine wifiStateMachine) { + mWifiStateMachine = wifiStateMachine; } public void startMonitoring() { new MonitorThread().start(); } - public NetworkStateTracker getNetworkStateTracker() { - return mWifiStateTracker; - } - class MonitorThread extends Thread { public MonitorThread() { super("WifiMonitor"); @@ -161,9 +156,9 @@ public class WifiMonitor { if (connectToSupplicant()) { // Send a message indicating that it is now possible to send commands // to the supplicant - mWifiStateTracker.notifySupplicantConnection(); + mWifiStateMachine.notifySupplicantConnection(); } else { - mWifiStateTracker.notifySupplicantLost(); + mWifiStateMachine.notifySupplicantLost(); return; } @@ -259,7 +254,7 @@ public class WifiMonitor { } // notify and exit - mWifiStateTracker.notifySupplicantLost(); + mWifiStateMachine.notifySupplicantLost(); break; } else { handleEvent(event, eventData); @@ -285,7 +280,7 @@ public class WifiMonitor { } private void handlePasswordKeyMayBeIncorrect() { - mWifiStateTracker.notifyPasswordKeyMayBeIncorrect(); + mWifiStateMachine.notifyPasswordKeyMayBeIncorrect(); } private void handleDriverEvent(String state) { @@ -293,11 +288,11 @@ public class WifiMonitor { return; } if (state.equals("STOPPED")) { - mWifiStateTracker.notifyDriverStopped(); + mWifiStateMachine.notifyDriverStopped(); } else if (state.equals("STARTED")) { - mWifiStateTracker.notifyDriverStarted(); + mWifiStateMachine.notifyDriverStarted(); } else if (state.equals("HANGED")) { - mWifiStateTracker.notifyDriverHung(); + mWifiStateMachine.notifyDriverHung(); } } @@ -318,7 +313,7 @@ public class WifiMonitor { break; case SCAN_RESULTS: - mWifiStateTracker.notifyScanResultsAvailable(); + mWifiStateMachine.notifyScanResultsAvailable(); break; case UNKNOWN: @@ -375,7 +370,7 @@ public class WifiMonitor { if (newSupplicantState == SupplicantState.INVALID) { Log.w(TAG, "Invalid supplicant state: " + newState); } - mWifiStateTracker.notifySupplicantStateChange(networkId, BSSID, newSupplicantState); + mWifiStateMachine.notifySupplicantStateChange(networkId, BSSID, newSupplicantState); } } @@ -395,7 +390,7 @@ public class WifiMonitor { } } } - mWifiStateTracker.notifyNetworkStateChange(newState, BSSID, networkId); + mWifiStateMachine.notifyNetworkStateChange(newState, BSSID, networkId); } /** diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java new file mode 100644 index 0000000..6794c05 --- /dev/null +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -0,0 +1,3572 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; +import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; +import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; +import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; +import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; + +/** + * TODO: Add soft AP states as part of WIFI_STATE_XXX + * Retain WIFI_STATE_ENABLING that indicates driver is loading + * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started + * and WIFI_STATE_FAILED for failure + * Deprecate WIFI_STATE_UNKNOWN + * + * Doing this will simplify the logic for sending broadcasts + */ +import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; + +import android.app.ActivityManagerNative; +import android.net.NetworkInfo; +import android.net.DhcpInfo; +import android.net.NetworkUtils; +import android.net.ConnectivityManager; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkProperties; +import android.os.Binder; +import android.os.Message; +import android.os.Parcelable; +import android.os.Handler; +import android.os.IBinder; +import android.os.INetworkManagementService; +import android.os.PowerManager; +import android.os.SystemProperties; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.Process; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.EventLog; +import android.util.Log; +import android.util.Slog; +import android.app.backup.IBackupManager; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothA2dp; +import android.content.ContentResolver; +import android.content.Intent; +import android.content.Context; +import android.database.ContentObserver; +import com.android.internal.app.IBatteryStats; +import com.android.internal.util.HierarchicalState; +import com.android.internal.util.HierarchicalStateMachine; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Pattern; + +/** + * Track the state of Wifi connectivity. All event handling is done here, + * and all changes in connectivity state are initiated here. + * + * @hide + */ +//TODO: we still need frequent scanning for the case when +// we issue disconnect but need scan results for open network notification +public class WifiStateMachine extends HierarchicalStateMachine { + + private static final String TAG = "WifiStateMachine"; + private static final String NETWORKTYPE = "WIFI"; + private static final boolean DBG = false; + + /* TODO: fetch a configurable interface */ + private static final String SOFTAP_IFACE = "wl0.1"; + + private WifiMonitor mWifiMonitor; + private INetworkManagementService nwService; + private ConnectivityManager mCm; + + /* Scan results handling */ + private List<ScanResult> mScanResults; + private static final Pattern scanResultPattern = Pattern.compile("\t+"); + private static final int SCAN_RESULT_CACHE_SIZE = 80; + private final LinkedHashMap<String, ScanResult> mScanResultCache; + + private String mInterfaceName; + + private int mNumAllowedChannels = 0; + private int mLastSignalLevel = -1; + private String mLastBssid; + private int mLastNetworkId; + private boolean mEnableRssiPolling = false; + private boolean mPasswordKeyMayBeIncorrect = false; + private boolean mUseStaticIp = false; + private int mReconnectCount = 0; + private boolean mIsScanMode = false; + private boolean mConfigChanged = false; + + /** + * Instance of the bluetooth headset helper. This needs to be created + * early because there is a delay before it actually 'connects', as + * noted by its javadoc. If we check before it is connected, it will be + * in an error state and we will not disable coexistence. + */ + private BluetoothHeadset mBluetoothHeadset; + + private BluetoothA2dp mBluetoothA2dp; + + /** + * Observes the static IP address settings. + */ + private SettingsObserver mSettingsObserver; + private NetworkProperties mNetworkProperties; + + // Held during driver load and unload + private static PowerManager.WakeLock sWakeLock; + + private Context mContext; + + private DhcpInfo mDhcpInfo; + private WifiInfo mWifiInfo; + private NetworkInfo mNetworkInfo; + private SupplicantStateTracker mSupplicantStateTracker; + + // Event log tags (must be in sync with event-log-tags) + private static final int EVENTLOG_WIFI_STATE_CHANGED = 50021; + private static final int EVENTLOG_WIFI_EVENT_HANDLED = 50022; + private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED = 50023; + + /* Load the driver */ + private static final int CMD_LOAD_DRIVER = 1; + /* Unload the driver */ + private static final int CMD_UNLOAD_DRIVER = 2; + /* Indicates driver load succeeded */ + private static final int CMD_LOAD_DRIVER_SUCCESS = 3; + /* Indicates driver load failed */ + private static final int CMD_LOAD_DRIVER_FAILURE = 4; + /* Indicates driver unload succeeded */ + private static final int CMD_UNLOAD_DRIVER_SUCCESS = 5; + /* Indicates driver unload failed */ + private static final int CMD_UNLOAD_DRIVER_FAILURE = 6; + + /* Start the supplicant */ + private static final int CMD_START_SUPPLICANT = 11; + /* Stop the supplicant */ + private static final int CMD_STOP_SUPPLICANT = 12; + /* Start the driver */ + private static final int CMD_START_DRIVER = 13; + /* Start the driver */ + private static final int CMD_STOP_DRIVER = 14; + /* Indicates DHCP succeded */ + private static final int CMD_IP_CONFIG_SUCCESS = 15; + /* Indicates DHCP failed */ + private static final int CMD_IP_CONFIG_FAILURE = 16; + /* Re-configure interface */ + private static final int CMD_RECONFIGURE_IP = 17; + + + /* Start the soft access point */ + private static final int CMD_START_AP = 21; + /* Stop the soft access point */ + private static final int CMD_STOP_AP = 22; + + + /* Supplicant events */ + /* Connection to supplicant established */ + private static final int SUP_CONNECTION_EVENT = 31; + /* Connection to supplicant lost */ + private static final int SUP_DISCONNECTION_EVENT = 32; + /* Driver start completed */ + private static final int DRIVER_START_EVENT = 33; + /* Driver stop completed */ + private static final int DRIVER_STOP_EVENT = 34; + /* Network connection completed */ + private static final int NETWORK_CONNECTION_EVENT = 36; + /* Network disconnection completed */ + private static final int NETWORK_DISCONNECTION_EVENT = 37; + /* Scan results are available */ + private static final int SCAN_RESULTS_EVENT = 38; + /* Supplicate state changed */ + private static final int SUPPLICANT_STATE_CHANGE_EVENT = 39; + /* Password may be incorrect */ + private static final int PASSWORD_MAY_BE_INCORRECT_EVENT = 40; + + /* Supplicant commands */ + /* Is supplicant alive ? */ + private static final int CMD_PING_SUPPLICANT = 51; + /* Add/update a network configuration */ + private static final int CMD_ADD_OR_UPDATE_NETWORK = 52; + /* Delete a network */ + private static final int CMD_REMOVE_NETWORK = 53; + /* Enable a network. The device will attempt a connection to the given network. */ + private static final int CMD_ENABLE_NETWORK = 54; + /* Disable a network. The device does not attempt a connection to the given network. */ + private static final int CMD_DISABLE_NETWORK = 55; + /* Blacklist network. De-prioritizes the given BSSID for connection. */ + private static final int CMD_BLACKLIST_NETWORK = 56; + /* Clear the blacklist network list */ + private static final int CMD_CLEAR_BLACKLIST = 57; + /* Get the configured networks */ + private static final int CMD_GET_NETWORK_CONFIG = 58; + /* Save configuration */ + private static final int CMD_SAVE_CONFIG = 59; + /* Connection status */ + private static final int CMD_CONNECTION_STATUS = 60; + + /* Supplicant commands after driver start*/ + /* Initiate a scan */ + private static final int CMD_START_SCAN = 71; + /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */ + private static final int CMD_SET_SCAN_MODE = 72; + /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */ + private static final int CMD_SET_SCAN_TYPE = 73; + /* Disconnect from a network */ + private static final int CMD_DISCONNECT = 74; + /* Reconnect to a network */ + private static final int CMD_RECONNECT = 75; + /* Reassociate to a network */ + private static final int CMD_REASSOCIATE = 76; + /* Set power mode + * POWER_MODE_ACTIVE + * POWER_MODE_AUTO + */ + private static final int CMD_SET_POWER_MODE = 77; + /* Set bluetooth co-existence + * BLUETOOTH_COEXISTENCE_MODE_ENABLED + * BLUETOOTH_COEXISTENCE_MODE_DISABLED + * BLUETOOTH_COEXISTENCE_MODE_SENSE + */ + private static final int CMD_SET_BLUETOOTH_COEXISTENCE = 78; + /* Enable/disable bluetooth scan mode + * true(1) + * false(0) + */ + private static final int CMD_SET_BLUETOOTH_SCAN_MODE = 79; + /* Set number of allowed channels */ + private static final int CMD_SET_NUM_ALLOWED_CHANNELS = 80; + /* Request connectivity manager wake lock before driver stop */ + private static final int CMD_REQUEST_CM_WAKELOCK = 81; + /* Enables RSSI poll */ + private static final int CMD_ENABLE_RSSI_POLL = 82; + /* RSSI poll */ + private static final int CMD_RSSI_POLL = 83; + /* Get current RSSI */ + private static final int CMD_GET_RSSI = 84; + /* Get approx current RSSI */ + private static final int CMD_GET_RSSI_APPROX = 85; + /* Get link speed on connection */ + private static final int CMD_GET_LINK_SPEED = 86; + /* Radio mac address */ + private static final int CMD_GET_MAC_ADDR = 87; + /* Set up packet filtering */ + private static final int CMD_START_PACKET_FILTERING = 88; + /* Clear packet filter */ + private static final int CMD_STOP_PACKET_FILTERING = 89; + + /** + * Interval in milliseconds between polling for connection + * status items that are not sent via asynchronous events. + * An example is RSSI (signal strength). + */ + private static final int POLL_RSSI_INTERVAL_MSECS = 3000; + + private static final int CONNECT_MODE = 1; + private static final int SCAN_ONLY_MODE = 2; + + private static final int SCAN_ACTIVE = 1; + private static final int SCAN_PASSIVE = 2; + + /** + * The maximum number of times we will retry a connection to an access point + * for which we have failed in acquiring an IP address from DHCP. A value of + * N means that we will make N+1 connection attempts in all. + * <p> + * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default + * value if a Settings value is not present. + */ + private static final int DEFAULT_MAX_DHCP_RETRIES = 9; + + private static final int DRIVER_POWER_MODE_ACTIVE = 1; + private static final int DRIVER_POWER_MODE_AUTO = 0; + + /* Default parent state */ + private HierarchicalState mDefaultState = new DefaultState(); + /* Temporary initial state */ + private HierarchicalState mInitialState = new InitialState(); + /* Unloading the driver */ + private HierarchicalState mDriverUnloadingState = new DriverUnloadingState(); + /* Loading the driver */ + private HierarchicalState mDriverUnloadedState = new DriverUnloadedState(); + /* Driver load/unload failed */ + private HierarchicalState mDriverFailedState = new DriverFailedState(); + /* Driver loading */ + private HierarchicalState mDriverLoadingState = new DriverLoadingState(); + /* Driver loaded */ + private HierarchicalState mDriverLoadedState = new DriverLoadedState(); + /* Driver loaded, waiting for supplicant to start */ + private HierarchicalState mWaitForSupState = new WaitForSupState(); + + /* Driver loaded and supplicant ready */ + private HierarchicalState mDriverSupReadyState = new DriverSupReadyState(); + /* Driver start issued, waiting for completed event */ + private HierarchicalState mDriverStartingState = new DriverStartingState(); + /* Driver started */ + private HierarchicalState mDriverStartedState = new DriverStartedState(); + /* Driver stopping */ + private HierarchicalState mDriverStoppingState = new DriverStoppingState(); + /* Driver stopped */ + private HierarchicalState mDriverStoppedState = new DriverStoppedState(); + /* Scan for networks, no connection will be established */ + private HierarchicalState mScanModeState = new ScanModeState(); + /* Connecting to an access point */ + private HierarchicalState mConnectModeState = new ConnectModeState(); + /* Fetching IP after network connection (assoc+auth complete) */ + private HierarchicalState mConnectingState = new ConnectingState(); + /* Connected with IP addr */ + private HierarchicalState mConnectedState = new ConnectedState(); + /* disconnect issued, waiting for network disconnect confirmation */ + private HierarchicalState mDisconnectingState = new DisconnectingState(); + /* Network is not connected, supplicant assoc+auth is not complete */ + private HierarchicalState mDisconnectedState = new DisconnectedState(); + + /* Soft Ap is running */ + private HierarchicalState mSoftApStartedState = new SoftApStartedState(); + + /* Argument for Message object to indicate a synchronous call */ + private static final int SYNCHRONOUS_CALL = 1; + private static final int ASYNCHRONOUS_CALL = 0; + + + /** + * One of {@link WifiManager#WIFI_STATE_DISABLED}, + * {@link WifiManager#WIFI_STATE_DISABLING}, + * {@link WifiManager#WIFI_STATE_ENABLED}, + * {@link WifiManager#WIFI_STATE_ENABLING}, + * {@link WifiManager#WIFI_STATE_UNKNOWN} + * + */ + private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); + + /** + * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, + * {@link WifiManager#WIFI_AP_STATE_DISABLING}, + * {@link WifiManager#WIFI_AP_STATE_ENABLED}, + * {@link WifiManager#WIFI_AP_STATE_ENABLING}, + * {@link WifiManager#WIFI_AP_STATE_FAILED} + * + */ + private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); + + private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid()); + private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid()); + + private final IBatteryStats mBatteryStats; + + public WifiStateMachine(Context context) { + super(TAG); + + mContext = context; + + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); + mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); + + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + nwService = INetworkManagementService.Stub.asInterface(b); + + mWifiMonitor = new WifiMonitor(this); + mDhcpInfo = new DhcpInfo(); + mWifiInfo = new WifiInfo(); + mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0"); + mSupplicantStateTracker = new SupplicantStateTracker(context, getHandler()); + + mBluetoothHeadset = new BluetoothHeadset(mContext, null); + mNetworkProperties = new NetworkProperties(); + + mNetworkInfo.setIsAvailable(false); + mNetworkProperties.clear(); + mLastBssid = null; + mLastNetworkId = -1; + mLastSignalLevel = -1; + + mScanResultCache = new LinkedHashMap<String, ScanResult>( + SCAN_RESULT_CACHE_SIZE, 0.75f, true) { + /* + * Limit the cache size by SCAN_RESULT_CACHE_SIZE + * elements + */ + @Override + public boolean removeEldestEntry(Map.Entry eldest) { + return SCAN_RESULT_CACHE_SIZE < this.size(); + } + }; + + mSettingsObserver = new SettingsObserver(new Handler()); + + PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + + addState(mDefaultState); + addState(mInitialState, mDefaultState); + addState(mDriverUnloadingState, mDefaultState); + addState(mDriverUnloadedState, mDefaultState); + addState(mDriverFailedState, mDriverUnloadedState); + addState(mDriverLoadingState, mDefaultState); + addState(mDriverLoadedState, mDefaultState); + addState(mWaitForSupState, mDriverLoadedState); + addState(mDriverSupReadyState, mDefaultState); + addState(mDriverStartingState, mDriverSupReadyState); + addState(mDriverStartedState, mDriverSupReadyState); + addState(mScanModeState, mDriverStartedState); + addState(mConnectModeState, mDriverStartedState); + addState(mConnectingState, mConnectModeState); + addState(mConnectedState, mConnectModeState); + addState(mDisconnectingState, mConnectModeState); + addState(mDisconnectedState, mConnectModeState); + addState(mDriverStoppingState, mDriverSupReadyState); + addState(mDriverStoppedState, mDriverSupReadyState); + addState(mSoftApStartedState, mDefaultState); + + setInitialState(mInitialState); + + if (DBG) setDbg(true); + + //start the state machine + start(); + } + + /********************************************************* + * Methods exposed for public use + ********************************************************/ + + /** + * TODO: doc + */ + public boolean pingSupplicant() { + return sendSyncMessage(CMD_PING_SUPPLICANT).boolValue; + } + + /** + * TODO: doc + */ + public boolean startScan(boolean forceActive) { + return sendSyncMessage(obtainMessage(CMD_START_SCAN, forceActive ? + SCAN_ACTIVE : SCAN_PASSIVE, 0)).boolValue; + } + + /** + * TODO: doc + */ + public void setWifiEnabled(boolean enable) { + mLastEnableUid.set(Binder.getCallingUid()); + if (enable) { + /* Argument is the state that is entered prior to load */ + sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0)); + sendMessage(CMD_START_SUPPLICANT); + } else { + sendMessage(CMD_STOP_SUPPLICANT); + /* Argument is the state that is entered upon success */ + sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0)); + } + } + + /** + * TODO: doc + */ + public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) { + mLastApEnableUid.set(Binder.getCallingUid()); + if (enable) { + /* Argument is the state that is entered prior to load */ + sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0)); + sendMessage(obtainMessage(CMD_START_AP, wifiConfig)); + } else { + sendMessage(CMD_STOP_AP); + /* Argument is the state that is entered upon success */ + sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0)); + } + } + + /** + * TODO: doc + */ + public int getWifiState() { + return mWifiState.get(); + } + + /** + * TODO: doc + */ + public String getWifiStateByName() { + switch (mWifiState.get()) { + case WIFI_STATE_DISABLING: + return "disabling"; + case WIFI_STATE_DISABLED: + return "disabled"; + case WIFI_STATE_ENABLING: + return "enabling"; + case WIFI_STATE_ENABLED: + return "enabled"; + case WIFI_STATE_UNKNOWN: + return "unknown state"; + default: + return "[invalid state]"; + } + } + + /** + * TODO: doc + */ + public int getWifiApState() { + return mWifiApState.get(); + } + + /** + * TODO: doc + */ + public String getWifiApStateByName() { + switch (mWifiApState.get()) { + case WIFI_AP_STATE_DISABLING: + return "disabling"; + case WIFI_AP_STATE_DISABLED: + return "disabled"; + case WIFI_AP_STATE_ENABLING: + return "enabling"; + case WIFI_AP_STATE_ENABLED: + return "enabled"; + case WIFI_AP_STATE_FAILED: + return "failed"; + default: + return "[invalid state]"; + } + } + + /** + * Get status information for the current connection, if any. + * @return a {@link WifiInfo} object containing information about the current connection + * + */ + public WifiInfo requestConnectionInfo() { + return mWifiInfo; + } + + public DhcpInfo getDhcpInfo() { + return mDhcpInfo; + } + + /** + * TODO: doc + */ + public void setDriverStart(boolean enable) { + if (enable) { + sendMessage(CMD_START_DRIVER); + } else { + sendMessage(CMD_STOP_DRIVER); + } + } + + /** + * TODO: doc + */ + public void setScanOnlyMode(boolean enable) { + if (enable) { + sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0)); + } else { + sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0)); + } + } + + /** + * TODO: doc + */ + public void setScanType(boolean active) { + if (active) { + sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0)); + } else { + sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0)); + } + } + + /** + * TODO: doc + */ + public List<ScanResult> getScanResultsList() { + return mScanResults; + } + + /** + * Disconnect from Access Point + */ + public boolean disconnectCommand() { + return sendSyncMessage(CMD_DISCONNECT).boolValue; + } + + /** + * Initiate a reconnection to AP + */ + public boolean reconnectCommand() { + return sendSyncMessage(CMD_RECONNECT).boolValue; + } + + /** + * Initiate a re-association to AP + */ + public boolean reassociateCommand() { + return sendSyncMessage(CMD_REASSOCIATE).boolValue; + } + + /** + * Add a network synchronously + * + * @return network id of the new network + */ + public int addOrUpdateNetwork(WifiConfiguration config) { + return sendSyncMessage(CMD_ADD_OR_UPDATE_NETWORK, config).intValue; + } + + public List<WifiConfiguration> getConfiguredNetworks() { + return sendSyncMessage(CMD_GET_NETWORK_CONFIG).configList; + } + + /** + * Delete a network + * + * @param networkId id of the network to be removed + */ + public boolean removeNetwork(int networkId) { + return sendSyncMessage(obtainMessage(CMD_REMOVE_NETWORK, networkId, 0)).boolValue; + } + + private class EnableNetParams { + private int netId; + private boolean disableOthers; + EnableNetParams(int n, boolean b) { + netId = n; + disableOthers = b; + } + } + /** + * Enable a network + * + * @param netId network id of the network + * @param disableOthers true, if all other networks have to be disabled + * @return {@code true} if the operation succeeds, {@code false} otherwise + */ + public boolean enableNetwork(int netId, boolean disableOthers) { + return sendSyncMessage(CMD_ENABLE_NETWORK, + new EnableNetParams(netId, disableOthers)).boolValue; + } + + /** + * Disable a network + * + * @param netId network id of the network + * @return {@code true} if the operation succeeds, {@code false} otherwise + */ + public boolean disableNetwork(int netId) { + return sendSyncMessage(obtainMessage(CMD_DISABLE_NETWORK, netId, 0)).boolValue; + } + + /** + * Blacklist a BSSID. This will avoid the AP if there are + * alternate APs to connect + * + * @param bssid BSSID of the network + */ + public void addToBlacklist(String bssid) { + sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid)); + } + + /** + * Clear the blacklist list + * + */ + public void clearBlacklist() { + sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST)); + } + + /** + * Get detailed status of the connection + * + * @return Example status result + * bssid=aa:bb:cc:dd:ee:ff + * ssid=TestNet + * id=3 + * pairwise_cipher=NONE + * group_cipher=NONE + * key_mgmt=NONE + * wpa_state=COMPLETED + * ip_address=X.X.X.X + */ + public String status() { + return sendSyncMessage(CMD_CONNECTION_STATUS).stringValue; + } + + public void enableRssiPolling(boolean enabled) { + sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0)); + } + /** + * Get RSSI to currently connected network + * + * @return RSSI value, -1 on failure + */ + public int getRssi() { + return sendSyncMessage(CMD_GET_RSSI).intValue; + } + + /** + * Get approx RSSI to currently connected network + * + * @return RSSI value, -1 on failure + */ + public int getRssiApprox() { + return sendSyncMessage(CMD_GET_RSSI_APPROX).intValue; + } + + /** + * Get link speed to currently connected network + * + * @return link speed, -1 on failure + */ + public int getLinkSpeed() { + return sendSyncMessage(CMD_GET_LINK_SPEED).intValue; + } + + /** + * Get MAC address of radio + * + * @return MAC address, null on failure + */ + public String getMacAddress() { + return sendSyncMessage(CMD_GET_MAC_ADDR).stringValue; + } + + /** + * Start packet filtering + */ + public void startPacketFiltering() { + sendMessage(CMD_START_PACKET_FILTERING); + } + + /** + * Stop packet filtering + */ + public void stopPacketFiltering() { + sendMessage(CMD_STOP_PACKET_FILTERING); + } + + /** + * Set power mode + * @param mode + * DRIVER_POWER_MODE_AUTO + * DRIVER_POWER_MODE_ACTIVE + */ + public void setPowerMode(int mode) { + sendMessage(obtainMessage(CMD_SET_POWER_MODE, mode, 0)); + } + + /** + * Set the number of allowed radio frequency channels from the system + * setting value, if any. + */ + public void setNumAllowedChannels() { + try { + setNumAllowedChannels( + Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS)); + } catch (Settings.SettingNotFoundException e) { + if (mNumAllowedChannels != 0) { + setNumAllowedChannels(mNumAllowedChannels); + } + // otherwise, use the driver default + } + } + + /** + * Set the number of radio frequency channels that are allowed to be used + * in the current regulatory domain. + * @param numChannels the number of allowed channels. Must be greater than 0 + * and less than or equal to 16. + */ + public void setNumAllowedChannels(int numChannels) { + sendMessage(obtainMessage(CMD_SET_NUM_ALLOWED_CHANNELS, numChannels, 0)); + } + + /** + * Get number of allowed channels + * + * @return channel count, -1 on failure + * + * TODO: this is not a public API and needs to be removed in favor + * of asynchronous reporting. unused for now. + */ + public int getNumAllowedChannels() { + return -1; + } + + /** + * Set bluetooth coex mode: + * + * @param mode + * BLUETOOTH_COEXISTENCE_MODE_ENABLED + * BLUETOOTH_COEXISTENCE_MODE_DISABLED + * BLUETOOTH_COEXISTENCE_MODE_SENSE + */ + public void setBluetoothCoexistenceMode(int mode) { + sendMessage(obtainMessage(CMD_SET_BLUETOOTH_COEXISTENCE, mode, 0)); + } + + /** + * Enable or disable Bluetooth coexistence scan mode. When this mode is on, + * some of the low-level scan parameters used by the driver are changed to + * reduce interference with A2DP streaming. + * + * @param isBluetoothPlaying whether to enable or disable this mode + */ + public void setBluetoothScanMode(boolean isBluetoothPlaying) { + sendMessage(obtainMessage(CMD_SET_BLUETOOTH_SCAN_MODE, isBluetoothPlaying ? 1 : 0, 0)); + } + + /** + * Save configuration on supplicant + * + * @return {@code true} if the operation succeeds, {@code false} otherwise + * + * TODO: deprecate this + */ + public boolean saveConfig() { + return sendSyncMessage(CMD_SAVE_CONFIG).boolValue; + } + + /** + * TODO: doc + */ + public void requestCmWakeLock() { + sendMessage(CMD_REQUEST_CM_WAKELOCK); + } + + /********************************************************* + * Internal private functions + ********************************************************/ + + class SyncReturn { + boolean boolValue; + int intValue; + String stringValue; + Object objValue; + List<WifiConfiguration> configList; + } + + class SyncParams { + Object mParameter; + SyncReturn mSyncReturn; + SyncParams() { + mSyncReturn = new SyncReturn(); + } + SyncParams(Object p) { + mParameter = p; + mSyncReturn = new SyncReturn(); + } + } + + /** + * message.arg2 is reserved to indicate synchronized + * message.obj is used to store SyncParams + */ + private SyncReturn syncedSend(Message msg) { + SyncParams syncParams = (SyncParams) msg.obj; + msg.arg2 = SYNCHRONOUS_CALL; + synchronized(syncParams) { + if (DBG) Log.d(TAG, "syncedSend " + msg); + sendMessage(msg); + try { + syncParams.wait(); + } catch (InterruptedException e) { + Log.e(TAG, "sendSyncMessage: unexpected interruption of wait()"); + return null; + } + } + return syncParams.mSyncReturn; + } + + private SyncReturn sendSyncMessage(Message msg) { + SyncParams syncParams = new SyncParams(); + msg.obj = syncParams; + return syncedSend(msg); + } + + private SyncReturn sendSyncMessage(int what, Object param) { + SyncParams syncParams = new SyncParams(param); + Message msg = obtainMessage(what, syncParams); + return syncedSend(msg); + } + + + private SyncReturn sendSyncMessage(int what) { + return sendSyncMessage(obtainMessage(what)); + } + + private void notifyOnMsgObject(Message msg) { + SyncParams syncParams = (SyncParams) msg.obj; + if (syncParams != null) { + synchronized(syncParams) { + if (DBG) Log.d(TAG, "notifyOnMsgObject " + msg); + syncParams.notify(); + } + } + else { + Log.e(TAG, "Error! syncParams in notifyOnMsgObject is null"); + } + } + + private void setWifiState(int wifiState) { + final int previousWifiState = mWifiState.get(); + + try { + if (wifiState == WIFI_STATE_ENABLED) { + mBatteryStats.noteWifiOn(mLastEnableUid.get()); + } else if (wifiState == WIFI_STATE_DISABLED) { + mBatteryStats.noteWifiOff(mLastEnableUid.get()); + } + } catch (RemoteException e) { + Log.e(TAG, "Failed to note battery stats in wifi"); + } + + mWifiState.set(wifiState); + + if (DBG) Log.d(TAG, "setWifiState: " + getWifiStateByName()); + + 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); + intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); + mContext.sendStickyBroadcast(intent); + } + + private void setWifiApState(int wifiApState) { + final int previousWifiApState = mWifiApState.get(); + + try { + if (wifiApState == WIFI_AP_STATE_ENABLED) { + mBatteryStats.noteWifiOn(mLastApEnableUid.get()); + } else if (wifiApState == WIFI_AP_STATE_DISABLED) { + mBatteryStats.noteWifiOff(mLastApEnableUid.get()); + } + } catch (RemoteException e) { + Log.d(TAG, "Failed to note battery stats in wifi"); + } + + // Update state + mWifiApState.set(wifiApState); + + if (DBG) Log.d(TAG, "setWifiApState: " + getWifiApStateByName()); + + final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); + intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); + mContext.sendStickyBroadcast(intent); + } + + /** + * Parse the scan result line passed to us by wpa_supplicant (helper). + * @param line the line to parse + * @return the {@link ScanResult} object + */ + private ScanResult parseScanResult(String line) { + ScanResult scanResult = null; + if (line != null) { + /* + * Cache implementation (LinkedHashMap) is not synchronized, thus, + * must synchronized here! + */ + synchronized (mScanResultCache) { + String[] result = scanResultPattern.split(line); + if (3 <= result.length && result.length <= 5) { + String bssid = result[0]; + // bssid | frequency | level | flags | ssid + int frequency; + int level; + try { + frequency = Integer.parseInt(result[1]); + level = Integer.parseInt(result[2]); + /* some implementations avoid negative values by adding 256 + * so we need to adjust for that here. + */ + if (level > 0) level -= 256; + } catch (NumberFormatException e) { + frequency = 0; + level = 0; + } + + /* + * The formatting of the results returned by + * wpa_supplicant is intended to make the fields + * line up nicely when printed, + * not to make them easy to parse. So we have to + * apply some heuristics to figure out which field + * is the SSID and which field is the flags. + */ + String ssid; + String flags; + if (result.length == 4) { + if (result[3].charAt(0) == '[') { + flags = result[3]; + ssid = ""; + } else { + flags = ""; + ssid = result[3]; + } + } else if (result.length == 5) { + flags = result[3]; + ssid = result[4]; + } else { + // Here, we must have 3 fields: no flags and ssid + // set + flags = ""; + ssid = ""; + } + + // bssid + ssid is the hash key + String key = bssid + ssid; + scanResult = mScanResultCache.get(key); + if (scanResult != null) { + scanResult.level = level; + scanResult.SSID = ssid; + scanResult.capabilities = flags; + scanResult.frequency = frequency; + } else { + // Do not add scan results that have no SSID set + if (0 < ssid.trim().length()) { + scanResult = + new ScanResult( + ssid, bssid, flags, level, frequency); + mScanResultCache.put(key, scanResult); + } + } + } else { + Log.w(TAG, "Misformatted scan result text with " + + result.length + " fields: " + line); + } + } + } + + return scanResult; + } + + /** + * scanResults input format + * 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1 + * 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2 + */ + private void setScanResults(String scanResults) { + if (scanResults == null) { + return; + } + + List<ScanResult> scanList = new ArrayList<ScanResult>(); + + int lineCount = 0; + + int scanResultsLen = scanResults.length(); + // Parse the result string, keeping in mind that the last line does + // not end with a newline. + for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) { + if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') { + ++lineCount; + + if (lineCount == 1) { + lineBeg = lineEnd + 1; + continue; + } + if (lineEnd > lineBeg) { + String line = scanResults.substring(lineBeg, lineEnd); + ScanResult scanResult = parseScanResult(line); + if (scanResult != null) { + scanList.add(scanResult); + } else { + Log.w(TAG, "misformatted scan result for: " + line); + } + } + lineBeg = lineEnd + 1; + } + } + + mScanResults = scanList; + } + + private void configureNetworkProperties() { + try { + mNetworkProperties.setInterface(NetworkInterface.getByName(mInterfaceName)); + } catch (SocketException e) { + Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName + + ". e=" + e); + return; + } catch (NullPointerException e) { + Log.e(TAG, "NPE creating NetworkInterface. e=" + e); + return; + } + // TODO - fix this for v6 + try { + mNetworkProperties.addAddress(InetAddress.getByAddress( + NetworkUtils.v4IntToArray(mDhcpInfo.ipAddress))); + } catch (UnknownHostException e) { + Log.e(TAG, "Exception setting IpAddress using " + mDhcpInfo + ", e=" + e); + } + + try { + mNetworkProperties.setGateway(InetAddress.getByAddress(NetworkUtils.v4IntToArray( + mDhcpInfo.gateway))); + } catch (UnknownHostException e) { + Log.e(TAG, "Exception setting Gateway using " + mDhcpInfo + ", e=" + e); + } + + try { + mNetworkProperties.addDns(InetAddress.getByAddress( + NetworkUtils.v4IntToArray(mDhcpInfo.dns1))); + } catch (UnknownHostException e) { + Log.e(TAG, "Exception setting Dns1 using " + mDhcpInfo + ", e=" + e); + } + try { + mNetworkProperties.addDns(InetAddress.getByAddress( + NetworkUtils.v4IntToArray(mDhcpInfo.dns2))); + + } catch (UnknownHostException e) { + Log.e(TAG, "Exception setting Dns2 using " + mDhcpInfo + ", e=" + e); + } + // TODO - add proxy info + } + + + private void checkUseStaticIp() { + mUseStaticIp = false; + final ContentResolver cr = mContext.getContentResolver(); + try { + if (Settings.System.getInt(cr, Settings.System.WIFI_USE_STATIC_IP) == 0) { + return; + } + } catch (Settings.SettingNotFoundException e) { + return; + } + + try { + String addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_IP); + if (addr != null) { + mDhcpInfo.ipAddress = stringToIpAddr(addr); + } else { + return; + } + addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_GATEWAY); + if (addr != null) { + mDhcpInfo.gateway = stringToIpAddr(addr); + } else { + return; + } + addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_NETMASK); + if (addr != null) { + mDhcpInfo.netmask = stringToIpAddr(addr); + } else { + return; + } + addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS1); + if (addr != null) { + mDhcpInfo.dns1 = stringToIpAddr(addr); + } else { + return; + } + addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS2); + if (addr != null) { + mDhcpInfo.dns2 = stringToIpAddr(addr); + } else { + mDhcpInfo.dns2 = 0; + } + } catch (UnknownHostException e) { + return; + } + mUseStaticIp = true; + } + + private static int stringToIpAddr(String addrString) throws UnknownHostException { + try { + String[] parts = addrString.split("\\."); + if (parts.length != 4) { + throw new UnknownHostException(addrString); + } + + int a = Integer.parseInt(parts[0]) ; + int b = Integer.parseInt(parts[1]) << 8; + int c = Integer.parseInt(parts[2]) << 16; + int d = Integer.parseInt(parts[3]) << 24; + + return a | b | c | d; + } catch (NumberFormatException ex) { + throw new UnknownHostException(addrString); + } + } + + private int getMaxDhcpRetries() { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT, + DEFAULT_MAX_DHCP_RETRIES); + } + + private class SettingsObserver extends ContentObserver { + public SettingsObserver(Handler handler) { + super(handler); + ContentResolver cr = mContext.getContentResolver(); + cr.registerContentObserver(Settings.System.getUriFor( + Settings.System.WIFI_USE_STATIC_IP), false, this); + cr.registerContentObserver(Settings.System.getUriFor( + Settings.System.WIFI_STATIC_IP), false, this); + cr.registerContentObserver(Settings.System.getUriFor( + Settings.System.WIFI_STATIC_GATEWAY), false, this); + cr.registerContentObserver(Settings.System.getUriFor( + Settings.System.WIFI_STATIC_NETMASK), false, this); + cr.registerContentObserver(Settings.System.getUriFor( + Settings.System.WIFI_STATIC_DNS1), false, this); + cr.registerContentObserver(Settings.System.getUriFor( + Settings.System.WIFI_STATIC_DNS2), false, this); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + + boolean wasStaticIp = mUseStaticIp; + int oIp, oGw, oMsk, oDns1, oDns2; + oIp = oGw = oMsk = oDns1 = oDns2 = 0; + if (wasStaticIp) { + oIp = mDhcpInfo.ipAddress; + oGw = mDhcpInfo.gateway; + oMsk = mDhcpInfo.netmask; + oDns1 = mDhcpInfo.dns1; + oDns2 = mDhcpInfo.dns2; + } + checkUseStaticIp(); + + if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED) { + return; + } + + boolean changed = + (wasStaticIp != mUseStaticIp) || + (wasStaticIp && ( + oIp != mDhcpInfo.ipAddress || + oGw != mDhcpInfo.gateway || + oMsk != mDhcpInfo.netmask || + oDns1 != mDhcpInfo.dns1 || + oDns2 != mDhcpInfo.dns2)); + + if (changed) { + sendMessage(CMD_RECONFIGURE_IP); + mConfigChanged = true; + } + } + } + + /** + * Whether to disable coexistence mode while obtaining IP address. This + * logic will return true only if the current bluetooth + * headset/handsfree state is disconnected. This means if it is in an + * error state, we will NOT disable coexistence mode to err on the side + * of safety. + * + * @return Whether to disable coexistence mode. + */ + private boolean shouldDisableCoexistenceMode() { + int state = mBluetoothHeadset.getState(mBluetoothHeadset.getCurrentHeadset()); + return state == BluetoothHeadset.STATE_DISCONNECTED; + } + + private void checkIsBluetoothPlaying() { + boolean isBluetoothPlaying = false; + Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks(); + + for (BluetoothDevice device : connected) { + if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) { + isBluetoothPlaying = true; + break; + } + } + setBluetoothScanMode(isBluetoothPlaying); + } + + private void sendScanResultsAvailableBroadcast() { + if (!ActivityManagerNative.isSystemReady()) return; + + mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); + } + + private void sendRssiChangeBroadcast(final int newRssi) { + if (!ActivityManagerNative.isSystemReady()) return; + + Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); + intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); + mContext.sendBroadcast(intent); + } + + private void sendNetworkStateChangeBroadcast(String bssid) { + Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT + | Intent.FLAG_RECEIVER_REPLACE_PENDING); + intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo); + intent.putExtra(WifiManager.EXTRA_NETWORK_PROPERTIES, mNetworkProperties); + if (bssid != null) + intent.putExtra(WifiManager.EXTRA_BSSID, bssid); + mContext.sendStickyBroadcast(intent); + } + + private void sendConfigChangeBroadcast() { + Intent intent = new Intent(WifiManager.CONFIG_CHANGED_ACTION); + intent.putExtra(WifiManager.EXTRA_NETWORK_PROPERTIES, mNetworkProperties); + mContext.sendBroadcast(intent); + } + + private void sendSupplicantStateChangedBroadcast(StateChangeResult sc, boolean failedAuth) { + Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT + | Intent.FLAG_RECEIVER_REPLACE_PENDING); + intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)sc.state); + if (failedAuth) { + intent.putExtra( + WifiManager.EXTRA_SUPPLICANT_ERROR, + WifiManager.ERROR_AUTHENTICATING); + } + mContext.sendStickyBroadcast(intent); + } + + private void sendSupplicantConnectionChangedBroadcast(boolean connected) { + if (!ActivityManagerNative.isSystemReady()) return; + + Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); + intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); + mContext.sendBroadcast(intent); + } + + /** + * Record the detailed state of a network. + * @param state the new @{code DetailedState} + */ + private void setDetailedState(NetworkInfo.DetailedState state) { + Log.d(TAG, "setDetailed state, old =" + + mNetworkInfo.getDetailedState() + " and new state=" + state); + if (state != mNetworkInfo.getDetailedState()) { + mNetworkInfo.setDetailedState(state, null, null); + } + } + + private static String removeDoubleQuotes(String string) { + if (string.length() <= 2) return ""; + return string.substring(1, string.length() - 1); + } + + private static String convertToQuotedString(String string) { + return "\"" + string + "\""; + } + + private static String makeString(BitSet set, String[] strings) { + StringBuffer buf = new StringBuffer(); + int nextSetBit = -1; + + /* Make sure all set bits are in [0, strings.length) to avoid + * going out of bounds on strings. (Shouldn't happen, but...) */ + set = set.get(0, strings.length); + + while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { + buf.append(strings[nextSetBit].replace('_', '-')).append(' '); + } + + // remove trailing space + if (set.cardinality() > 0) { + buf.setLength(buf.length() - 1); + } + + return buf.toString(); + } + + private static int lookupString(String string, String[] strings) { + int size = strings.length; + + string = string.replace('-', '_'); + + for (int i = 0; i < size; i++) + if (string.equals(strings[i])) + return i; + + // if we ever get here, we should probably add the + // value to WifiConfiguration to reflect that it's + // supported by the WPA supplicant + Log.w(TAG, "Failed to look-up a string: " + string); + + return -1; + } + + private int addOrUpdateNetworkNative(WifiConfiguration config) { + /* + * If the supplied networkId is -1, we create a new empty + * network configuration. Otherwise, the networkId should + * refer to an existing configuration. + */ + int netId = config.networkId; + boolean newNetwork = netId == -1; + // networkId of -1 means we want to create a new network + + if (newNetwork) { + netId = WifiNative.addNetworkCommand(); + if (netId < 0) { + Log.e(TAG, "Failed to add a network!"); + return -1; + } + } + + setVariables: { + + if (config.SSID != null && + !WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.ssidVarName, + config.SSID)) { + Log.d(TAG, "failed to set SSID: "+config.SSID); + break setVariables; + } + + if (config.BSSID != null && + !WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.bssidVarName, + config.BSSID)) { + Log.d(TAG, "failed to set BSSID: "+config.BSSID); + break setVariables; + } + + String allowedKeyManagementString = + makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); + if (config.allowedKeyManagement.cardinality() != 0 && + !WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.KeyMgmt.varName, + allowedKeyManagementString)) { + Log.d(TAG, "failed to set key_mgmt: "+ + allowedKeyManagementString); + break setVariables; + } + + String allowedProtocolsString = + makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); + if (config.allowedProtocols.cardinality() != 0 && + !WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.Protocol.varName, + allowedProtocolsString)) { + Log.d(TAG, "failed to set proto: "+ + allowedProtocolsString); + break setVariables; + } + + String allowedAuthAlgorithmsString = + makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); + if (config.allowedAuthAlgorithms.cardinality() != 0 && + !WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.AuthAlgorithm.varName, + allowedAuthAlgorithmsString)) { + Log.d(TAG, "failed to set auth_alg: "+ + allowedAuthAlgorithmsString); + break setVariables; + } + + String allowedPairwiseCiphersString = + makeString(config.allowedPairwiseCiphers, + WifiConfiguration.PairwiseCipher.strings); + if (config.allowedPairwiseCiphers.cardinality() != 0 && + !WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.PairwiseCipher.varName, + allowedPairwiseCiphersString)) { + Log.d(TAG, "failed to set pairwise: "+ + allowedPairwiseCiphersString); + break setVariables; + } + + String allowedGroupCiphersString = + makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); + if (config.allowedGroupCiphers.cardinality() != 0 && + !WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.GroupCipher.varName, + allowedGroupCiphersString)) { + Log.d(TAG, "failed to set group: "+ + allowedGroupCiphersString); + break setVariables; + } + + // Prevent client screw-up by passing in a WifiConfiguration we gave it + // by preventing "*" as a key. + if (config.preSharedKey != null && !config.preSharedKey.equals("*") && + !WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.pskVarName, + config.preSharedKey)) { + Log.d(TAG, "failed to set psk: "+config.preSharedKey); + break setVariables; + } + + boolean hasSetKey = false; + if (config.wepKeys != null) { + for (int i = 0; i < config.wepKeys.length; i++) { + // Prevent client screw-up by passing in a WifiConfiguration we gave it + // by preventing "*" as a key. + if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { + if (!WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.wepKeyVarNames[i], + config.wepKeys[i])) { + Log.d(TAG, + "failed to set wep_key"+i+": " + + config.wepKeys[i]); + break setVariables; + } + hasSetKey = true; + } + } + } + + if (hasSetKey) { + if (!WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.wepTxKeyIdxVarName, + Integer.toString(config.wepTxKeyIndex))) { + Log.d(TAG, + "failed to set wep_tx_keyidx: "+ + config.wepTxKeyIndex); + break setVariables; + } + } + + if (!WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.priorityVarName, + Integer.toString(config.priority))) { + Log.d(TAG, config.SSID + ": failed to set priority: " + +config.priority); + break setVariables; + } + + if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.hiddenSSIDVarName, + Integer.toString(config.hiddenSSID ? 1 : 0))) { + Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+ + config.hiddenSSID); + break setVariables; + } + + for (WifiConfiguration.EnterpriseField field + : config.enterpriseFields) { + String varName = field.varName(); + String value = field.value(); + if (value != null) { + if (field != config.eap) { + value = (value.length() == 0) ? "NULL" : convertToQuotedString(value); + } + if (!WifiNative.setNetworkVariableCommand( + netId, + varName, + value)) { + Log.d(TAG, config.SSID + ": failed to set " + varName + + ": " + value); + break setVariables; + } + } + } + return netId; + } + + if (newNetwork) { + WifiNative.removeNetworkCommand(netId); + Log.d(TAG, + "Failed to set a network variable, removed network: " + + netId); + } + + return -1; + } + + private List<WifiConfiguration> getConfiguredNetworksNative() { + String listStr = WifiNative.listNetworksCommand(); + + List<WifiConfiguration> networks = + new ArrayList<WifiConfiguration>(); + if (listStr == null) + return networks; + + String[] lines = listStr.split("\n"); + // Skip the first line, which is a header + for (int i = 1; i < lines.length; i++) { + String[] result = lines[i].split("\t"); + // network-id | ssid | bssid | flags + WifiConfiguration config = new WifiConfiguration(); + try { + config.networkId = Integer.parseInt(result[0]); + } catch(NumberFormatException e) { + continue; + } + if (result.length > 3) { + if (result[3].indexOf("[CURRENT]") != -1) + config.status = WifiConfiguration.Status.CURRENT; + else if (result[3].indexOf("[DISABLED]") != -1) + config.status = WifiConfiguration.Status.DISABLED; + else + config.status = WifiConfiguration.Status.ENABLED; + } else { + config.status = WifiConfiguration.Status.ENABLED; + } + readNetworkVariables(config); + networks.add(config); + } + return networks; + } + + /** + * Read the variables from the supplicant daemon that are needed to + * fill in the WifiConfiguration object. + * + * @param config the {@link WifiConfiguration} object to be filled in. + */ + private void readNetworkVariables(WifiConfiguration config) { + + int netId = config.networkId; + if (netId < 0) + return; + + /* + * TODO: maybe should have a native method that takes an array of + * variable names and returns an array of values. But we'd still + * be doing a round trip to the supplicant daemon for each variable. + */ + String value; + + value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName); + if (!TextUtils.isEmpty(value)) { + config.SSID = removeDoubleQuotes(value); + } else { + config.SSID = null; + } + + value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName); + if (!TextUtils.isEmpty(value)) { + config.BSSID = value; + } else { + config.BSSID = null; + } + + value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName); + config.priority = -1; + if (!TextUtils.isEmpty(value)) { + try { + config.priority = Integer.parseInt(value); + } catch (NumberFormatException ignore) { + } + } + + value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName); + config.hiddenSSID = false; + if (!TextUtils.isEmpty(value)) { + try { + config.hiddenSSID = Integer.parseInt(value) != 0; + } catch (NumberFormatException ignore) { + } + } + + value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName); + config.wepTxKeyIndex = -1; + if (!TextUtils.isEmpty(value)) { + try { + config.wepTxKeyIndex = Integer.parseInt(value); + } catch (NumberFormatException ignore) { + } + } + + for (int i = 0; i < 4; i++) { + value = WifiNative.getNetworkVariableCommand(netId, + WifiConfiguration.wepKeyVarNames[i]); + if (!TextUtils.isEmpty(value)) { + config.wepKeys[i] = value; + } else { + config.wepKeys[i] = null; + } + } + + value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName); + if (!TextUtils.isEmpty(value)) { + config.preSharedKey = value; + } else { + config.preSharedKey = null; + } + + value = WifiNative.getNetworkVariableCommand(config.networkId, + WifiConfiguration.Protocol.varName); + if (!TextUtils.isEmpty(value)) { + String vals[] = value.split(" "); + for (String val : vals) { + int index = + lookupString(val, WifiConfiguration.Protocol.strings); + if (0 <= index) { + config.allowedProtocols.set(index); + } + } + } + + value = WifiNative.getNetworkVariableCommand(config.networkId, + WifiConfiguration.KeyMgmt.varName); + if (!TextUtils.isEmpty(value)) { + String vals[] = value.split(" "); + for (String val : vals) { + int index = + lookupString(val, WifiConfiguration.KeyMgmt.strings); + if (0 <= index) { + config.allowedKeyManagement.set(index); + } + } + } + + value = WifiNative.getNetworkVariableCommand(config.networkId, + WifiConfiguration.AuthAlgorithm.varName); + if (!TextUtils.isEmpty(value)) { + String vals[] = value.split(" "); + for (String val : vals) { + int index = + lookupString(val, WifiConfiguration.AuthAlgorithm.strings); + if (0 <= index) { + config.allowedAuthAlgorithms.set(index); + } + } + } + + value = WifiNative.getNetworkVariableCommand(config.networkId, + WifiConfiguration.PairwiseCipher.varName); + if (!TextUtils.isEmpty(value)) { + String vals[] = value.split(" "); + for (String val : vals) { + int index = + lookupString(val, WifiConfiguration.PairwiseCipher.strings); + if (0 <= index) { + config.allowedPairwiseCiphers.set(index); + } + } + } + + value = WifiNative.getNetworkVariableCommand(config.networkId, + WifiConfiguration.GroupCipher.varName); + if (!TextUtils.isEmpty(value)) { + String vals[] = value.split(" "); + for (String val : vals) { + int index = + lookupString(val, WifiConfiguration.GroupCipher.strings); + if (0 <= index) { + config.allowedGroupCiphers.set(index); + } + } + } + + for (WifiConfiguration.EnterpriseField field : + config.enterpriseFields) { + value = WifiNative.getNetworkVariableCommand(netId, + field.varName()); + if (!TextUtils.isEmpty(value)) { + if (field != config.eap) value = removeDoubleQuotes(value); + field.setValue(value); + } + } + + } + + /** + * Poll for info not reported via events + * RSSI & Linkspeed + */ + private void requestPolledInfo() { + int newRssi = WifiNative.getRssiCommand(); + if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values + /* some implementations avoid negative values by adding 256 + * so we need to adjust for that here. + */ + if (newRssi > 0) newRssi -= 256; + mWifiInfo.setRssi(newRssi); + /* + * Rather then sending the raw RSSI out every time it + * changes, we precalculate the signal level that would + * be displayed in the status bar, and only send the + * broadcast if that much more coarse-grained number + * changes. This cuts down greatly on the number of + * broadcasts, at the cost of not mWifiInforming others + * interested in RSSI of all the changes in signal + * level. + */ + // TODO: The second arg to the call below needs to be a symbol somewhere, but + // it's actually the size of an array of icons that's private + // to StatusBar Policy. + int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4); + if (newSignalLevel != mLastSignalLevel) { + sendRssiChangeBroadcast(newRssi); + } + mLastSignalLevel = newSignalLevel; + } else { + mWifiInfo.setRssi(-200); + } + int newLinkSpeed = WifiNative.getLinkSpeedCommand(); + if (newLinkSpeed != -1) { + mWifiInfo.setLinkSpeed(newLinkSpeed); + } + } + + /** + * Resets the Wi-Fi Connections by clearing any state, resetting any sockets + * using the interface, stopping DHCP & disabling interface + */ + private void handleNetworkDisconnect() { + Log.d(TAG, "Reset connections and stopping DHCP"); + + /* + * Reset connections & stop DHCP + */ + NetworkUtils.resetConnections(mInterfaceName); + + if (!NetworkUtils.stopDhcp(mInterfaceName)) { + Log.e(TAG, "Could not stop DHCP"); + } + + /* Disable interface */ + NetworkUtils.disableInterface(mInterfaceName); + + /* send event to CM & network change broadcast */ + setDetailedState(DetailedState.DISCONNECTED); + sendNetworkStateChangeBroadcast(mLastBssid); + + /* Reset data structures */ + mWifiInfo.setIpAddress(0); + mWifiInfo.setBSSID(null); + mWifiInfo.setSSID(null); + mWifiInfo.setNetworkId(-1); + + /* Clear network properties */ + mNetworkProperties.clear(); + + mLastBssid= null; + mLastNetworkId = -1; + + } + + + /********************************************************* + * Notifications from WifiMonitor + ********************************************************/ + + /** + * A structure for supplying information about a supplicant state + * change in the STATE_CHANGE event message that comes from the + * WifiMonitor + * thread. + */ + private static class StateChangeResult { + StateChangeResult(int networkId, String BSSID, Object state) { + this.state = state; + this.BSSID = BSSID; + this.networkId = networkId; + } + int networkId; + String BSSID; + Object state; + } + + /** + * Send the tracker a notification that a user-entered password key + * may be incorrect (i.e., caused authentication to fail). + */ + void notifyPasswordKeyMayBeIncorrect() { + sendMessage(PASSWORD_MAY_BE_INCORRECT_EVENT); + } + + /** + * Send the tracker a notification that a connection to the supplicant + * daemon has been established. + */ + void notifySupplicantConnection() { + sendMessage(SUP_CONNECTION_EVENT); + } + + /** + * Send the tracker a notification that a connection to the supplicant + * daemon has been established. + */ + void notifySupplicantLost() { + sendMessage(SUP_DISCONNECTION_EVENT); + } + + /** + * Send the tracker a notification that the state of Wifi connectivity + * has changed. + * @param networkId the configured network on which the state change occurred + * @param newState the new network state + * @param BSSID when the new state is {@link DetailedState#CONNECTED + * NetworkInfo.DetailedState.CONNECTED}, + * this is the MAC address of the access point. Otherwise, it + * is {@code null}. + */ + void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) { + if (newState == NetworkInfo.DetailedState.CONNECTED) { + sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT, + new StateChangeResult(networkId, BSSID, newState))); + } else { + sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT, + new StateChangeResult(networkId, BSSID, newState))); + } + } + + /** + * Send the tracker a notification that the state of the supplicant + * has changed. + * @param networkId the configured network on which the state change occurred + * @param newState the new {@code SupplicantState} + */ + void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) { + sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, + new StateChangeResult(networkId, BSSID, newState))); + } + + /** + * Send the tracker a notification that a scan has completed, and results + * are available. + */ + void notifyScanResultsAvailable() { + /** + * Switch scan mode over to passive. + * Turning off scan-only mode happens only in "Connect" mode + */ + setScanType(false); + sendMessage(SCAN_RESULTS_EVENT); + } + + void notifyDriverStarted() { + sendMessage(DRIVER_START_EVENT); + } + + void notifyDriverStopped() { + sendMessage(DRIVER_STOP_EVENT); + } + + void notifyDriverHung() { + setWifiEnabled(false); + setWifiEnabled(true); + } + + + /******************************************************** + * HSM states + *******************************************************/ + + class DefaultState extends HierarchicalState { + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + SyncParams syncParams; + switch (message.what) { + /* Synchronous call returns */ + case CMD_PING_SUPPLICANT: + case CMD_START_SCAN: + case CMD_DISCONNECT: + case CMD_RECONNECT: + case CMD_REASSOCIATE: + case CMD_REMOVE_NETWORK: + case CMD_ENABLE_NETWORK: + case CMD_DISABLE_NETWORK: + case CMD_ADD_OR_UPDATE_NETWORK: + case CMD_GET_RSSI: + case CMD_GET_RSSI_APPROX: + case CMD_GET_LINK_SPEED: + case CMD_GET_MAC_ADDR: + case CMD_SAVE_CONFIG: + case CMD_CONNECTION_STATUS: + case CMD_GET_NETWORK_CONFIG: + if (message.arg2 == SYNCHRONOUS_CALL) { + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = false; + syncParams.mSyncReturn.intValue = -1; + syncParams.mSyncReturn.stringValue = null; + syncParams.mSyncReturn.configList = null; + notifyOnMsgObject(message); + } + break; + case CMD_ENABLE_RSSI_POLL: + mEnableRssiPolling = (message.arg1 == 1); + mSupplicantStateTracker.sendMessage(CMD_ENABLE_RSSI_POLL); + break; + /* Discard */ + case CMD_LOAD_DRIVER: + case CMD_UNLOAD_DRIVER: + case CMD_START_SUPPLICANT: + case CMD_STOP_SUPPLICANT: + case CMD_START_DRIVER: + case CMD_STOP_DRIVER: + case CMD_START_AP: + case CMD_STOP_AP: + case CMD_RECONFIGURE_IP: + case SUP_CONNECTION_EVENT: + case SUP_DISCONNECTION_EVENT: + case DRIVER_START_EVENT: + case DRIVER_STOP_EVENT: + case DRIVER_HUNG_EVENT: + case NETWORK_CONNECTION_EVENT: + case NETWORK_DISCONNECTION_EVENT: + case SCAN_RESULTS_EVENT: + case SUPPLICANT_STATE_CHANGE_EVENT: + case PASSWORD_MAY_BE_INCORRECT_EVENT: + case CMD_BLACKLIST_NETWORK: + case CMD_CLEAR_BLACKLIST: + case CMD_SET_SCAN_MODE: + case CMD_SET_SCAN_TYPE: + case CMD_SET_POWER_MODE: + case CMD_SET_BLUETOOTH_COEXISTENCE: + case CMD_SET_BLUETOOTH_SCAN_MODE: + case CMD_SET_NUM_ALLOWED_CHANNELS: + case CMD_REQUEST_CM_WAKELOCK: + break; + default: + Log.e(TAG, "Error! unhandled message" + message); + break; + } + return HANDLED; + } + } + + class InitialState extends HierarchicalState { + @Override + //TODO: could move logging into a common class + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + // [31-8] Reserved for future use + // [7 - 0] HSM state change + // 50021 wifi_state_changed (custom|1|5) + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + + if (WifiNative.isDriverLoaded()) { + transitionTo(mDriverLoadedState); + } + else { + transitionTo(mDriverUnloadedState); + } + } + } + + class DriverLoadingState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + + final Message message = new Message(); + message.copyFrom(getCurrentMessage()); + /* TODO: add a timeout to fail when driver load is hung. + * Similarly for driver unload. + */ + new Thread(new Runnable() { + public void run() { + sWakeLock.acquire(); + //enabling state + switch(message.arg1) { + case WIFI_STATE_ENABLING: + setWifiState(WIFI_STATE_ENABLING); + break; + case WIFI_AP_STATE_ENABLING: + setWifiApState(WIFI_AP_STATE_ENABLING); + break; + } + + if(WifiNative.loadDriver()) { + Log.d(TAG, "Driver load successful"); + sendMessage(CMD_LOAD_DRIVER_SUCCESS); + } else { + Log.e(TAG, "Failed to load driver!"); + switch(message.arg1) { + case WIFI_STATE_ENABLING: + setWifiState(WIFI_STATE_UNKNOWN); + break; + case WIFI_AP_STATE_ENABLING: + setWifiApState(WIFI_AP_STATE_FAILED); + break; + } + sendMessage(CMD_LOAD_DRIVER_FAILURE); + } + sWakeLock.release(); + } + }).start(); + } + + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_LOAD_DRIVER_SUCCESS: + transitionTo(mDriverLoadedState); + break; + case CMD_LOAD_DRIVER_FAILURE: + transitionTo(mDriverFailedState); + 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_POWER_MODE: + case CMD_SET_BLUETOOTH_COEXISTENCE: + case CMD_SET_BLUETOOTH_SCAN_MODE: + case CMD_SET_NUM_ALLOWED_CHANNELS: + case CMD_START_PACKET_FILTERING: + case CMD_STOP_PACKET_FILTERING: + deferMessage(message); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class DriverLoadedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch(message.what) { + case CMD_UNLOAD_DRIVER: + transitionTo(mDriverUnloadingState); + break; + case CMD_START_SUPPLICANT: + if(WifiNative.startSupplicant()) { + Log.d(TAG, "Supplicant start successful"); + mWifiMonitor.startMonitoring(); + setWifiState(WIFI_STATE_ENABLED); + transitionTo(mWaitForSupState); + } else { + Log.e(TAG, "Failed to start supplicant!"); + sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); + } + break; + case CMD_START_AP: + try { + nwService.startAccessPoint((WifiConfiguration) message.obj, + mInterfaceName, + SOFTAP_IFACE); + } catch(Exception e) { + Log.e(TAG, "Exception in startAccessPoint()"); + sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0)); + break; + } + Log.d(TAG, "Soft AP start successful"); + setWifiApState(WIFI_AP_STATE_ENABLED); + transitionTo(mSoftApStartedState); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class DriverUnloadingState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + + final Message message = new Message(); + message.copyFrom(getCurrentMessage()); + new Thread(new Runnable() { + public void run() { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + sWakeLock.acquire(); + if(WifiNative.unloadDriver()) { + Log.d(TAG, "Driver unload successful"); + sendMessage(CMD_UNLOAD_DRIVER_SUCCESS); + + switch(message.arg1) { + case WIFI_STATE_DISABLED: + case WIFI_STATE_UNKNOWN: + setWifiState(message.arg1); + break; + case WIFI_AP_STATE_DISABLED: + case WIFI_AP_STATE_FAILED: + setWifiApState(message.arg1); + break; + } + } else { + Log.e(TAG, "Failed to unload driver!"); + sendMessage(CMD_UNLOAD_DRIVER_FAILURE); + + switch(message.arg1) { + case WIFI_STATE_DISABLED: + case WIFI_STATE_UNKNOWN: + setWifiState(WIFI_STATE_UNKNOWN); + break; + case WIFI_AP_STATE_DISABLED: + case WIFI_AP_STATE_FAILED: + setWifiApState(WIFI_AP_STATE_FAILED); + break; + } + } + sWakeLock.release(); + } + }).start(); + } + + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_UNLOAD_DRIVER_SUCCESS: + transitionTo(mDriverUnloadedState); + break; + case CMD_UNLOAD_DRIVER_FAILURE: + transitionTo(mDriverFailedState); + 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_POWER_MODE: + case CMD_SET_BLUETOOTH_COEXISTENCE: + case CMD_SET_BLUETOOTH_SCAN_MODE: + case CMD_SET_NUM_ALLOWED_CHANNELS: + case CMD_START_PACKET_FILTERING: + case CMD_STOP_PACKET_FILTERING: + deferMessage(message); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class DriverUnloadedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_LOAD_DRIVER: + transitionTo(mDriverLoadingState); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class DriverFailedState extends HierarchicalState { + @Override + public void enter() { + Log.e(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + return NOT_HANDLED; + } + } + + + class WaitForSupState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch(message.what) { + case SUP_CONNECTION_EVENT: + Log.d(TAG, "Supplicant connection established"); + mSupplicantStateTracker.resetSupplicantState(); + /* Initialize data structures */ + mLastBssid = null; + mLastNetworkId = -1; + mLastSignalLevel = -1; + + mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand()); + + //TODO: initialize and fix multicast filtering + //mWM.initializeMulticastFiltering(); + + if (mBluetoothA2dp == null) { + mBluetoothA2dp = new BluetoothA2dp(mContext); + } + checkIsBluetoothPlaying(); + + checkUseStaticIp(); + sendSupplicantConnectionChangedBroadcast(true); + transitionTo(mDriverSupReadyState); + break; + case CMD_STOP_SUPPLICANT: + Log.d(TAG, "Stop supplicant received"); + WifiNative.stopSupplicant(); + transitionTo(mDriverLoadedState); + break; + /* Fail soft ap when waiting for supplicant start */ + case CMD_START_AP: + Log.d(TAG, "Failed to start soft AP with a running supplicant"); + setWifiApState(WIFI_AP_STATE_FAILED); + break; + case CMD_START_DRIVER: + case CMD_STOP_DRIVER: + case CMD_SET_SCAN_MODE: + case CMD_SET_SCAN_TYPE: + case CMD_SET_POWER_MODE: + case CMD_SET_BLUETOOTH_COEXISTENCE: + case CMD_SET_BLUETOOTH_SCAN_MODE: + case CMD_SET_NUM_ALLOWED_CHANNELS: + case CMD_START_PACKET_FILTERING: + case CMD_STOP_PACKET_FILTERING: + deferMessage(message); + break; + case CMD_STOP_AP: + case CMD_START_SUPPLICANT: + case CMD_UNLOAD_DRIVER: + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class DriverSupReadyState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + /* Initialize for connect mode operation at start */ + mIsScanMode = false; + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + SyncParams syncParams; + switch(message.what) { + case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ + Log.d(TAG, "Stop supplicant received"); + WifiNative.stopSupplicant(); + //$FALL-THROUGH$ + case SUP_DISCONNECTION_EVENT: /* Supplicant died */ + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + WifiNative.closeSupplicantConnection(); + handleNetworkDisconnect(); + sendSupplicantConnectionChangedBroadcast(false); + mSupplicantStateTracker.resetSupplicantState(); + transitionTo(mDriverLoadedState); + + /* When supplicant dies, unload driver and enter failed state */ + //TODO: consider bringing up supplicant again + if (message.what == SUP_DISCONNECTION_EVENT) { + Log.d(TAG, "Supplicant died, unloading driver"); + sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); + } + break; + case CMD_START_DRIVER: + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + WifiNative.startDriverCommand(); + transitionTo(mDriverStartingState); + break; + case SCAN_RESULTS_EVENT: + setScanResults(WifiNative.scanResultsCommand()); + sendScanResultsAvailableBroadcast(); + break; + case CMD_PING_SUPPLICANT: + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = WifiNative.pingCommand(); + notifyOnMsgObject(message); + break; + case CMD_ADD_OR_UPDATE_NETWORK: + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + syncParams = (SyncParams) message.obj; + WifiConfiguration config = (WifiConfiguration) syncParams.mParameter; + syncParams.mSyncReturn.intValue = addOrUpdateNetworkNative(config); + notifyOnMsgObject(message); + break; + case CMD_REMOVE_NETWORK: + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + if (message.arg2 == SYNCHRONOUS_CALL) { + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = WifiNative.removeNetworkCommand( + message.arg1); + notifyOnMsgObject(message); + } else { + /* asynchronous handling */ + WifiNative.removeNetworkCommand(message.arg1); + } + break; + case CMD_ENABLE_NETWORK: + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + if (message.arg2 == SYNCHRONOUS_CALL) { + syncParams = (SyncParams) message.obj; + EnableNetParams enableNetParams = (EnableNetParams) syncParams.mParameter; + syncParams.mSyncReturn.boolValue = WifiNative.enableNetworkCommand( + enableNetParams.netId, enableNetParams.disableOthers); + notifyOnMsgObject(message); + } else { + /* asynchronous handling */ + WifiNative.enableNetworkCommand(message.arg1, message.arg2 == 1); + } + break; + case CMD_DISABLE_NETWORK: + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + if (message.arg2 == SYNCHRONOUS_CALL) { + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = WifiNative.disableNetworkCommand( + message.arg1); + notifyOnMsgObject(message); + } else { + /* asynchronous handling */ + WifiNative.disableNetworkCommand(message.arg1); + } + break; + case CMD_BLACKLIST_NETWORK: + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + WifiNative.addToBlacklistCommand((String)message.obj); + break; + case CMD_CLEAR_BLACKLIST: + WifiNative.clearBlacklistCommand(); + break; + case CMD_GET_NETWORK_CONFIG: + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.configList = getConfiguredNetworksNative(); + notifyOnMsgObject(message); + break; + case CMD_SAVE_CONFIG: + if (message.arg2 == SYNCHRONOUS_CALL) { + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = WifiNative.saveConfigCommand(); + notifyOnMsgObject(message); + } else { + /* asynchronous handling */ + WifiNative.saveConfigCommand(); + } + // Inform the backup manager about a data change + IBackupManager ibm = IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + if (ibm != null) { + try { + ibm.dataChanged("com.android.providers.settings"); + } catch (Exception e) { + // Try again later + } + } + break; + case CMD_CONNECTION_STATUS: + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.stringValue = WifiNative.statusCommand(); + notifyOnMsgObject(message); + break; + case CMD_GET_MAC_ADDR: + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.stringValue = WifiNative.getMacAddressCommand(); + notifyOnMsgObject(message); + break; + /* Cannot start soft AP while in client mode */ + case CMD_START_AP: + Log.d(TAG, "Failed to start soft AP with a running supplicant"); + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + setWifiApState(WIFI_AP_STATE_FAILED); + break; + case CMD_SET_SCAN_MODE: + mIsScanMode = (message.arg1 == SCAN_ONLY_MODE); + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + } + + class DriverStartingState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch(message.what) { + case DRIVER_START_EVENT: + transitionTo(mDriverStartedState); + break; + /* Queue driver commands & connection events */ + case CMD_START_DRIVER: + case CMD_STOP_DRIVER: + case SUPPLICANT_STATE_CHANGE_EVENT: + case NETWORK_CONNECTION_EVENT: + case NETWORK_DISCONNECTION_EVENT: + case PASSWORD_MAY_BE_INCORRECT_EVENT: + case CMD_SET_SCAN_TYPE: + case CMD_SET_POWER_MODE: + case CMD_SET_BLUETOOTH_COEXISTENCE: + case CMD_SET_BLUETOOTH_SCAN_MODE: + case CMD_SET_NUM_ALLOWED_CHANNELS: + case CMD_START_PACKET_FILTERING: + case CMD_STOP_PACKET_FILTERING: + deferMessage(message); + break; + /* Queue the asynchronous version of these commands */ + case CMD_START_SCAN: + case CMD_DISCONNECT: + case CMD_REASSOCIATE: + case CMD_RECONNECT: + if (message.arg2 != SYNCHRONOUS_CALL) { + deferMessage(message); + } + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class DriverStartedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + + try { + mBatteryStats.noteWifiRunning(); + } catch (RemoteException ignore) {} + + /* Initialize channel count */ + setNumAllowedChannels(); + + if (mIsScanMode) { + WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); + WifiNative.disconnectCommand(); + transitionTo(mScanModeState); + } else { + WifiNative.setScanResultHandlingCommand(CONNECT_MODE); + /* If supplicant has already connected, before we could finish establishing + * the control channel connection, we miss all the supplicant events. + * Disconnect and reconnect when driver has started to ensure we receive + * all supplicant events. + * + * TODO: This is a bit unclean, ideally the supplicant should never + * connect until told to do so by the framework + */ + WifiNative.disconnectCommand(); + WifiNative.reconnectCommand(); + transitionTo(mConnectModeState); + } + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + SyncParams syncParams; + switch(message.what) { + case CMD_SET_SCAN_TYPE: + if (message.arg1 == SCAN_ACTIVE) { + WifiNative.setScanModeCommand(true); + } else { + WifiNative.setScanModeCommand(false); + } + break; + case CMD_SET_POWER_MODE: + WifiNative.setPowerModeCommand(message.arg1); + break; + case CMD_SET_BLUETOOTH_COEXISTENCE: + WifiNative.setBluetoothCoexistenceModeCommand(message.arg1); + break; + case CMD_SET_BLUETOOTH_SCAN_MODE: + WifiNative.setBluetoothCoexistenceScanModeCommand(message.arg1 == 1); + break; + case CMD_SET_NUM_ALLOWED_CHANNELS: + mNumAllowedChannels = message.arg1; + WifiNative.setNumAllowedChannelsCommand(message.arg1); + break; + case CMD_START_DRIVER: + /* Ignore another driver start */ + break; + case CMD_STOP_DRIVER: + WifiNative.stopDriverCommand(); + transitionTo(mDriverStoppingState); + break; + case CMD_REQUEST_CM_WAKELOCK: + if (mCm == null) { + mCm = (ConnectivityManager)mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + } + mCm.requestNetworkTransitionWakelock(TAG); + break; + case CMD_START_PACKET_FILTERING: + WifiNative.startPacketFiltering(); + break; + case CMD_STOP_PACKET_FILTERING: + WifiNative.stopPacketFiltering(); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + @Override + public void exit() { + if (DBG) Log.d(TAG, getName() + "\n"); + try { + mBatteryStats.noteWifiStopped(); + } catch (RemoteException ignore) { } + } + } + + class DriverStoppingState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch(message.what) { + case DRIVER_STOP_EVENT: + transitionTo(mDriverStoppedState); + break; + /* Queue driver commands */ + case CMD_START_DRIVER: + case CMD_STOP_DRIVER: + case CMD_SET_SCAN_TYPE: + case CMD_SET_POWER_MODE: + case CMD_SET_BLUETOOTH_COEXISTENCE: + case CMD_SET_BLUETOOTH_SCAN_MODE: + case CMD_SET_NUM_ALLOWED_CHANNELS: + case CMD_START_PACKET_FILTERING: + case CMD_STOP_PACKET_FILTERING: + deferMessage(message); + break; + /* Queue the asynchronous version of these commands */ + case CMD_START_SCAN: + case CMD_DISCONNECT: + case CMD_REASSOCIATE: + case CMD_RECONNECT: + if (message.arg2 != SYNCHRONOUS_CALL) { + deferMessage(message); + } + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class DriverStoppedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + return NOT_HANDLED; + } + } + + class ScanModeState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + SyncParams syncParams; + switch(message.what) { + case CMD_SET_SCAN_MODE: + if (message.arg1 == SCAN_ONLY_MODE) { + /* Ignore */ + return HANDLED; + } else { + WifiNative.setScanResultHandlingCommand(message.arg1); + WifiNative.reconnectCommand(); + mIsScanMode = false; + transitionTo(mDisconnectedState); + } + break; + case CMD_START_SCAN: + if (message.arg2 == SYNCHRONOUS_CALL) { + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = WifiNative.scanCommand( + message.arg1 == SCAN_ACTIVE); + notifyOnMsgObject(message); + } else { + /* asynchronous handling */ + WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); + } + break; + /* Ignore */ + case CMD_DISCONNECT: + case CMD_RECONNECT: + case CMD_REASSOCIATE: + case SUPPLICANT_STATE_CHANGE_EVENT: + case NETWORK_CONNECTION_EVENT: + case NETWORK_DISCONNECTION_EVENT: + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class ConnectModeState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + SyncParams syncParams; + StateChangeResult stateChangeResult; + switch(message.what) { + case PASSWORD_MAY_BE_INCORRECT_EVENT: + mPasswordKeyMayBeIncorrect = true; + break; + case SUPPLICANT_STATE_CHANGE_EVENT: + stateChangeResult = (StateChangeResult) message.obj; + mSupplicantStateTracker.handleEvent(stateChangeResult); + break; + case CMD_START_SCAN: + if (message.arg2 == SYNCHRONOUS_CALL) { + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = true; + notifyOnMsgObject(message); + } + /* We need to set scan type in completed state */ + Message newMsg = obtainMessage(); + newMsg.copyFrom(message); + mSupplicantStateTracker.sendMessage(newMsg); + break; + /* Do a redundant disconnect without transition */ + case CMD_DISCONNECT: + if (message.arg2 == SYNCHRONOUS_CALL) { + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand(); + notifyOnMsgObject(message); + } else { + /* asynchronous handling */ + WifiNative.disconnectCommand(); + } + break; + case CMD_RECONNECT: + if (message.arg2 == SYNCHRONOUS_CALL) { + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = WifiNative.reconnectCommand(); + notifyOnMsgObject(message); + } else { + /* asynchronous handling */ + WifiNative.reconnectCommand(); + } + break; + case CMD_REASSOCIATE: + if (message.arg2 == SYNCHRONOUS_CALL) { + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = WifiNative.reassociateCommand(); + notifyOnMsgObject(message); + } else { + /* asynchronous handling */ + WifiNative.reassociateCommand(); + } + break; + case SCAN_RESULTS_EVENT: + /* Set the scan setting back to "connect" mode */ + WifiNative.setScanResultHandlingCommand(CONNECT_MODE); + /* Handle scan results */ + return NOT_HANDLED; + case NETWORK_CONNECTION_EVENT: + Log.d(TAG,"Network connection established"); + stateChangeResult = (StateChangeResult) message.obj; + + mWifiInfo.setBSSID(mLastBssid = stateChangeResult.BSSID); + mWifiInfo.setNetworkId(stateChangeResult.networkId); + mLastNetworkId = stateChangeResult.networkId; + + /* send event to CM & network change broadcast */ + setDetailedState(DetailedState.OBTAINING_IPADDR); + sendNetworkStateChangeBroadcast(mLastBssid); + + transitionTo(mConnectingState); + break; + case NETWORK_DISCONNECTION_EVENT: + Log.d(TAG,"Network connection lost"); + handleNetworkDisconnect(); + transitionTo(mDisconnectedState); + break; + case CMD_GET_RSSI: + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.intValue = WifiNative.getRssiCommand(); + notifyOnMsgObject(message); + break; + case CMD_GET_RSSI_APPROX: + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.intValue = WifiNative.getRssiApproxCommand(); + notifyOnMsgObject(message); + break; + case CMD_GET_LINK_SPEED: + syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.intValue = WifiNative.getLinkSpeedCommand(); + notifyOnMsgObject(message); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class ConnectingState extends HierarchicalState { + boolean modifiedBluetoothCoexistenceMode; + int powerMode; + Thread mDhcpThread; + + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + + if (!mUseStaticIp) { + + mDhcpThread = null; + modifiedBluetoothCoexistenceMode = false; + powerMode = DRIVER_POWER_MODE_AUTO; + + if (shouldDisableCoexistenceMode()) { + /* + * There are problems setting the Wi-Fi driver's power + * mode to active when bluetooth coexistence mode is + * enabled or sense. + * <p> + * We set Wi-Fi to active mode when + * obtaining an IP address because we've found + * compatibility issues with some routers with low power + * mode. + * <p> + * In order for this active power mode to properly be set, + * we disable coexistence mode until we're done with + * obtaining an IP address. One exception is if we + * are currently connected to a headset, since disabling + * coexistence would interrupt that connection. + */ + modifiedBluetoothCoexistenceMode = true; + + // Disable the coexistence mode + WifiNative.setBluetoothCoexistenceModeCommand( + WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); + } + + powerMode = WifiNative.getPowerModeCommand(); + if (powerMode < 0) { + // Handle the case where supplicant driver does not support + // getPowerModeCommand. + powerMode = DRIVER_POWER_MODE_AUTO; + } + if (powerMode != DRIVER_POWER_MODE_ACTIVE) { + WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE); + } + + Log.d(TAG, "DHCP request started"); + mDhcpThread = new Thread(new Runnable() { + public void run() { + if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) { + Log.d(TAG, "DHCP request succeeded"); + sendMessage(CMD_IP_CONFIG_SUCCESS); + } else { + Log.d(TAG, "DHCP request failed: " + + NetworkUtils.getDhcpError()); + sendMessage(CMD_IP_CONFIG_FAILURE); + } + } + }); + mDhcpThread.start(); + } else { + if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) { + Log.v(TAG, "Static IP configuration succeeded"); + sendMessage(CMD_IP_CONFIG_SUCCESS); + } else { + Log.v(TAG, "Static IP configuration failed"); + sendMessage(CMD_IP_CONFIG_FAILURE); + } + } + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + + switch(message.what) { + case CMD_IP_CONFIG_SUCCESS: + mReconnectCount = 0; + mLastSignalLevel = -1; // force update of signal strength + mWifiInfo.setIpAddress(mDhcpInfo.ipAddress); + Log.d(TAG, "IP configuration: " + mDhcpInfo); + configureNetworkProperties(); + setDetailedState(DetailedState.CONNECTED); + sendNetworkStateChangeBroadcast(mLastBssid); + //TODO: we could also detect an IP config change + // from a DHCP renewal and send out a config change + // broadcast + if (mConfigChanged) { + sendConfigChangeBroadcast(); + mConfigChanged = false; + } + transitionTo(mConnectedState); + break; + case CMD_IP_CONFIG_FAILURE: + mWifiInfo.setIpAddress(0); + + Log.e(TAG, "IP configuration failed"); + /** + * If we've exceeded the maximum number of retries for DHCP + * to a given network, disable the network + */ + if (++mReconnectCount > getMaxDhcpRetries()) { + Log.e(TAG, "Failed " + + mReconnectCount + " times, Disabling " + mLastNetworkId); + WifiNative.disableNetworkCommand(mLastNetworkId); + } + + /* DHCP times out after about 30 seconds, we do a + * disconnect and an immediate reconnect to try again + */ + WifiNative.disconnectCommand(); + WifiNative.reconnectCommand(); + transitionTo(mDisconnectingState); + break; + case CMD_DISCONNECT: + if (message.arg2 == SYNCHRONOUS_CALL) { + SyncParams syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand(); + notifyOnMsgObject(message); + } else { + /* asynchronous handling */ + WifiNative.disconnectCommand(); + } + transitionTo(mDisconnectingState); + break; + /* Ignore */ + case NETWORK_CONNECTION_EVENT: + break; + case CMD_STOP_DRIVER: + sendMessage(CMD_DISCONNECT); + deferMessage(message); + break; + case CMD_SET_SCAN_MODE: + if (message.arg1 == SCAN_ONLY_MODE) { + sendMessage(CMD_DISCONNECT); + deferMessage(message); + } + break; + case CMD_RECONFIGURE_IP: + deferMessage(message); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + + @Override + public void exit() { + /* reset power state & bluetooth coexistence if on DHCP */ + if (!mUseStaticIp) { + if (powerMode != DRIVER_POWER_MODE_ACTIVE) { + WifiNative.setPowerModeCommand(powerMode); + } + + if (modifiedBluetoothCoexistenceMode) { + // Set the coexistence mode back to its default value + WifiNative.setBluetoothCoexistenceModeCommand( + WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); + } + } + + } + } + + class ConnectedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_DISCONNECT: + if (message.arg2 == SYNCHRONOUS_CALL) { + SyncParams syncParams = (SyncParams) message.obj; + syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand(); + notifyOnMsgObject(message); + } else { + /* asynchronous handling */ + WifiNative.disconnectCommand(); + } + transitionTo(mDisconnectingState); + break; + case CMD_RECONFIGURE_IP: + Log.d(TAG,"Reconfiguring IP on connection"); + NetworkUtils.resetConnections(mInterfaceName); + transitionTo(mConnectingState); + break; + case CMD_STOP_DRIVER: + sendMessage(CMD_DISCONNECT); + deferMessage(message); + break; + case CMD_SET_SCAN_MODE: + if (message.arg1 == SCAN_ONLY_MODE) { + sendMessage(CMD_DISCONNECT); + deferMessage(message); + } + break; + /* Ignore */ + case NETWORK_CONNECTION_EVENT: + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class DisconnectingState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */ + deferMessage(message); + break; + case CMD_SET_SCAN_MODE: + if (message.arg1 == SCAN_ONLY_MODE) { + deferMessage(message); + } + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class DisconnectedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_SET_SCAN_MODE: + if (message.arg1 == SCAN_ONLY_MODE) { + WifiNative.setScanResultHandlingCommand(message.arg1); + //Supplicant disconnect to prevent further connects + WifiNative.disconnectCommand(); + mIsScanMode = true; + transitionTo(mScanModeState); + } + break; + /* Ignore network disconnect */ + case NETWORK_DISCONNECTION_EVENT: + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class SoftApStartedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch(message.what) { + case CMD_STOP_AP: + Log.d(TAG,"Stopping Soft AP"); + setWifiApState(WIFI_AP_STATE_DISABLING); + try { + nwService.stopAccessPoint(); + } catch(Exception e) { + Log.e(TAG, "Exception in stopAccessPoint()"); + } + transitionTo(mDriverLoadedState); + break; + case CMD_START_AP: + Log.d(TAG,"SoftAP set on a running access point"); + try { + nwService.setAccessPoint((WifiConfiguration) message.obj, + mInterfaceName, + SOFTAP_IFACE); + } catch(Exception e) { + Log.e(TAG, "Exception in nwService during soft AP set"); + try { + nwService.stopAccessPoint(); + } catch (Exception ee) { + Slog.e(TAG, "Could not stop AP, :" + ee); + } + sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0)); + } + break; + /* Fail client mode operation when soft AP is enabled */ + case CMD_START_SUPPLICANT: + Log.e(TAG,"Cannot start supplicant with a running soft AP"); + setWifiState(WIFI_STATE_UNKNOWN); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + + class SupplicantStateTracker extends HierarchicalStateMachine { + + private int mRssiPollToken = 0; + + /** + * The max number of the WPA supplicant loop iterations before we + * decide that the loop should be terminated: + */ + private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4; + private int mLoopDetectIndex = 0; + private int mLoopDetectCount = 0; + + /** + * Supplicant state change commands follow + * the ordinal values defined in SupplicantState.java + */ + private static final int DISCONNECTED = 0; + private static final int INACTIVE = 1; + private static final int SCANNING = 2; + private static final int ASSOCIATING = 3; + private static final int ASSOCIATED = 4; + private static final int FOUR_WAY_HANDSHAKE = 5; + private static final int GROUP_HANDSHAKE = 6; + private static final int COMPLETED = 7; + private static final int DORMANT = 8; + private static final int UNINITIALIZED = 9; + private static final int INVALID = 10; + + private HierarchicalState mUninitializedState = new UninitializedState(); + private HierarchicalState mInitializedState = new InitializedState();; + private HierarchicalState mInactiveState = new InactiveState(); + private HierarchicalState mDisconnectState = new DisconnectedState(); + private HierarchicalState mScanState = new ScanState(); + private HierarchicalState mConnectState = new ConnectState(); + private HierarchicalState mHandshakeState = new HandshakeState(); + private HierarchicalState mCompletedState = new CompletedState(); + private HierarchicalState mDormantState = new DormantState(); + + public SupplicantStateTracker(Context context, Handler target) { + super(TAG, target.getLooper()); + + addState(mUninitializedState); + addState(mInitializedState); + addState(mInactiveState, mInitializedState); + addState(mDisconnectState, mInitializedState); + addState(mScanState, mInitializedState); + addState(mConnectState, mInitializedState); + addState(mHandshakeState, mConnectState); + addState(mCompletedState, mConnectState); + addState(mDormantState, mInitializedState); + + setInitialState(mUninitializedState); + + //start the state machine + start(); + } + + public void handleEvent(StateChangeResult stateChangeResult) { + SupplicantState newState = (SupplicantState) stateChangeResult.state; + + // Supplicant state change + // [31-13] Reserved for future use + // [8 - 0] Supplicant state (as defined in SupplicantState.java) + // 50023 supplicant_state_changed (custom|1|5) + EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, newState.ordinal()); + + sendMessage(obtainMessage(newState.ordinal(), stateChangeResult)); + } + + public void resetSupplicantState() { + transitionTo(mUninitializedState); + } + + private void resetLoopDetection() { + mLoopDetectCount = 0; + mLoopDetectIndex = 0; + } + + private boolean handleTransition(Message msg) { + if (DBG) Log.d(TAG, getName() + msg.toString() + "\n"); + switch (msg.what) { + case DISCONNECTED: + transitionTo(mDisconnectState); + break; + case SCANNING: + transitionTo(mScanState); + break; + case ASSOCIATING: + StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; + /* BSSID is valid only in ASSOCIATING state */ + mWifiInfo.setBSSID(stateChangeResult.BSSID); + //$FALL-THROUGH$ + case ASSOCIATED: + case FOUR_WAY_HANDSHAKE: + case GROUP_HANDSHAKE: + transitionTo(mHandshakeState); + break; + case COMPLETED: + transitionTo(mCompletedState); + break; + case DORMANT: + transitionTo(mDormantState); + break; + case INACTIVE: + transitionTo(mInactiveState); + break; + case UNINITIALIZED: + case INVALID: + transitionTo(mUninitializedState); + break; + default: + return NOT_HANDLED; + } + StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; + SupplicantState supState = (SupplicantState) stateChangeResult.state; + setDetailedState(WifiInfo.getDetailedStateOf(supState)); + mWifiInfo.setSupplicantState(supState); + mWifiInfo.setNetworkId(stateChangeResult.networkId); + //TODO: Modify WifiMonitor to report SSID on events + //mWifiInfo.setSSID() + return HANDLED; + } + + /******************************************************** + * HSM states + *******************************************************/ + + class InitializedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + } + @Override + public boolean processMessage(Message message) { + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_START_SCAN: + WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); + break; + default: + if (DBG) Log.w(TAG, "Ignoring " + message); + break; + } + return HANDLED; + } + } + + class UninitializedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + mNetworkInfo.setIsAvailable(false); + resetLoopDetection(); + mPasswordKeyMayBeIncorrect = false; + } + @Override + public boolean processMessage(Message message) { + switch(message.what) { + default: + if (!handleTransition(message)) { + if (DBG) Log.w(TAG, "Ignoring " + message); + } + break; + } + return HANDLED; + } + @Override + public void exit() { + mNetworkInfo.setIsAvailable(true); + } + } + + class InactiveState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + Message message = getCurrentMessage(); + StateChangeResult stateChangeResult = (StateChangeResult) message.obj; + + mNetworkInfo.setIsAvailable(false); + resetLoopDetection(); + mPasswordKeyMayBeIncorrect = false; + + sendSupplicantStateChangedBroadcast(stateChangeResult, false); + } + @Override + public boolean processMessage(Message message) { + return handleTransition(message); + } + @Override + public void exit() { + mNetworkInfo.setIsAvailable(true); + } + } + + + class DisconnectedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + Message message = getCurrentMessage(); + StateChangeResult stateChangeResult = (StateChangeResult) message.obj; + + resetLoopDetection(); + + /* If a disconnect event happens after a password key failure + * event, disable the network + */ + if (mPasswordKeyMayBeIncorrect) { + Log.d(TAG, "Failed to authenticate, disabling network " + + mWifiInfo.getNetworkId()); + WifiNative.disableNetworkCommand(mWifiInfo.getNetworkId()); + mPasswordKeyMayBeIncorrect = false; + sendSupplicantStateChangedBroadcast(stateChangeResult, true); + } + else { + sendSupplicantStateChangedBroadcast(stateChangeResult, false); + } + } + @Override + public boolean processMessage(Message message) { + return handleTransition(message); + } + } + + class ScanState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + Message message = getCurrentMessage(); + StateChangeResult stateChangeResult = (StateChangeResult) message.obj; + + mPasswordKeyMayBeIncorrect = false; + resetLoopDetection(); + sendSupplicantStateChangedBroadcast(stateChangeResult, false); + } + @Override + public boolean processMessage(Message message) { + return handleTransition(message); + } + } + + class ConnectState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + } + @Override + public boolean processMessage(Message message) { + switch (message.what) { + case CMD_START_SCAN: + WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); + WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + } + + class HandshakeState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + final Message message = getCurrentMessage(); + StateChangeResult stateChangeResult = (StateChangeResult) message.obj; + + if (mLoopDetectIndex > message.what) { + mLoopDetectCount++; + } + if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) { + WifiNative.disableNetworkCommand(stateChangeResult.networkId); + mLoopDetectCount = 0; + } + + mLoopDetectIndex = message.what; + + mPasswordKeyMayBeIncorrect = false; + sendSupplicantStateChangedBroadcast(stateChangeResult, false); + } + @Override + public boolean processMessage(Message message) { + return handleTransition(message); + } + } + + class CompletedState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + Message message = getCurrentMessage(); + StateChangeResult stateChangeResult = (StateChangeResult) message.obj; + + mRssiPollToken++; + if (mEnableRssiPolling) { + sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), + POLL_RSSI_INTERVAL_MSECS); + } + + resetLoopDetection(); + + mPasswordKeyMayBeIncorrect = false; + sendSupplicantStateChangedBroadcast(stateChangeResult, false); + } + @Override + public boolean processMessage(Message message) { + switch(message.what) { + case ASSOCIATING: + case ASSOCIATED: + case FOUR_WAY_HANDSHAKE: + case GROUP_HANDSHAKE: + case COMPLETED: + break; + case CMD_RSSI_POLL: + if (message.arg1 == mRssiPollToken) { + // Get Info and continue polling + requestPolledInfo(); + sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), + POLL_RSSI_INTERVAL_MSECS); + } else { + // Polling has completed + } + break; + case CMD_ENABLE_RSSI_POLL: + mRssiPollToken++; + if (mEnableRssiPolling) { + // first poll + requestPolledInfo(); + sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), + POLL_RSSI_INTERVAL_MSECS); + } + break; + default: + return handleTransition(message); + } + return HANDLED; + } + } + + class DormantState extends HierarchicalState { + @Override + public void enter() { + if (DBG) Log.d(TAG, getName() + "\n"); + Message message = getCurrentMessage(); + StateChangeResult stateChangeResult = (StateChangeResult) message.obj; + + resetLoopDetection(); + mPasswordKeyMayBeIncorrect = false; + + sendSupplicantStateChangedBroadcast(stateChangeResult, false); + + /* TODO: reconnect is now being handled at DHCP failure handling + * If we run into issues with staying in Dormant state, might + * need a reconnect here + */ + } + @Override + public boolean processMessage(Message message) { + return handleTransition(message); + } + } + } +} diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 388beea..8e1b236 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -16,524 +16,59 @@ package android.net.wifi; -import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; -import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; -import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; -import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; -import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; -/** - * TODO: Add soft AP states as part of WIFI_STATE_XXX - * Retain WIFI_STATE_ENABLING that indicates driver is loading - * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started - * and WIFI_STATE_FAILED for failure - * Deprecate WIFI_STATE_UNKNOWN - * - * Doing this will simplify the logic for sending broadcasts - */ -import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; -import android.app.ActivityManagerNative; -import android.net.NetworkInfo; -import android.net.NetworkStateTracker; -import android.net.DhcpInfo; -import android.net.NetworkUtils; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.net.ConnectivityManager; -import android.net.NetworkInfo.DetailedState; -import android.net.NetworkInfo.State; +import android.net.NetworkInfo; import android.net.NetworkProperties; -import android.os.Binder; -import android.os.Message; -import android.os.Parcelable; +import android.net.NetworkStateTracker; import android.os.Handler; -import android.os.IBinder; -import android.os.INetworkManagementService; -import android.os.PowerManager; -import android.os.SystemProperties; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.Process; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.EventLog; -import android.util.Log; -import android.util.Slog; -import android.app.Notification; -import android.app.PendingIntent; -import android.app.backup.IBackupManager; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadset; -import android.bluetooth.BluetoothA2dp; -import android.content.ContentResolver; -import android.content.Intent; -import android.content.Context; -import android.database.ContentObserver; -import com.android.internal.app.IBatteryStats; -import com.android.internal.util.HierarchicalState; -import com.android.internal.util.HierarchicalStateMachine; +import android.os.Message; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.regex.Pattern; /** - * Track the state of Wifi connectivity. All event handling is done here, - * and all changes in connectivity state are initiated here. + * Track the state of wifi for connectivity service. * * @hide */ -//TODO: we still need frequent scanning for the case when -// we issue disconnect but need scan results for open network notification -public class WifiStateTracker extends HierarchicalStateMachine implements NetworkStateTracker { +public class WifiStateTracker implements NetworkStateTracker { - private static final String TAG = "WifiStateTracker"; private static final String NETWORKTYPE = "WIFI"; - private static final boolean DBG = false; - - /* TODO: fetch a configurable interface */ - private static final String SOFTAP_IFACE = "wl0.1"; - - private WifiMonitor mWifiMonitor; - private INetworkManagementService nwService; - private ConnectivityManager mCm; - - /* Scan results handling */ - private List<ScanResult> mScanResults; - private static final Pattern scanResultPattern = Pattern.compile("\t+"); - private static final int SCAN_RESULT_CACHE_SIZE = 80; - private final LinkedHashMap<String, ScanResult> mScanResultCache; + private static final String TAG = "WifiStateTracker"; - private String mInterfaceName; private AtomicBoolean mTeardownRequested = new AtomicBoolean(false); private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false); private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0); private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false); - private int mNumAllowedChannels = 0; - private int mLastSignalLevel = -1; - private String mLastBssid; - private int mLastNetworkId; - private boolean mEnableRssiPolling = false; - private boolean mPasswordKeyMayBeIncorrect = false; - private boolean mUseStaticIp = false; - private int mReconnectCount = 0; - private boolean mIsScanMode = false; - - /** - * Instance of the bluetooth headset helper. This needs to be created - * early because there is a delay before it actually 'connects', as - * noted by its javadoc. If we check before it is connected, it will be - * in an error state and we will not disable coexistence. - */ - private BluetoothHeadset mBluetoothHeadset; - - private BluetoothA2dp mBluetoothA2dp; - - /** - * Observes the static IP address settings. - */ - private SettingsObserver mSettingsObserver; private NetworkProperties mNetworkProperties; - - - // Variables relating to the 'available networks' notification - /** - * The icon to show in the 'available networks' notification. This will also - * be the ID of the Notification given to the NotificationManager. - */ - private static final int ICON_NETWORKS_AVAILABLE = - com.android.internal.R.drawable.stat_notify_wifi_in_range; - /** - * When a notification is shown, we wait this amount before possibly showing it again. - */ - private final long NOTIFICATION_REPEAT_DELAY_MS; - /** - * Whether the user has set the setting to show the 'available networks' notification. - */ - private boolean mNotificationEnabled; - /** - * Observes the user setting to keep {@link #mNotificationEnabled} in sync. - */ - private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver; - /** - * The {@link System#currentTimeMillis()} must be at least this value for us - * to show the notification again. - */ - private long mNotificationRepeatTime; - /** - * The Notification object given to the NotificationManager. - */ - private Notification mNotification; - /** - * Whether the notification is being shown, as set by us. That is, if the - * user cancels the notification, we will not receive the callback so this - * will still be true. We only guarantee if this is false, then the - * notification is not showing. - */ - private boolean mNotificationShown; - /** - * The number of continuous scans that must occur before consider the - * supplicant in a scanning state. This allows supplicant to associate with - * remembered networks that are in the scan results. - */ - private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3; - /** - * The number of scans since the last network state change. When this - * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the - * supplicant to actually be scanning. When the network state changes to - * something other than scanning, we reset this to 0. - */ - private int mNumScansSinceNetworkStateChange; - - // Held during driver load and unload - private static PowerManager.WakeLock sWakeLock; + private NetworkInfo mNetworkInfo; /* For sending events to connectivity service handler */ private Handler mCsHandler; private Context mContext; - - private DhcpInfo mDhcpInfo; - private WifiInfo mWifiInfo; - private NetworkInfo mNetworkInfo; - private SupplicantStateTracker mSupplicantStateTracker; - - // Event log tags (must be in sync with event-log-tags) - private static final int EVENTLOG_WIFI_STATE_CHANGED = 50021; - private static final int EVENTLOG_WIFI_EVENT_HANDLED = 50022; - private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED = 50023; - - /* Load the driver */ - private static final int CMD_LOAD_DRIVER = 1; - /* Unload the driver */ - private static final int CMD_UNLOAD_DRIVER = 2; - /* Indicates driver load succeeded */ - private static final int CMD_LOAD_DRIVER_SUCCESS = 3; - /* Indicates driver load failed */ - private static final int CMD_LOAD_DRIVER_FAILURE = 4; - /* Indicates driver unload succeeded */ - private static final int CMD_UNLOAD_DRIVER_SUCCESS = 5; - /* Indicates driver unload failed */ - private static final int CMD_UNLOAD_DRIVER_FAILURE = 6; - - /* Start the supplicant */ - private static final int CMD_START_SUPPLICANT = 11; - /* Stop the supplicant */ - private static final int CMD_STOP_SUPPLICANT = 12; - /* Start the driver */ - private static final int CMD_START_DRIVER = 13; - /* Start the driver */ - private static final int CMD_STOP_DRIVER = 14; - /* Indicates DHCP succeded */ - private static final int CMD_IP_CONFIG_SUCCESS = 15; - /* Indicates DHCP failed */ - private static final int CMD_IP_CONFIG_FAILURE = 16; - /* Re-configure interface */ - private static final int CMD_RECONFIGURE_IP = 17; - - - /* Start the soft access point */ - private static final int CMD_START_AP = 21; - /* Stop the soft access point */ - private static final int CMD_STOP_AP = 22; - - - /* Supplicant events */ - /* Connection to supplicant established */ - private static final int SUP_CONNECTION_EVENT = 31; - /* Connection to supplicant lost */ - private static final int SUP_DISCONNECTION_EVENT = 32; - /* Driver start completed */ - private static final int DRIVER_START_EVENT = 33; - /* Driver stop completed */ - private static final int DRIVER_STOP_EVENT = 34; - /* Network connection completed */ - private static final int NETWORK_CONNECTION_EVENT = 36; - /* Network disconnection completed */ - private static final int NETWORK_DISCONNECTION_EVENT = 37; - /* Scan results are available */ - private static final int SCAN_RESULTS_EVENT = 38; - /* Supplicate state changed */ - private static final int SUPPLICANT_STATE_CHANGE_EVENT = 39; - /* Password may be incorrect */ - private static final int PASSWORD_MAY_BE_INCORRECT_EVENT = 40; - - /* Supplicant commands */ - /* Is supplicant alive ? */ - private static final int CMD_PING_SUPPLICANT = 51; - /* Add/update a network configuration */ - private static final int CMD_ADD_OR_UPDATE_NETWORK = 52; - /* Delete a network */ - private static final int CMD_REMOVE_NETWORK = 53; - /* Enable a network. The device will attempt a connection to the given network. */ - private static final int CMD_ENABLE_NETWORK = 54; - /* Disable a network. The device does not attempt a connection to the given network. */ - private static final int CMD_DISABLE_NETWORK = 55; - /* Blacklist network. De-prioritizes the given BSSID for connection. */ - private static final int CMD_BLACKLIST_NETWORK = 56; - /* Clear the blacklist network list */ - private static final int CMD_CLEAR_BLACKLIST = 57; - /* Get the configured networks */ - private static final int CMD_GET_NETWORK_CONFIG = 58; - /* Save configuration */ - private static final int CMD_SAVE_CONFIG = 59; - /* Connection status */ - private static final int CMD_CONNECTION_STATUS = 60; - - /* Supplicant commands after driver start*/ - /* Initiate a scan */ - private static final int CMD_START_SCAN = 71; - /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */ - private static final int CMD_SET_SCAN_MODE = 72; - /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */ - private static final int CMD_SET_SCAN_TYPE = 73; - /* Disconnect from a network */ - private static final int CMD_DISCONNECT = 74; - /* Reconnect to a network */ - private static final int CMD_RECONNECT = 75; - /* Reassociate to a network */ - private static final int CMD_REASSOCIATE = 76; - /* Set power mode - * POWER_MODE_ACTIVE - * POWER_MODE_AUTO - */ - private static final int CMD_SET_POWER_MODE = 77; - /* Set bluetooth co-existence - * BLUETOOTH_COEXISTENCE_MODE_ENABLED - * BLUETOOTH_COEXISTENCE_MODE_DISABLED - * BLUETOOTH_COEXISTENCE_MODE_SENSE - */ - private static final int CMD_SET_BLUETOOTH_COEXISTENCE = 78; - /* Enable/disable bluetooth scan mode - * true(1) - * false(0) - */ - private static final int CMD_SET_BLUETOOTH_SCAN_MODE = 79; - /* Set number of allowed channels */ - private static final int CMD_SET_NUM_ALLOWED_CHANNELS = 80; - /* Request connectivity manager wake lock before driver stop */ - private static final int CMD_REQUEST_CM_WAKELOCK = 81; - /* Enables RSSI poll */ - private static final int CMD_ENABLE_RSSI_POLL = 82; - /* RSSI poll */ - private static final int CMD_RSSI_POLL = 83; - /* Get current RSSI */ - private static final int CMD_GET_RSSI = 84; - /* Get approx current RSSI */ - private static final int CMD_GET_RSSI_APPROX = 85; - /* Get link speed on connection */ - private static final int CMD_GET_LINK_SPEED = 86; - /* Radio mac address */ - private static final int CMD_GET_MAC_ADDR = 87; - /* Set up packet filtering */ - private static final int CMD_START_PACKET_FILTERING = 88; - /* Clear packet filter */ - private static final int CMD_STOP_PACKET_FILTERING = 89; - - /* Connectivity service commands */ - /* Bring down wifi connection */ - private static final int CM_CMD_TEARDOWN = 110; - /* Reconnect to wifi */ - private static final int CM_CMD_RECONNECT = 111; - - /** - * Interval in milliseconds between polling for connection - * status items that are not sent via asynchronous events. - * An example is RSSI (signal strength). - */ - private static final int POLL_RSSI_INTERVAL_MSECS = 3000; - - private static final int CONNECT_MODE = 1; - private static final int SCAN_ONLY_MODE = 2; - - private static final int SCAN_ACTIVE = 1; - private static final int SCAN_PASSIVE = 2; - - /** - * The maximum number of times we will retry a connection to an access point - * for which we have failed in acquiring an IP address from DHCP. A value of - * N means that we will make N+1 connection attempts in all. - * <p> - * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default - * value if a Settings value is not present. - */ - private static final int DEFAULT_MAX_DHCP_RETRIES = 9; - - private static final int DRIVER_POWER_MODE_ACTIVE = 1; - private static final int DRIVER_POWER_MODE_AUTO = 0; - - /* Default parent state */ - private HierarchicalState mDefaultState = new DefaultState(); - /* Temporary initial state */ - private HierarchicalState mInitialState = new InitialState(); - /* Unloading the driver */ - private HierarchicalState mDriverUnloadingState = new DriverUnloadingState(); - /* Loading the driver */ - private HierarchicalState mDriverUnloadedState = new DriverUnloadedState(); - /* Driver load/unload failed */ - private HierarchicalState mDriverFailedState = new DriverFailedState(); - /* Driver loading */ - private HierarchicalState mDriverLoadingState = new DriverLoadingState(); - /* Driver loaded */ - private HierarchicalState mDriverLoadedState = new DriverLoadedState(); - /* Driver loaded, waiting for supplicant to start */ - private HierarchicalState mWaitForSupState = new WaitForSupState(); - - /* Driver loaded and supplicant ready */ - private HierarchicalState mDriverSupReadyState = new DriverSupReadyState(); - /* Driver start issued, waiting for completed event */ - private HierarchicalState mDriverStartingState = new DriverStartingState(); - /* Driver started */ - private HierarchicalState mDriverStartedState = new DriverStartedState(); - /* Driver stopping */ - private HierarchicalState mDriverStoppingState = new DriverStoppingState(); - /* Driver stopped */ - private HierarchicalState mDriverStoppedState = new DriverStoppedState(); - /* Scan for networks, no connection will be established */ - private HierarchicalState mScanModeState = new ScanModeState(); - /* Connecting to an access point */ - private HierarchicalState mConnectModeState = new ConnectModeState(); - /* Fetching IP after network connection (assoc+auth complete) */ - private HierarchicalState mConnectingState = new ConnectingState(); - /* Connected with IP addr */ - private HierarchicalState mConnectedState = new ConnectedState(); - /* disconnect issued, waiting for network disconnect confirmation */ - private HierarchicalState mDisconnectingState = new DisconnectingState(); - /* Network is not connected, supplicant assoc+auth is not complete */ - private HierarchicalState mDisconnectedState = new DisconnectedState(); - - /* Soft Ap is running */ - private HierarchicalState mSoftApStartedState = new SoftApStartedState(); - - /* Argument for Message object to indicate a synchronous call */ - private static final int SYNCHRONOUS_CALL = 1; - private static final int ASYNCHRONOUS_CALL = 0; - - - /** - * One of {@link WifiManager#WIFI_STATE_DISABLED}, - * {@link WifiManager#WIFI_STATE_DISABLING}, - * {@link WifiManager#WIFI_STATE_ENABLED}, - * {@link WifiManager#WIFI_STATE_ENABLING}, - * {@link WifiManager#WIFI_STATE_UNKNOWN} - * - */ - private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); - - /** - * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, - * {@link WifiManager#WIFI_AP_STATE_DISABLING}, - * {@link WifiManager#WIFI_AP_STATE_ENABLED}, - * {@link WifiManager#WIFI_AP_STATE_ENABLING}, - * {@link WifiManager#WIFI_AP_STATE_FAILED} - * - */ - private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); - - private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid()); - private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid()); - - private final IBatteryStats mBatteryStats; + private BroadcastReceiver mWifiStateReceiver; + private WifiManager mWifiManager; public WifiStateTracker(Context context, Handler target) { - super(NETWORKTYPE); - mCsHandler = target; mContext = context; mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); - mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); - - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - nwService = INetworkManagementService.Stub.asInterface(b); - - mWifiMonitor = new WifiMonitor(this); - mDhcpInfo = new DhcpInfo(); - mWifiInfo = new WifiInfo(); - mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0"); - mSupplicantStateTracker = new SupplicantStateTracker(context, getHandler()); - - mBluetoothHeadset = new BluetoothHeadset(mContext, null); mNetworkProperties = new NetworkProperties(); mNetworkInfo.setIsAvailable(false); mNetworkProperties.clear(); - resetNotificationTimer(); setTeardownRequested(false); - mLastBssid = null; - mLastNetworkId = -1; - mLastSignalLevel = -1; - - mScanResultCache = new LinkedHashMap<String, ScanResult>( - SCAN_RESULT_CACHE_SIZE, 0.75f, true) { - /* - * Limit the cache size by SCAN_RESULT_CACHE_SIZE - * elements - */ - @Override - public boolean removeEldestEntry(Map.Entry eldest) { - return SCAN_RESULT_CACHE_SIZE < this.size(); - } - }; - - // Setting is in seconds - NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(), - Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l; - mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(target); - mNotificationEnabledSettingObserver.register(); - - mSettingsObserver = new SettingsObserver(new Handler()); - - PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); - sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - - addState(mDefaultState); - addState(mInitialState, mDefaultState); - addState(mDriverUnloadingState, mDefaultState); - addState(mDriverUnloadedState, mDefaultState); - addState(mDriverFailedState, mDriverUnloadedState); - addState(mDriverLoadingState, mDefaultState); - addState(mDriverLoadedState, mDefaultState); - addState(mWaitForSupState, mDriverLoadedState); - addState(mDriverSupReadyState, mDefaultState); - addState(mDriverStartingState, mDriverSupReadyState); - addState(mDriverStartedState, mDriverSupReadyState); - addState(mScanModeState, mDriverStartedState); - addState(mConnectModeState, mDriverStartedState); - addState(mConnectingState, mConnectModeState); - addState(mConnectedState, mConnectModeState); - addState(mDisconnectingState, mConnectModeState); - addState(mDisconnectedState, mConnectModeState); - addState(mDriverStoppingState, mDriverSupReadyState); - addState(mDriverStoppedState, mDriverSupReadyState); - addState(mSoftApStartedState, mDefaultState); - - setInitialState(mInitialState); - - if (DBG) setDbg(true); - - //start the state machine - start(); } - /********************************************************* - * NetworkStateTracker interface implementation - ********************************************************/ - public void setTeardownRequested(boolean isRequested) { mTeardownRequested.set(isRequested); } @@ -544,11 +79,17 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ /** * Begin monitoring wifi connectivity - * @deprecated - * - * TODO: remove this from callers */ public void startMonitoring() { + mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + IntentFilter filter = new IntentFilter(); + filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + filter.addAction(WifiManager.CONFIG_CHANGED_ACTION); + filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + + mWifiStateReceiver = new WifiStateReceiver(); + mContext.registerReceiver(mWifiStateReceiver, filter); } /** @@ -556,7 +97,8 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ * TODO: do away with return value after making MobileDataStateTracker async */ public boolean teardown() { - sendMessage(CM_CMD_TEARDOWN); + mTeardownRequested.set(true); + mWifiManager.stopWifi(); return true; } @@ -565,7 +107,8 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ * TODO: do away with return value after making MobileDataStateTracker async */ public boolean reconnect() { - sendMessage(CM_CMD_RECONNECT); + mTeardownRequested.set(false); + mWifiManager.startWifi(); return true; } @@ -575,7 +118,7 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ * TODO: do away with return value after making MobileDataStateTracker async */ public boolean setRadio(boolean turnOn) { - setWifiEnabled(turnOn); + mWifiManager.setWifiEnabled(turnOn); return true; } @@ -626,21 +169,6 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ return -1; } - /* TODO: will go away. - * Notifications are directly handled in WifiStateTracker at checkAndSetNotification() - */ - public void interpretScanResultsAvailable() { - - } - - /** - * Return the name of our WLAN network interface. - * @return the name of our interface. - */ - public String getInterfaceName() { - return mInterfaceName; - } - /** * Check if private DNS route is set for the network */ @@ -698,3279 +226,23 @@ public class WifiStateTracker extends HierarchicalStateMachine implements Networ return "net.tcp.buffersize.wifi"; } - - /********************************************************* - * Methods exposed for public use - ********************************************************/ - - /** - * TODO: doc - */ - public boolean pingSupplicant() { - return sendSyncMessage(CMD_PING_SUPPLICANT).boolValue; - } - - /** - * TODO: doc - */ - public boolean startScan(boolean forceActive) { - return sendSyncMessage(obtainMessage(CMD_START_SCAN, forceActive ? - SCAN_ACTIVE : SCAN_PASSIVE, 0)).boolValue; - } - - /** - * TODO: doc - */ - public void setWifiEnabled(boolean enable) { - mLastEnableUid.set(Binder.getCallingUid()); - if (enable) { - /* Argument is the state that is entered prior to load */ - sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0)); - sendMessage(CMD_START_SUPPLICANT); - } else { - sendMessage(CMD_STOP_SUPPLICANT); - /* Argument is the state that is entered upon success */ - sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0)); - } - } - - /** - * TODO: doc - */ - public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) { - mLastApEnableUid.set(Binder.getCallingUid()); - if (enable) { - /* Argument is the state that is entered prior to load */ - sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0)); - sendMessage(obtainMessage(CMD_START_AP, wifiConfig)); - } else { - sendMessage(CMD_STOP_AP); - /* Argument is the state that is entered upon success */ - sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0)); - } - } - - /** - * TODO: doc - */ - public int getWifiState() { - return mWifiState.get(); - } - - /** - * TODO: doc - */ - public String getWifiStateByName() { - switch (mWifiState.get()) { - case WIFI_STATE_DISABLING: - return "disabling"; - case WIFI_STATE_DISABLED: - return "disabled"; - case WIFI_STATE_ENABLING: - return "enabling"; - case WIFI_STATE_ENABLED: - return "enabled"; - case WIFI_STATE_UNKNOWN: - return "unknown state"; - default: - return "[invalid state]"; - } - } - - /** - * TODO: doc - */ - public int getWifiApState() { - return mWifiApState.get(); - } - - /** - * TODO: doc - */ - public String getWifiApStateByName() { - switch (mWifiApState.get()) { - case WIFI_AP_STATE_DISABLING: - return "disabling"; - case WIFI_AP_STATE_DISABLED: - return "disabled"; - case WIFI_AP_STATE_ENABLING: - return "enabling"; - case WIFI_AP_STATE_ENABLED: - return "enabled"; - case WIFI_AP_STATE_FAILED: - return "failed"; - default: - return "[invalid state]"; - } - } - - /** - * Get status information for the current connection, if any. - * @return a {@link WifiInfo} object containing information about the current connection - * - */ - public WifiInfo requestConnectionInfo() { - return mWifiInfo; - } - - public DhcpInfo getDhcpInfo() { - return mDhcpInfo; - } - - /** - * TODO: doc - */ - public void startWifi(boolean enable) { - if (enable) { - sendMessage(CMD_START_DRIVER); - } else { - sendMessage(CMD_STOP_DRIVER); - } - } - - /** - * TODO: doc - */ - public void disconnectAndStop() { - sendMessage(CMD_DISCONNECT); - sendMessage(CMD_STOP_DRIVER); - } - - /** - * TODO: doc - */ - public void setScanOnlyMode(boolean enable) { - if (enable) { - sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0)); - } else { - sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0)); - } - } - - /** - * TODO: doc - */ - public void setScanType(boolean active) { - if (active) { - sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0)); - } else { - sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0)); - } - } - - /** - * TODO: doc - */ - public List<ScanResult> getScanResultsList() { - return mScanResults; - } - - /** - * Disconnect from Access Point - */ - public boolean disconnectCommand() { - return sendSyncMessage(CMD_DISCONNECT).boolValue; - } - - /** - * Initiate a reconnection to AP - */ - public boolean reconnectCommand() { - return sendSyncMessage(CMD_RECONNECT).boolValue; - } - - /** - * Initiate a re-association to AP - */ - public boolean reassociateCommand() { - return sendSyncMessage(CMD_REASSOCIATE).boolValue; - } - - /** - * Add a network synchronously - * - * @return network id of the new network - */ - public int addOrUpdateNetwork(WifiConfiguration config) { - return sendSyncMessage(CMD_ADD_OR_UPDATE_NETWORK, config).intValue; - } - - public List<WifiConfiguration> getConfiguredNetworks() { - return sendSyncMessage(CMD_GET_NETWORK_CONFIG).configList; - } - - /** - * Delete a network - * - * @param networkId id of the network to be removed - */ - public boolean removeNetwork(int networkId) { - return sendSyncMessage(obtainMessage(CMD_REMOVE_NETWORK, networkId, 0)).boolValue; - } - - private class EnableNetParams { - private int netId; - private boolean disableOthers; - EnableNetParams(int n, boolean b) { - netId = n; - disableOthers = b; - } - } - /** - * Enable a network - * - * @param netId network id of the network - * @param disableOthers true, if all other networks have to be disabled - * @return {@code true} if the operation succeeds, {@code false} otherwise - */ - public boolean enableNetwork(int netId, boolean disableOthers) { - return sendSyncMessage(CMD_ENABLE_NETWORK, - new EnableNetParams(netId, disableOthers)).boolValue; - } - - /** - * Disable a network - * - * @param netId network id of the network - * @return {@code true} if the operation succeeds, {@code false} otherwise - */ - public boolean disableNetwork(int netId) { - return sendSyncMessage(obtainMessage(CMD_DISABLE_NETWORK, netId, 0)).boolValue; - } - - /** - * Blacklist a BSSID. This will avoid the AP if there are - * alternate APs to connect - * - * @param bssid BSSID of the network - */ - public void addToBlacklist(String bssid) { - sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid)); - } - - /** - * Clear the blacklist list - * - */ - public void clearBlacklist() { - sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST)); - } - - /** - * Get detailed status of the connection - * - * @return Example status result - * bssid=aa:bb:cc:dd:ee:ff - * ssid=TestNet - * id=3 - * pairwise_cipher=NONE - * group_cipher=NONE - * key_mgmt=NONE - * wpa_state=COMPLETED - * ip_address=X.X.X.X - */ - public String status() { - return sendSyncMessage(CMD_CONNECTION_STATUS).stringValue; - } - - public void enableRssiPolling(boolean enabled) { - sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0)); - } - /** - * Get RSSI to currently connected network - * - * @return RSSI value, -1 on failure - */ - public int getRssi() { - return sendSyncMessage(CMD_GET_RSSI).intValue; - } - - /** - * Get approx RSSI to currently connected network - * - * @return RSSI value, -1 on failure - */ - public int getRssiApprox() { - return sendSyncMessage(CMD_GET_RSSI_APPROX).intValue; - } - - /** - * Get link speed to currently connected network - * - * @return link speed, -1 on failure - */ - public int getLinkSpeed() { - return sendSyncMessage(CMD_GET_LINK_SPEED).intValue; - } - - /** - * Get MAC address of radio - * - * @return MAC address, null on failure - */ - public String getMacAddress() { - return sendSyncMessage(CMD_GET_MAC_ADDR).stringValue; - } - - /** - * Start packet filtering - */ - public void startPacketFiltering() { - sendMessage(CMD_START_PACKET_FILTERING); - } - - /** - * Stop packet filtering - */ - public void stopPacketFiltering() { - sendMessage(CMD_STOP_PACKET_FILTERING); - } - - /** - * Set power mode - * @param mode - * DRIVER_POWER_MODE_AUTO - * DRIVER_POWER_MODE_ACTIVE - */ - public void setPowerMode(int mode) { - sendMessage(obtainMessage(CMD_SET_POWER_MODE, mode, 0)); - } - - /** - * Set the number of allowed radio frequency channels from the system - * setting value, if any. - */ - public void setNumAllowedChannels() { - try { - setNumAllowedChannels( - Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS)); - } catch (Settings.SettingNotFoundException e) { - if (mNumAllowedChannels != 0) { - setNumAllowedChannels(mNumAllowedChannels); - } - // otherwise, use the driver default - } - } - - /** - * Set the number of radio frequency channels that are allowed to be used - * in the current regulatory domain. - * @param numChannels the number of allowed channels. Must be greater than 0 - * and less than or equal to 16. - */ - public void setNumAllowedChannels(int numChannels) { - sendMessage(obtainMessage(CMD_SET_NUM_ALLOWED_CHANNELS, numChannels, 0)); - } - - /** - * Get number of allowed channels - * - * @return channel count, -1 on failure - * - * TODO: this is not a public API and needs to be removed in favor - * of asynchronous reporting. unused for now. - */ - public int getNumAllowedChannels() { - return -1; - } - - /** - * Set bluetooth coex mode: - * - * @param mode - * BLUETOOTH_COEXISTENCE_MODE_ENABLED - * BLUETOOTH_COEXISTENCE_MODE_DISABLED - * BLUETOOTH_COEXISTENCE_MODE_SENSE - */ - public void setBluetoothCoexistenceMode(int mode) { - sendMessage(obtainMessage(CMD_SET_BLUETOOTH_COEXISTENCE, mode, 0)); - } - - /** - * Enable or disable Bluetooth coexistence scan mode. When this mode is on, - * some of the low-level scan parameters used by the driver are changed to - * reduce interference with A2DP streaming. - * - * @param isBluetoothPlaying whether to enable or disable this mode - */ - public void setBluetoothScanMode(boolean isBluetoothPlaying) { - sendMessage(obtainMessage(CMD_SET_BLUETOOTH_SCAN_MODE, isBluetoothPlaying ? 1 : 0, 0)); - } - - /** - * Save configuration on supplicant - * - * @return {@code true} if the operation succeeds, {@code false} otherwise - * - * TODO: deprecate this - */ - public boolean saveConfig() { - return sendSyncMessage(CMD_SAVE_CONFIG).boolValue; - } - - /** - * TODO: doc - */ - public void requestCmWakeLock() { - sendMessage(CMD_REQUEST_CM_WAKELOCK); - } - - /********************************************************* - * Internal private functions - ********************************************************/ - - class SyncReturn { - boolean boolValue; - int intValue; - String stringValue; - Object objValue; - List<WifiConfiguration> configList; - } - - class SyncParams { - Object mParameter; - SyncReturn mSyncReturn; - SyncParams() { - mSyncReturn = new SyncReturn(); - } - SyncParams(Object p) { - mParameter = p; - mSyncReturn = new SyncReturn(); - } - } - - /** - * message.arg2 is reserved to indicate synchronized - * message.obj is used to store SyncParams - */ - private SyncReturn syncedSend(Message msg) { - SyncParams syncParams = (SyncParams) msg.obj; - msg.arg2 = SYNCHRONOUS_CALL; - synchronized(syncParams) { - if (DBG) Log.d(TAG, "syncedSend " + msg); - sendMessage(msg); - try { - syncParams.wait(); - } catch (InterruptedException e) { - Log.e(TAG, "sendSyncMessage: unexpected interruption of wait()"); - return null; - } - } - return syncParams.mSyncReturn; - } - - private SyncReturn sendSyncMessage(Message msg) { - SyncParams syncParams = new SyncParams(); - msg.obj = syncParams; - return syncedSend(msg); - } - - private SyncReturn sendSyncMessage(int what, Object param) { - SyncParams syncParams = new SyncParams(param); - Message msg = obtainMessage(what, syncParams); - return syncedSend(msg); - } - - - private SyncReturn sendSyncMessage(int what) { - return sendSyncMessage(obtainMessage(what)); - } - - private void notifyOnMsgObject(Message msg) { - SyncParams syncParams = (SyncParams) msg.obj; - if (syncParams != null) { - synchronized(syncParams) { - if (DBG) Log.d(TAG, "notifyOnMsgObject " + msg); - syncParams.notify(); - } - } - else { - Log.e(TAG, "Error! syncParams in notifyOnMsgObject is null"); - } - } - - private void setWifiState(int wifiState) { - final int previousWifiState = mWifiState.get(); - - try { - if (wifiState == WIFI_STATE_ENABLED) { - mBatteryStats.noteWifiOn(mLastEnableUid.get()); - } else if (wifiState == WIFI_STATE_DISABLED) { - mBatteryStats.noteWifiOff(mLastEnableUid.get()); - } - } catch (RemoteException e) { - Log.e(TAG, "Failed to note battery stats in wifi"); - } - - mWifiState.set(wifiState); - - if (DBG) Log.d(TAG, "setWifiState: " + getWifiStateByName()); - - 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); - intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); - mContext.sendStickyBroadcast(intent); - } - - private void setWifiApState(int wifiApState) { - final int previousWifiApState = mWifiApState.get(); - - try { - if (wifiApState == WIFI_AP_STATE_ENABLED) { - mBatteryStats.noteWifiOn(mLastApEnableUid.get()); - } else if (wifiApState == WIFI_AP_STATE_DISABLED) { - mBatteryStats.noteWifiOff(mLastApEnableUid.get()); - } - } catch (RemoteException e) { - Log.d(TAG, "Failed to note battery stats in wifi"); - } - - // Update state - mWifiApState.set(wifiApState); - - if (DBG) Log.d(TAG, "setWifiApState: " + getWifiApStateByName()); - - // Broadcast - final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); - intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); - mContext.sendStickyBroadcast(intent); - } - - /** - * Parse the scan result line passed to us by wpa_supplicant (helper). - * @param line the line to parse - * @return the {@link ScanResult} object - */ - private ScanResult parseScanResult(String line) { - ScanResult scanResult = null; - if (line != null) { - /* - * Cache implementation (LinkedHashMap) is not synchronized, thus, - * must synchronized here! - */ - synchronized (mScanResultCache) { - String[] result = scanResultPattern.split(line); - if (3 <= result.length && result.length <= 5) { - String bssid = result[0]; - // bssid | frequency | level | flags | ssid - int frequency; - int level; - try { - frequency = Integer.parseInt(result[1]); - level = Integer.parseInt(result[2]); - /* some implementations avoid negative values by adding 256 - * so we need to adjust for that here. - */ - if (level > 0) level -= 256; - } catch (NumberFormatException e) { - frequency = 0; - level = 0; - } - - /* - * The formatting of the results returned by - * wpa_supplicant is intended to make the fields - * line up nicely when printed, - * not to make them easy to parse. So we have to - * apply some heuristics to figure out which field - * is the SSID and which field is the flags. - */ - String ssid; - String flags; - if (result.length == 4) { - if (result[3].charAt(0) == '[') { - flags = result[3]; - ssid = ""; - } else { - flags = ""; - ssid = result[3]; - } - } else if (result.length == 5) { - flags = result[3]; - ssid = result[4]; - } else { - // Here, we must have 3 fields: no flags and ssid - // set - flags = ""; - ssid = ""; - } - - // bssid + ssid is the hash key - String key = bssid + ssid; - scanResult = mScanResultCache.get(key); - if (scanResult != null) { - scanResult.level = level; - scanResult.SSID = ssid; - scanResult.capabilities = flags; - scanResult.frequency = frequency; - } else { - // Do not add scan results that have no SSID set - if (0 < ssid.trim().length()) { - scanResult = - new ScanResult( - ssid, bssid, flags, level, frequency); - mScanResultCache.put(key, scanResult); - } - } - } else { - Log.w(TAG, "Misformatted scan result text with " + - result.length + " fields: " + line); - } - } - } - - return scanResult; - } - - /** - * scanResults input format - * 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1 - * 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2 - */ - private void setScanResults(String scanResults) { - if (scanResults == null) { - return; - } - - List<ScanResult> scanList = new ArrayList<ScanResult>(); - - int lineCount = 0; - - int scanResultsLen = scanResults.length(); - // Parse the result string, keeping in mind that the last line does - // not end with a newline. - for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) { - if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') { - ++lineCount; - - if (lineCount == 1) { - lineBeg = lineEnd + 1; - continue; - } - if (lineEnd > lineBeg) { - String line = scanResults.substring(lineBeg, lineEnd); - ScanResult scanResult = parseScanResult(line); - if (scanResult != null) { - scanList.add(scanResult); - } else { - Log.w(TAG, "misformatted scan result for: " + line); - } - } - lineBeg = lineEnd + 1; - } - } - - mScanResults = scanList; - } - - private void checkAndSetNotification() { - // If we shouldn't place a notification on available networks, then - // don't bother doing any of the following - if (!mNotificationEnabled) return; - - State state = mNetworkInfo.getState(); - if ((state == NetworkInfo.State.DISCONNECTED) - || (state == NetworkInfo.State.UNKNOWN)) { - // Look for an open network - List<ScanResult> scanResults = mScanResults; - if (scanResults != null) { - int numOpenNetworks = 0; - for (int i = scanResults.size() - 1; i >= 0; i--) { - ScanResult scanResult = scanResults.get(i); - - if (TextUtils.isEmpty(scanResult.capabilities)) { - numOpenNetworks++; - } - } - - if (numOpenNetworks > 0) { - if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) { - /* - * We've scanned continuously at least - * NUM_SCANS_BEFORE_NOTIFICATION times. The user - * probably does not have a remembered network in range, - * since otherwise supplicant would have tried to - * associate and thus resetting this counter. - */ - setNotificationVisible(true, numOpenNetworks, false, 0); - } - return; - } - } - } - - // No open networks in range, remove the notification - setNotificationVisible(false, 0, false, 0); - } - - /** - * Display or don't display a notification that there are open Wi-Fi networks. - * @param visible {@code true} if notification should be visible, {@code false} otherwise - * @param numNetworks the number networks seen - * @param force {@code true} to force notification to be shown/not-shown, - * even if it is already shown/not-shown. - * @param delay time in milliseconds after which the notification should be made - * visible or invisible. - */ - private void setNotificationVisible(boolean visible, int numNetworks, boolean force, - int delay) { - - // Since we use auto cancel on the notification, when the - // mNetworksAvailableNotificationShown is true, the notification may - // have actually been canceled. However, when it is false we know - // for sure that it is not being shown (it will not be shown any other - // place than here) - - // If it should be hidden and it is already hidden, then noop - if (!visible && !mNotificationShown && !force) { - return; - } - - Message message; - if (visible) { - - // Not enough time has passed to show the notification again - if (System.currentTimeMillis() < mNotificationRepeatTime) { - return; - } - - if (mNotification == null) { - // Cache the Notification mainly so we can remove the - // EVENT_NOTIFICATION_CHANGED message with this Notification from - // the queue later - mNotification = new Notification(); - mNotification.when = 0; - mNotification.icon = ICON_NETWORKS_AVAILABLE; - mNotification.flags = Notification.FLAG_AUTO_CANCEL; - mNotification.contentIntent = PendingIntent.getActivity(mContext, 0, - new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0); - } - - CharSequence title = mContext.getResources().getQuantityText( - com.android.internal.R.plurals.wifi_available, numNetworks); - CharSequence details = mContext.getResources().getQuantityText( - com.android.internal.R.plurals.wifi_available_detailed, numNetworks); - mNotification.tickerText = title; - mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent); - - mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS; - - message = mCsHandler.obtainMessage(EVENT_NOTIFICATION_CHANGED, 1, - ICON_NETWORKS_AVAILABLE, mNotification); - - } else { - - // Remove any pending messages to show the notification - mCsHandler.removeMessages(EVENT_NOTIFICATION_CHANGED, mNotification); - - message = mCsHandler.obtainMessage(EVENT_NOTIFICATION_CHANGED, 0, - ICON_NETWORKS_AVAILABLE); - } - - mCsHandler.sendMessageDelayed(message, delay); - - mNotificationShown = visible; - } - - private void configureNetworkProperties() { - try { - mNetworkProperties.setInterface(NetworkInterface.getByName(mInterfaceName)); - } catch (SocketException e) { - Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName + - ". e=" + e); - return; - } catch (NullPointerException e) { - Log.e(TAG, "NPE creating NetworkInterface. e=" + e); - return; - } - // TODO - fix this for v6 - try { - mNetworkProperties.addAddress(InetAddress.getByAddress( - NetworkUtils.v4IntToArray(mDhcpInfo.ipAddress))); - } catch (UnknownHostException e) { - Log.e(TAG, "Exception setting IpAddress using " + mDhcpInfo + ", e=" + e); - } - - try { - mNetworkProperties.setGateway(InetAddress.getByAddress(NetworkUtils.v4IntToArray( - mDhcpInfo.gateway))); - } catch (UnknownHostException e) { - Log.e(TAG, "Exception setting Gateway using " + mDhcpInfo + ", e=" + e); - } - - try { - mNetworkProperties.addDns(InetAddress.getByAddress( - NetworkUtils.v4IntToArray(mDhcpInfo.dns1))); - } catch (UnknownHostException e) { - Log.e(TAG, "Exception setting Dns1 using " + mDhcpInfo + ", e=" + e); - } - try { - mNetworkProperties.addDns(InetAddress.getByAddress( - NetworkUtils.v4IntToArray(mDhcpInfo.dns2))); - - } catch (UnknownHostException e) { - Log.e(TAG, "Exception setting Dns2 using " + mDhcpInfo + ", e=" + e); - } - // TODO - add proxy info - } - - - private void checkUseStaticIp() { - mUseStaticIp = false; - final ContentResolver cr = mContext.getContentResolver(); - try { - if (Settings.System.getInt(cr, Settings.System.WIFI_USE_STATIC_IP) == 0) { - return; - } - } catch (Settings.SettingNotFoundException e) { - return; - } - - try { - String addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_IP); - if (addr != null) { - mDhcpInfo.ipAddress = stringToIpAddr(addr); - } else { - return; - } - addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_GATEWAY); - if (addr != null) { - mDhcpInfo.gateway = stringToIpAddr(addr); - } else { - return; - } - addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_NETMASK); - if (addr != null) { - mDhcpInfo.netmask = stringToIpAddr(addr); - } else { - return; - } - addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS1); - if (addr != null) { - mDhcpInfo.dns1 = stringToIpAddr(addr); - } else { - return; - } - addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS2); - if (addr != null) { - mDhcpInfo.dns2 = stringToIpAddr(addr); - } else { - mDhcpInfo.dns2 = 0; - } - } catch (UnknownHostException e) { - return; - } - mUseStaticIp = true; - } - - private static int stringToIpAddr(String addrString) throws UnknownHostException { - try { - String[] parts = addrString.split("\\."); - if (parts.length != 4) { - throw new UnknownHostException(addrString); - } - - int a = Integer.parseInt(parts[0]) ; - int b = Integer.parseInt(parts[1]) << 8; - int c = Integer.parseInt(parts[2]) << 16; - int d = Integer.parseInt(parts[3]) << 24; - - return a | b | c | d; - } catch (NumberFormatException ex) { - throw new UnknownHostException(addrString); - } - } - - private int getMaxDhcpRetries() { - return Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT, - DEFAULT_MAX_DHCP_RETRIES); - } - - private class SettingsObserver extends ContentObserver { - public SettingsObserver(Handler handler) { - super(handler); - ContentResolver cr = mContext.getContentResolver(); - cr.registerContentObserver(Settings.System.getUriFor( - Settings.System.WIFI_USE_STATIC_IP), false, this); - cr.registerContentObserver(Settings.System.getUriFor( - Settings.System.WIFI_STATIC_IP), false, this); - cr.registerContentObserver(Settings.System.getUriFor( - Settings.System.WIFI_STATIC_GATEWAY), false, this); - cr.registerContentObserver(Settings.System.getUriFor( - Settings.System.WIFI_STATIC_NETMASK), false, this); - cr.registerContentObserver(Settings.System.getUriFor( - Settings.System.WIFI_STATIC_DNS1), false, this); - cr.registerContentObserver(Settings.System.getUriFor( - Settings.System.WIFI_STATIC_DNS2), false, this); - } - + private class WifiStateReceiver extends BroadcastReceiver { @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - - boolean wasStaticIp = mUseStaticIp; - int oIp, oGw, oMsk, oDns1, oDns2; - oIp = oGw = oMsk = oDns1 = oDns2 = 0; - if (wasStaticIp) { - oIp = mDhcpInfo.ipAddress; - oGw = mDhcpInfo.gateway; - oMsk = mDhcpInfo.netmask; - oDns1 = mDhcpInfo.dns1; - oDns2 = mDhcpInfo.dns2; - } - checkUseStaticIp(); - - if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED) { - return; - } - - boolean changed = - (wasStaticIp != mUseStaticIp) || - (wasStaticIp && ( - oIp != mDhcpInfo.ipAddress || - oGw != mDhcpInfo.gateway || - oMsk != mDhcpInfo.netmask || - oDns1 != mDhcpInfo.dns1 || - oDns2 != mDhcpInfo.dns2)); - - if (changed) { - sendMessage(CMD_RECONFIGURE_IP); - if (mUseStaticIp) { - mCsHandler.sendEmptyMessage(EVENT_CONFIGURATION_CHANGED); - } + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( + WifiManager.EXTRA_NETWORK_INFO); + mNetworkProperties = (NetworkProperties) intent.getParcelableExtra( + WifiManager.EXTRA_NETWORK_PROPERTIES); + Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); + msg.sendToTarget(); + } else if (intent.getAction().equals(WifiManager.CONFIG_CHANGED_ACTION)) { + mNetworkProperties = (NetworkProperties) intent.getParcelableExtra( + WifiManager.EXTRA_NETWORK_PROPERTIES); + Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo); + msg.sendToTarget(); } } } - - /** - * Clears variables related to tracking whether a notification has been - * shown recently. - * <p> - * After calling this method, the timer that prevents notifications from - * being shown too often will be cleared. - */ - private void resetNotificationTimer() { - mNotificationRepeatTime = 0; - mNumScansSinceNetworkStateChange = 0; - } - - - /** - * Whether to disable coexistence mode while obtaining IP address. This - * logic will return true only if the current bluetooth - * headset/handsfree state is disconnected. This means if it is in an - * error state, we will NOT disable coexistence mode to err on the side - * of safety. - * - * @return Whether to disable coexistence mode. - */ - private boolean shouldDisableCoexistenceMode() { - int state = mBluetoothHeadset.getState(mBluetoothHeadset.getCurrentHeadset()); - return state == BluetoothHeadset.STATE_DISCONNECTED; - } - - private void checkIsBluetoothPlaying() { - boolean isBluetoothPlaying = false; - Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks(); - - for (BluetoothDevice device : connected) { - if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) { - isBluetoothPlaying = true; - break; - } - } - setBluetoothScanMode(isBluetoothPlaying); - } - - private void sendScanResultsAvailableBroadcast() { - if (!ActivityManagerNative.isSystemReady()) return; - - mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); - } - - private void sendRssiChangeBroadcast(final int newRssi) { - if (!ActivityManagerNative.isSystemReady()) return; - - Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); - intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); - mContext.sendBroadcast(intent); - } - - private void sendNetworkStateChangeBroadcast(String bssid) { - Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT - | Intent.FLAG_RECEIVER_REPLACE_PENDING); - intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo); - if (bssid != null) - intent.putExtra(WifiManager.EXTRA_BSSID, bssid); - mContext.sendStickyBroadcast(intent); - } - - private void sendSupplicantStateChangedBroadcast(StateChangeResult sc, boolean failedAuth) { - Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT - | Intent.FLAG_RECEIVER_REPLACE_PENDING); - intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)sc.state); - if (failedAuth) { - intent.putExtra( - WifiManager.EXTRA_SUPPLICANT_ERROR, - WifiManager.ERROR_AUTHENTICATING); - } - mContext.sendStickyBroadcast(intent); - } - - private void sendSupplicantConnectionChangedBroadcast(boolean connected) { - if (!ActivityManagerNative.isSystemReady()) return; - - Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); - mContext.sendBroadcast(intent); - } - - /** - * Record the detailed state of a network, and if it is a - * change from the previous state, send a notification to - * any listeners. - * @param state the new @{code DetailedState} - */ - private void setDetailedState(NetworkInfo.DetailedState state) { - Log.d(TAG, "setDetailed state, old =" - + mNetworkInfo.getDetailedState() + " and new state=" + state); - if (state != mNetworkInfo.getDetailedState()) { - mNetworkInfo.setDetailedState(state, null, null); - Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); - msg.sendToTarget(); - } - } - - private static String removeDoubleQuotes(String string) { - if (string.length() <= 2) return ""; - return string.substring(1, string.length() - 1); - } - - private static String convertToQuotedString(String string) { - return "\"" + string + "\""; - } - - private static String makeString(BitSet set, String[] strings) { - StringBuffer buf = new StringBuffer(); - int nextSetBit = -1; - - /* Make sure all set bits are in [0, strings.length) to avoid - * going out of bounds on strings. (Shouldn't happen, but...) */ - set = set.get(0, strings.length); - - while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { - buf.append(strings[nextSetBit].replace('_', '-')).append(' '); - } - - // remove trailing space - if (set.cardinality() > 0) { - buf.setLength(buf.length() - 1); - } - - return buf.toString(); - } - - private static int lookupString(String string, String[] strings) { - int size = strings.length; - - string = string.replace('-', '_'); - - for (int i = 0; i < size; i++) - if (string.equals(strings[i])) - return i; - - // if we ever get here, we should probably add the - // value to WifiConfiguration to reflect that it's - // supported by the WPA supplicant - Log.w(TAG, "Failed to look-up a string: " + string); - - return -1; - } - - private int addOrUpdateNetworkNative(WifiConfiguration config) { - /* - * If the supplied networkId is -1, we create a new empty - * network configuration. Otherwise, the networkId should - * refer to an existing configuration. - */ - int netId = config.networkId; - boolean newNetwork = netId == -1; - // networkId of -1 means we want to create a new network - - if (newNetwork) { - netId = WifiNative.addNetworkCommand(); - if (netId < 0) { - Log.e(TAG, "Failed to add a network!"); - return -1; - } - } - - setVariables: { - - if (config.SSID != null && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.ssidVarName, - config.SSID)) { - Log.d(TAG, "failed to set SSID: "+config.SSID); - break setVariables; - } - - if (config.BSSID != null && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.bssidVarName, - config.BSSID)) { - Log.d(TAG, "failed to set BSSID: "+config.BSSID); - break setVariables; - } - - String allowedKeyManagementString = - makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); - if (config.allowedKeyManagement.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.KeyMgmt.varName, - allowedKeyManagementString)) { - Log.d(TAG, "failed to set key_mgmt: "+ - allowedKeyManagementString); - break setVariables; - } - - String allowedProtocolsString = - makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); - if (config.allowedProtocols.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.Protocol.varName, - allowedProtocolsString)) { - Log.d(TAG, "failed to set proto: "+ - allowedProtocolsString); - break setVariables; - } - - String allowedAuthAlgorithmsString = - makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); - if (config.allowedAuthAlgorithms.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.AuthAlgorithm.varName, - allowedAuthAlgorithmsString)) { - Log.d(TAG, "failed to set auth_alg: "+ - allowedAuthAlgorithmsString); - break setVariables; - } - - String allowedPairwiseCiphersString = - makeString(config.allowedPairwiseCiphers, - WifiConfiguration.PairwiseCipher.strings); - if (config.allowedPairwiseCiphers.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.PairwiseCipher.varName, - allowedPairwiseCiphersString)) { - Log.d(TAG, "failed to set pairwise: "+ - allowedPairwiseCiphersString); - break setVariables; - } - - String allowedGroupCiphersString = - makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); - if (config.allowedGroupCiphers.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.GroupCipher.varName, - allowedGroupCiphersString)) { - Log.d(TAG, "failed to set group: "+ - allowedGroupCiphersString); - break setVariables; - } - - // Prevent client screw-up by passing in a WifiConfiguration we gave it - // by preventing "*" as a key. - if (config.preSharedKey != null && !config.preSharedKey.equals("*") && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.pskVarName, - config.preSharedKey)) { - Log.d(TAG, "failed to set psk: "+config.preSharedKey); - break setVariables; - } - - boolean hasSetKey = false; - if (config.wepKeys != null) { - for (int i = 0; i < config.wepKeys.length; i++) { - // Prevent client screw-up by passing in a WifiConfiguration we gave it - // by preventing "*" as a key. - if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { - if (!WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.wepKeyVarNames[i], - config.wepKeys[i])) { - Log.d(TAG, - "failed to set wep_key"+i+": " + - config.wepKeys[i]); - break setVariables; - } - hasSetKey = true; - } - } - } - - if (hasSetKey) { - if (!WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.wepTxKeyIdxVarName, - Integer.toString(config.wepTxKeyIndex))) { - Log.d(TAG, - "failed to set wep_tx_keyidx: "+ - config.wepTxKeyIndex); - break setVariables; - } - } - - if (!WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.priorityVarName, - Integer.toString(config.priority))) { - Log.d(TAG, config.SSID + ": failed to set priority: " - +config.priority); - break setVariables; - } - - if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.hiddenSSIDVarName, - Integer.toString(config.hiddenSSID ? 1 : 0))) { - Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+ - config.hiddenSSID); - break setVariables; - } - - for (WifiConfiguration.EnterpriseField field - : config.enterpriseFields) { - String varName = field.varName(); - String value = field.value(); - if (value != null) { - if (field != config.eap) { - value = (value.length() == 0) ? "NULL" : convertToQuotedString(value); - } - if (!WifiNative.setNetworkVariableCommand( - netId, - varName, - value)) { - Log.d(TAG, config.SSID + ": failed to set " + varName + - ": " + value); - break setVariables; - } - } - } - return netId; - } - - if (newNetwork) { - WifiNative.removeNetworkCommand(netId); - Log.d(TAG, - "Failed to set a network variable, removed network: " - + netId); - } - - return -1; - } - - private List<WifiConfiguration> getConfiguredNetworksNative() { - String listStr = WifiNative.listNetworksCommand(); - - List<WifiConfiguration> networks = - new ArrayList<WifiConfiguration>(); - if (listStr == null) - return networks; - - String[] lines = listStr.split("\n"); - // Skip the first line, which is a header - for (int i = 1; i < lines.length; i++) { - String[] result = lines[i].split("\t"); - // network-id | ssid | bssid | flags - WifiConfiguration config = new WifiConfiguration(); - try { - config.networkId = Integer.parseInt(result[0]); - } catch(NumberFormatException e) { - continue; - } - if (result.length > 3) { - if (result[3].indexOf("[CURRENT]") != -1) - config.status = WifiConfiguration.Status.CURRENT; - else if (result[3].indexOf("[DISABLED]") != -1) - config.status = WifiConfiguration.Status.DISABLED; - else - config.status = WifiConfiguration.Status.ENABLED; - } else { - config.status = WifiConfiguration.Status.ENABLED; - } - readNetworkVariables(config); - networks.add(config); - } - return networks; - } - - /** - * Read the variables from the supplicant daemon that are needed to - * fill in the WifiConfiguration object. - * - * @param config the {@link WifiConfiguration} object to be filled in. - */ - private void readNetworkVariables(WifiConfiguration config) { - - int netId = config.networkId; - if (netId < 0) - return; - - /* - * TODO: maybe should have a native method that takes an array of - * variable names and returns an array of values. But we'd still - * be doing a round trip to the supplicant daemon for each variable. - */ - String value; - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName); - if (!TextUtils.isEmpty(value)) { - config.SSID = removeDoubleQuotes(value); - } else { - config.SSID = null; - } - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName); - if (!TextUtils.isEmpty(value)) { - config.BSSID = value; - } else { - config.BSSID = null; - } - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName); - config.priority = -1; - if (!TextUtils.isEmpty(value)) { - try { - config.priority = Integer.parseInt(value); - } catch (NumberFormatException ignore) { - } - } - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName); - config.hiddenSSID = false; - if (!TextUtils.isEmpty(value)) { - try { - config.hiddenSSID = Integer.parseInt(value) != 0; - } catch (NumberFormatException ignore) { - } - } - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName); - config.wepTxKeyIndex = -1; - if (!TextUtils.isEmpty(value)) { - try { - config.wepTxKeyIndex = Integer.parseInt(value); - } catch (NumberFormatException ignore) { - } - } - - for (int i = 0; i < 4; i++) { - value = WifiNative.getNetworkVariableCommand(netId, - WifiConfiguration.wepKeyVarNames[i]); - if (!TextUtils.isEmpty(value)) { - config.wepKeys[i] = value; - } else { - config.wepKeys[i] = null; - } - } - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName); - if (!TextUtils.isEmpty(value)) { - config.preSharedKey = value; - } else { - config.preSharedKey = null; - } - - value = WifiNative.getNetworkVariableCommand(config.networkId, - WifiConfiguration.Protocol.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.Protocol.strings); - if (0 <= index) { - config.allowedProtocols.set(index); - } - } - } - - value = WifiNative.getNetworkVariableCommand(config.networkId, - WifiConfiguration.KeyMgmt.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.KeyMgmt.strings); - if (0 <= index) { - config.allowedKeyManagement.set(index); - } - } - } - - value = WifiNative.getNetworkVariableCommand(config.networkId, - WifiConfiguration.AuthAlgorithm.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.AuthAlgorithm.strings); - if (0 <= index) { - config.allowedAuthAlgorithms.set(index); - } - } - } - - value = WifiNative.getNetworkVariableCommand(config.networkId, - WifiConfiguration.PairwiseCipher.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.PairwiseCipher.strings); - if (0 <= index) { - config.allowedPairwiseCiphers.set(index); - } - } - } - - value = WifiNative.getNetworkVariableCommand(config.networkId, - WifiConfiguration.GroupCipher.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.GroupCipher.strings); - if (0 <= index) { - config.allowedGroupCiphers.set(index); - } - } - } - - for (WifiConfiguration.EnterpriseField field : - config.enterpriseFields) { - value = WifiNative.getNetworkVariableCommand(netId, - field.varName()); - if (!TextUtils.isEmpty(value)) { - if (field != config.eap) value = removeDoubleQuotes(value); - field.setValue(value); - } - } - - } - - /** - * Poll for info not reported via events - * RSSI & Linkspeed - */ - private void requestPolledInfo() { - int newRssi = WifiNative.getRssiCommand(); - if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values - /* some implementations avoid negative values by adding 256 - * so we need to adjust for that here. - */ - if (newRssi > 0) newRssi -= 256; - mWifiInfo.setRssi(newRssi); - /* - * Rather then sending the raw RSSI out every time it - * changes, we precalculate the signal level that would - * be displayed in the status bar, and only send the - * broadcast if that much more coarse-grained number - * changes. This cuts down greatly on the number of - * broadcasts, at the cost of not mWifiInforming others - * interested in RSSI of all the changes in signal - * level. - */ - // TODO: The second arg to the call below needs to be a symbol somewhere, but - // it's actually the size of an array of icons that's private - // to StatusBar Policy. - int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4); - if (newSignalLevel != mLastSignalLevel) { - sendRssiChangeBroadcast(newRssi); - } - mLastSignalLevel = newSignalLevel; - } else { - mWifiInfo.setRssi(-200); - } - int newLinkSpeed = WifiNative.getLinkSpeedCommand(); - if (newLinkSpeed != -1) { - mWifiInfo.setLinkSpeed(newLinkSpeed); - } - } - - /** - * Resets the Wi-Fi Connections by clearing any state, resetting any sockets - * using the interface, stopping DHCP & disabling interface - */ - private void handleNetworkDisconnect() { - Log.d(TAG, "Reset connections and stopping DHCP"); - - /* - * Reset connections & stop DHCP - */ - NetworkUtils.resetConnections(mInterfaceName); - - if (!NetworkUtils.stopDhcp(mInterfaceName)) { - Log.e(TAG, "Could not stop DHCP"); - } - - /* Disable interface */ - NetworkUtils.disableInterface(mInterfaceName); - - /* send event to CM & network change broadcast */ - setDetailedState(DetailedState.DISCONNECTED); - sendNetworkStateChangeBroadcast(mLastBssid); - - /* Reset data structures */ - mWifiInfo.setIpAddress(0); - mWifiInfo.setBSSID(null); - mWifiInfo.setSSID(null); - mWifiInfo.setNetworkId(-1); - - /* Clear network properties */ - mNetworkProperties.clear(); - - mLastBssid= null; - mLastNetworkId = -1; - - } - - - /********************************************************* - * Notifications from WifiMonitor - ********************************************************/ - - /** - * A structure for supplying information about a supplicant state - * change in the STATE_CHANGE event message that comes from the - * WifiMonitor - * thread. - */ - private static class StateChangeResult { - StateChangeResult(int networkId, String BSSID, Object state) { - this.state = state; - this.BSSID = BSSID; - this.networkId = networkId; - } - int networkId; - String BSSID; - Object state; - } - - /** - * Send the tracker a notification that a user-entered password key - * may be incorrect (i.e., caused authentication to fail). - */ - void notifyPasswordKeyMayBeIncorrect() { - sendMessage(PASSWORD_MAY_BE_INCORRECT_EVENT); - } - - /** - * Send the tracker a notification that a connection to the supplicant - * daemon has been established. - */ - void notifySupplicantConnection() { - sendMessage(SUP_CONNECTION_EVENT); - } - - /** - * Send the tracker a notification that a connection to the supplicant - * daemon has been established. - */ - void notifySupplicantLost() { - sendMessage(SUP_DISCONNECTION_EVENT); - } - - /** - * Send the tracker a notification that the state of Wifi connectivity - * has changed. - * @param networkId the configured network on which the state change occurred - * @param newState the new network state - * @param BSSID when the new state is {@link DetailedState#CONNECTED - * NetworkInfo.DetailedState.CONNECTED}, - * this is the MAC address of the access point. Otherwise, it - * is {@code null}. - */ - void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) { - if (newState == NetworkInfo.DetailedState.CONNECTED) { - sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT, - new StateChangeResult(networkId, BSSID, newState))); - } else { - sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT, - new StateChangeResult(networkId, BSSID, newState))); - } - } - - /** - * Send the tracker a notification that the state of the supplicant - * has changed. - * @param networkId the configured network on which the state change occurred - * @param newState the new {@code SupplicantState} - */ - void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) { - sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, - new StateChangeResult(networkId, BSSID, newState))); - } - - /** - * Send the tracker a notification that a scan has completed, and results - * are available. - */ - void notifyScanResultsAvailable() { - /** - * Switch scan mode over to passive. - * Turning off scan-only mode happens only in "Connect" mode - */ - setScanType(false); - sendMessage(SCAN_RESULTS_EVENT); - } - - void notifyDriverStarted() { - sendMessage(DRIVER_START_EVENT); - } - - void notifyDriverStopped() { - sendMessage(DRIVER_STOP_EVENT); - } - - void notifyDriverHung() { - setWifiEnabled(false); - setWifiEnabled(true); - } - - - /******************************************************** - * HSM states - *******************************************************/ - - class DefaultState extends HierarchicalState { - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - SyncParams syncParams; - switch (message.what) { - /* Synchronous call returns */ - case CMD_PING_SUPPLICANT: - case CMD_START_SCAN: - case CMD_DISCONNECT: - case CMD_RECONNECT: - case CMD_REASSOCIATE: - case CMD_REMOVE_NETWORK: - case CMD_ENABLE_NETWORK: - case CMD_DISABLE_NETWORK: - case CMD_ADD_OR_UPDATE_NETWORK: - case CMD_GET_RSSI: - case CMD_GET_RSSI_APPROX: - case CMD_GET_LINK_SPEED: - case CMD_GET_MAC_ADDR: - case CMD_SAVE_CONFIG: - case CMD_CONNECTION_STATUS: - case CMD_GET_NETWORK_CONFIG: - if (message.arg2 == SYNCHRONOUS_CALL) { - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = false; - syncParams.mSyncReturn.intValue = -1; - syncParams.mSyncReturn.stringValue = null; - syncParams.mSyncReturn.configList = null; - notifyOnMsgObject(message); - } - break; - case CM_CMD_TEARDOWN: - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - mTeardownRequested.set(true); - sendMessage(CMD_DISCONNECT); - sendMessage(CMD_STOP_DRIVER); - /* Mark wifi available when CM tears down */ - mNetworkInfo.setIsAvailable(true); - break; - case CM_CMD_RECONNECT: - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - mTeardownRequested.set(false); - sendMessage(CMD_START_DRIVER); - sendMessage(CMD_RECONNECT); - break; - case CMD_ENABLE_RSSI_POLL: - mEnableRssiPolling = (message.arg1 == 1); - mSupplicantStateTracker.sendMessage(CMD_ENABLE_RSSI_POLL); - break; - default: - if (DBG) Log.w(TAG, "Unhandled " + message); - break; - } - return HANDLED; - } - } - - class InitialState extends HierarchicalState { - @Override - //TODO: could move logging into a common class - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - // [31-8] Reserved for future use - // [7 - 0] HSM state change - // 50021 wifi_state_changed (custom|1|5) - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - - if (WifiNative.isDriverLoaded()) { - transitionTo(mDriverLoadedState); - } - else { - transitionTo(mDriverUnloadedState); - } - } - } - - class DriverLoadingState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - - final Message message = new Message(); - message.copyFrom(getCurrentMessage()); - new Thread(new Runnable() { - public void run() { - sWakeLock.acquire(); - //enabling state - switch(message.arg1) { - case WIFI_STATE_ENABLING: - setWifiState(WIFI_STATE_ENABLING); - break; - case WIFI_AP_STATE_ENABLING: - setWifiApState(WIFI_AP_STATE_ENABLING); - break; - } - - if(WifiNative.loadDriver()) { - Log.d(TAG, "Driver load successful"); - sendMessage(CMD_LOAD_DRIVER_SUCCESS); - } else { - Log.e(TAG, "Failed to load driver!"); - switch(message.arg1) { - case WIFI_STATE_ENABLING: - setWifiState(WIFI_STATE_UNKNOWN); - break; - case WIFI_AP_STATE_ENABLING: - setWifiApState(WIFI_AP_STATE_FAILED); - break; - } - sendMessage(CMD_LOAD_DRIVER_FAILURE); - } - sWakeLock.release(); - } - }).start(); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch (message.what) { - case CMD_LOAD_DRIVER_SUCCESS: - transitionTo(mDriverLoadedState); - break; - case CMD_LOAD_DRIVER_FAILURE: - transitionTo(mDriverFailedState); - 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_POWER_MODE: - case CMD_SET_BLUETOOTH_COEXISTENCE: - case CMD_SET_BLUETOOTH_SCAN_MODE: - case CMD_SET_NUM_ALLOWED_CHANNELS: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class DriverLoadedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch(message.what) { - case CMD_UNLOAD_DRIVER: - transitionTo(mDriverUnloadingState); - break; - case CMD_START_SUPPLICANT: - if(WifiNative.startSupplicant()) { - Log.d(TAG, "Supplicant start successful"); - mWifiMonitor.startMonitoring(); - setWifiState(WIFI_STATE_ENABLED); - transitionTo(mWaitForSupState); - } else { - Log.e(TAG, "Failed to start supplicant!"); - sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); - } - break; - case CMD_START_AP: - try { - nwService.startAccessPoint((WifiConfiguration) message.obj, - mInterfaceName, - SOFTAP_IFACE); - } catch(Exception e) { - Log.e(TAG, "Exception in startAccessPoint()"); - sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0)); - break; - } - Log.d(TAG, "Soft AP start successful"); - setWifiApState(WIFI_AP_STATE_ENABLED); - transitionTo(mSoftApStartedState); - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class DriverUnloadingState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - - final Message message = new Message(); - message.copyFrom(getCurrentMessage()); - new Thread(new Runnable() { - public void run() { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - sWakeLock.acquire(); - if(WifiNative.unloadDriver()) { - Log.d(TAG, "Driver unload successful"); - sendMessage(CMD_UNLOAD_DRIVER_SUCCESS); - - switch(message.arg1) { - case WIFI_STATE_DISABLED: - case WIFI_STATE_UNKNOWN: - setWifiState(message.arg1); - break; - case WIFI_AP_STATE_DISABLED: - case WIFI_AP_STATE_FAILED: - setWifiApState(message.arg1); - break; - } - } else { - Log.e(TAG, "Failed to unload driver!"); - sendMessage(CMD_UNLOAD_DRIVER_FAILURE); - - switch(message.arg1) { - case WIFI_STATE_DISABLED: - case WIFI_STATE_UNKNOWN: - setWifiState(WIFI_STATE_UNKNOWN); - break; - case WIFI_AP_STATE_DISABLED: - case WIFI_AP_STATE_FAILED: - setWifiApState(WIFI_AP_STATE_FAILED); - break; - } - } - sWakeLock.release(); - } - }).start(); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch (message.what) { - case CMD_UNLOAD_DRIVER_SUCCESS: - transitionTo(mDriverUnloadedState); - break; - case CMD_UNLOAD_DRIVER_FAILURE: - transitionTo(mDriverFailedState); - 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_POWER_MODE: - case CMD_SET_BLUETOOTH_COEXISTENCE: - case CMD_SET_BLUETOOTH_SCAN_MODE: - case CMD_SET_NUM_ALLOWED_CHANNELS: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class DriverUnloadedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch (message.what) { - case CMD_LOAD_DRIVER: - transitionTo(mDriverLoadingState); - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class DriverFailedState extends HierarchicalState { - @Override - public void enter() { - Log.e(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - return NOT_HANDLED; - } - } - - - class WaitForSupState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch(message.what) { - case SUP_CONNECTION_EVENT: - Log.d(TAG, "Supplicant connection established"); - mSupplicantStateTracker.resetSupplicantState(); - /* Initialize data structures */ - resetNotificationTimer(); - setTeardownRequested(false); - mLastBssid = null; - mLastNetworkId = -1; - mLastSignalLevel = -1; - - mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand()); - - //TODO: initialize and fix multicast filtering - //mWM.initializeMulticastFiltering(); - - if (mBluetoothA2dp == null) { - mBluetoothA2dp = new BluetoothA2dp(mContext); - } - checkIsBluetoothPlaying(); - - checkUseStaticIp(); - sendSupplicantConnectionChangedBroadcast(true); - transitionTo(mDriverSupReadyState); - break; - case CMD_STOP_SUPPLICANT: - Log.d(TAG, "Stop supplicant received"); - WifiNative.stopSupplicant(); - transitionTo(mDriverLoadedState); - break; - /* Fail soft ap when waiting for supplicant start */ - case CMD_START_AP: - Log.d(TAG, "Failed to start soft AP with a running supplicant"); - setWifiApState(WIFI_AP_STATE_FAILED); - break; - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_SET_SCAN_MODE: - case CMD_SET_SCAN_TYPE: - case CMD_SET_POWER_MODE: - case CMD_SET_BLUETOOTH_COEXISTENCE: - case CMD_SET_BLUETOOTH_SCAN_MODE: - case CMD_SET_NUM_ALLOWED_CHANNELS: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - deferMessage(message); - break; - case CMD_STOP_AP: - case CMD_START_SUPPLICANT: - case CMD_UNLOAD_DRIVER: - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class DriverSupReadyState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - /* Initialize for connect mode operation at start */ - mIsScanMode = false; - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - SyncParams syncParams; - switch(message.what) { - case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ - Log.d(TAG, "Stop supplicant received"); - WifiNative.stopSupplicant(); - //$FALL-THROUGH$ - case SUP_DISCONNECTION_EVENT: /* Supplicant died */ - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - //Remove any notifications on disconnection - setNotificationVisible(false, 0, false, 0); - WifiNative.closeSupplicantConnection(); - handleNetworkDisconnect(); - sendSupplicantConnectionChangedBroadcast(false); - mSupplicantStateTracker.resetSupplicantState(); - transitionTo(mDriverLoadedState); - - /* When supplicant dies, unload driver and enter failed state */ - //TODO: consider bringing up supplicant again - if (message.what == SUP_DISCONNECTION_EVENT) { - Log.d(TAG, "Supplicant died, unloading driver"); - sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); - } - break; - case CMD_START_DRIVER: - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - WifiNative.startDriverCommand(); - transitionTo(mDriverStartingState); - break; - case SCAN_RESULTS_EVENT: - setScanResults(WifiNative.scanResultsCommand()); - sendScanResultsAvailableBroadcast(); - checkAndSetNotification(); - break; - case CMD_PING_SUPPLICANT: - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = WifiNative.pingCommand(); - notifyOnMsgObject(message); - break; - case CMD_ADD_OR_UPDATE_NETWORK: - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - syncParams = (SyncParams) message.obj; - WifiConfiguration config = (WifiConfiguration) syncParams.mParameter; - syncParams.mSyncReturn.intValue = addOrUpdateNetworkNative(config); - notifyOnMsgObject(message); - break; - case CMD_REMOVE_NETWORK: - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - if (message.arg2 == SYNCHRONOUS_CALL) { - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = WifiNative.removeNetworkCommand( - message.arg1); - notifyOnMsgObject(message); - } else { - /* asynchronous handling */ - WifiNative.removeNetworkCommand(message.arg1); - } - break; - case CMD_ENABLE_NETWORK: - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - if (message.arg2 == SYNCHRONOUS_CALL) { - syncParams = (SyncParams) message.obj; - EnableNetParams enableNetParams = (EnableNetParams) syncParams.mParameter; - syncParams.mSyncReturn.boolValue = WifiNative.enableNetworkCommand( - enableNetParams.netId, enableNetParams.disableOthers); - notifyOnMsgObject(message); - } else { - /* asynchronous handling */ - WifiNative.enableNetworkCommand(message.arg1, message.arg2 == 1); - } - break; - case CMD_DISABLE_NETWORK: - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - if (message.arg2 == SYNCHRONOUS_CALL) { - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = WifiNative.disableNetworkCommand( - message.arg1); - notifyOnMsgObject(message); - } else { - /* asynchronous handling */ - WifiNative.disableNetworkCommand(message.arg1); - } - break; - case CMD_BLACKLIST_NETWORK: - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - WifiNative.addToBlacklistCommand((String)message.obj); - break; - case CMD_CLEAR_BLACKLIST: - WifiNative.clearBlacklistCommand(); - break; - case CMD_GET_NETWORK_CONFIG: - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.configList = getConfiguredNetworksNative(); - notifyOnMsgObject(message); - break; - case CMD_SAVE_CONFIG: - if (message.arg2 == SYNCHRONOUS_CALL) { - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = WifiNative.saveConfigCommand(); - notifyOnMsgObject(message); - } else { - /* asynchronous handling */ - WifiNative.saveConfigCommand(); - } - // Inform the backup manager about a data change - IBackupManager ibm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - if (ibm != null) { - try { - ibm.dataChanged("com.android.providers.settings"); - } catch (Exception e) { - // Try again later - } - } - break; - case CMD_CONNECTION_STATUS: - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.stringValue = WifiNative.statusCommand(); - notifyOnMsgObject(message); - break; - case CMD_GET_MAC_ADDR: - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.stringValue = WifiNative.getMacAddressCommand(); - notifyOnMsgObject(message); - break; - /* Cannot start soft AP while in client mode */ - case CMD_START_AP: - Log.d(TAG, "Failed to start soft AP with a running supplicant"); - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - setWifiApState(WIFI_AP_STATE_FAILED); - break; - case CMD_SET_SCAN_MODE: - mIsScanMode = (message.arg1 == SCAN_ONLY_MODE); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class DriverStartingState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch(message.what) { - case DRIVER_START_EVENT: - transitionTo(mDriverStartedState); - break; - /* Queue driver commands & connection events */ - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case SUPPLICANT_STATE_CHANGE_EVENT: - case NETWORK_CONNECTION_EVENT: - case NETWORK_DISCONNECTION_EVENT: - case PASSWORD_MAY_BE_INCORRECT_EVENT: - case CMD_SET_SCAN_TYPE: - case CMD_SET_POWER_MODE: - case CMD_SET_BLUETOOTH_COEXISTENCE: - case CMD_SET_BLUETOOTH_SCAN_MODE: - case CMD_SET_NUM_ALLOWED_CHANNELS: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - deferMessage(message); - break; - /* Queue the asynchronous version of these commands */ - case CMD_START_SCAN: - case CMD_DISCONNECT: - case CMD_REASSOCIATE: - case CMD_RECONNECT: - if (message.arg2 != SYNCHRONOUS_CALL) { - deferMessage(message); - } - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class DriverStartedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - - try { - mBatteryStats.noteWifiRunning(); - } catch (RemoteException ignore) {} - - /* Initialize channel count */ - setNumAllowedChannels(); - - if (mIsScanMode) { - WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); - WifiNative.disconnectCommand(); - transitionTo(mScanModeState); - } else { - WifiNative.setScanResultHandlingCommand(CONNECT_MODE); - /* If supplicant has already connected, before we could finish establishing - * the control channel connection, we miss all the supplicant events. - * Disconnect and reconnect when driver has started to ensure we receive - * all supplicant events. - * - * TODO: This is a bit unclean, ideally the supplicant should never - * connect until told to do so by the framework - */ - WifiNative.disconnectCommand(); - WifiNative.reconnectCommand(); - transitionTo(mConnectModeState); - } - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - SyncParams syncParams; - switch(message.what) { - case CMD_SET_SCAN_TYPE: - if (message.arg1 == SCAN_ACTIVE) { - WifiNative.setScanModeCommand(true); - } else { - WifiNative.setScanModeCommand(false); - } - break; - case CMD_SET_POWER_MODE: - WifiNative.setPowerModeCommand(message.arg1); - break; - case CMD_SET_BLUETOOTH_COEXISTENCE: - WifiNative.setBluetoothCoexistenceModeCommand(message.arg1); - break; - case CMD_SET_BLUETOOTH_SCAN_MODE: - WifiNative.setBluetoothCoexistenceScanModeCommand(message.arg1 == 1); - break; - case CMD_SET_NUM_ALLOWED_CHANNELS: - mNumAllowedChannels = message.arg1; - WifiNative.setNumAllowedChannelsCommand(message.arg1); - break; - case CMD_START_DRIVER: - /* Ignore another driver start */ - break; - case CMD_STOP_DRIVER: - WifiNative.stopDriverCommand(); - transitionTo(mDriverStoppingState); - break; - case CMD_REQUEST_CM_WAKELOCK: - if (mCm == null) { - mCm = (ConnectivityManager)mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - } - mCm.requestNetworkTransitionWakelock(TAG); - break; - case CMD_START_PACKET_FILTERING: - WifiNative.startPacketFiltering(); - break; - case CMD_STOP_PACKET_FILTERING: - WifiNative.stopPacketFiltering(); - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - @Override - public void exit() { - if (DBG) Log.d(TAG, getName() + "\n"); - try { - mBatteryStats.noteWifiStopped(); - } catch (RemoteException ignore) { } - } - } - - class DriverStoppingState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch(message.what) { - case DRIVER_STOP_EVENT: - transitionTo(mDriverStoppedState); - break; - /* Queue driver commands */ - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_SET_SCAN_TYPE: - case CMD_SET_POWER_MODE: - case CMD_SET_BLUETOOTH_COEXISTENCE: - case CMD_SET_BLUETOOTH_SCAN_MODE: - case CMD_SET_NUM_ALLOWED_CHANNELS: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - deferMessage(message); - break; - /* Queue the asynchronous version of these commands */ - case CMD_START_SCAN: - case CMD_DISCONNECT: - case CMD_REASSOCIATE: - case CMD_RECONNECT: - if (message.arg2 != SYNCHRONOUS_CALL) { - deferMessage(message); - } - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class DriverStoppedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - - // Take down any open network notifications on driver stop - setNotificationVisible(false, 0, false, 0); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - return NOT_HANDLED; - } - } - - class ScanModeState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - SyncParams syncParams; - switch(message.what) { - case CMD_SET_SCAN_MODE: - if (message.arg1 == SCAN_ONLY_MODE) { - /* Ignore */ - return HANDLED; - } else { - WifiNative.setScanResultHandlingCommand(message.arg1); - WifiNative.reconnectCommand(); - mIsScanMode = false; - transitionTo(mDisconnectedState); - } - break; - case CMD_START_SCAN: - if (message.arg2 == SYNCHRONOUS_CALL) { - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = WifiNative.scanCommand( - message.arg1 == SCAN_ACTIVE); - notifyOnMsgObject(message); - } else { - /* asynchronous handling */ - WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); - } - break; - /* Ignore */ - case CMD_DISCONNECT: - case CMD_RECONNECT: - case CMD_REASSOCIATE: - case SUPPLICANT_STATE_CHANGE_EVENT: - case NETWORK_CONNECTION_EVENT: - case NETWORK_DISCONNECTION_EVENT: - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class ConnectModeState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - SyncParams syncParams; - StateChangeResult stateChangeResult; - switch(message.what) { - case PASSWORD_MAY_BE_INCORRECT_EVENT: - mPasswordKeyMayBeIncorrect = true; - break; - case SUPPLICANT_STATE_CHANGE_EVENT: - stateChangeResult = (StateChangeResult) message.obj; - mSupplicantStateTracker.handleEvent(stateChangeResult); - break; - case CMD_START_SCAN: - if (message.arg2 == SYNCHRONOUS_CALL) { - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = true; - notifyOnMsgObject(message); - } - /* We need to set scan type in completed state */ - Message newMsg = obtainMessage(); - newMsg.copyFrom(message); - mSupplicantStateTracker.sendMessage(newMsg); - break; - /* Do a redundant disconnect without transition */ - case CMD_DISCONNECT: - if (message.arg2 == SYNCHRONOUS_CALL) { - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand(); - notifyOnMsgObject(message); - } else { - /* asynchronous handling */ - WifiNative.disconnectCommand(); - } - break; - case CMD_RECONNECT: - if (message.arg2 == SYNCHRONOUS_CALL) { - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = WifiNative.reconnectCommand(); - notifyOnMsgObject(message); - } else { - /* asynchronous handling */ - WifiNative.reconnectCommand(); - } - break; - case CMD_REASSOCIATE: - if (message.arg2 == SYNCHRONOUS_CALL) { - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = WifiNative.reassociateCommand(); - notifyOnMsgObject(message); - } else { - /* asynchronous handling */ - WifiNative.reassociateCommand(); - } - break; - case SCAN_RESULTS_EVENT: - /* Set the scan setting back to "connect" mode */ - WifiNative.setScanResultHandlingCommand(CONNECT_MODE); - /* Handle scan results */ - return NOT_HANDLED; - case NETWORK_CONNECTION_EVENT: - Log.d(TAG,"Network connection established"); - stateChangeResult = (StateChangeResult) message.obj; - - /* Remove any notifications */ - setNotificationVisible(false, 0, false, 0); - resetNotificationTimer(); - - mWifiInfo.setBSSID(mLastBssid = stateChangeResult.BSSID); - mWifiInfo.setNetworkId(stateChangeResult.networkId); - mLastNetworkId = stateChangeResult.networkId; - - /* send event to CM & network change broadcast */ - setDetailedState(DetailedState.OBTAINING_IPADDR); - sendNetworkStateChangeBroadcast(mLastBssid); - - transitionTo(mConnectingState); - break; - case NETWORK_DISCONNECTION_EVENT: - Log.d(TAG,"Network connection lost"); - handleNetworkDisconnect(); - transitionTo(mDisconnectedState); - break; - case CMD_GET_RSSI: - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.intValue = WifiNative.getRssiCommand(); - notifyOnMsgObject(message); - break; - case CMD_GET_RSSI_APPROX: - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.intValue = WifiNative.getRssiApproxCommand(); - notifyOnMsgObject(message); - break; - case CMD_GET_LINK_SPEED: - syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.intValue = WifiNative.getLinkSpeedCommand(); - notifyOnMsgObject(message); - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class ConnectingState extends HierarchicalState { - boolean modifiedBluetoothCoexistenceMode; - int powerMode; - Thread mDhcpThread; - - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - - if (!mUseStaticIp) { - - mDhcpThread = null; - modifiedBluetoothCoexistenceMode = false; - powerMode = DRIVER_POWER_MODE_AUTO; - - if (shouldDisableCoexistenceMode()) { - /* - * There are problems setting the Wi-Fi driver's power - * mode to active when bluetooth coexistence mode is - * enabled or sense. - * <p> - * We set Wi-Fi to active mode when - * obtaining an IP address because we've found - * compatibility issues with some routers with low power - * mode. - * <p> - * In order for this active power mode to properly be set, - * we disable coexistence mode until we're done with - * obtaining an IP address. One exception is if we - * are currently connected to a headset, since disabling - * coexistence would interrupt that connection. - */ - modifiedBluetoothCoexistenceMode = true; - - // Disable the coexistence mode - WifiNative.setBluetoothCoexistenceModeCommand( - WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); - } - - powerMode = WifiNative.getPowerModeCommand(); - if (powerMode < 0) { - // Handle the case where supplicant driver does not support - // getPowerModeCommand. - powerMode = DRIVER_POWER_MODE_AUTO; - } - if (powerMode != DRIVER_POWER_MODE_ACTIVE) { - WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE); - } - - Log.d(TAG, "DHCP request started"); - mDhcpThread = new Thread(new Runnable() { - public void run() { - if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) { - Log.d(TAG, "DHCP request succeeded"); - sendMessage(CMD_IP_CONFIG_SUCCESS); - } else { - Log.d(TAG, "DHCP request failed: " + - NetworkUtils.getDhcpError()); - sendMessage(CMD_IP_CONFIG_FAILURE); - } - } - }); - mDhcpThread.start(); - } else { - if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) { - Log.v(TAG, "Static IP configuration succeeded"); - sendMessage(CMD_IP_CONFIG_SUCCESS); - } else { - Log.v(TAG, "Static IP configuration failed"); - sendMessage(CMD_IP_CONFIG_FAILURE); - } - } - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - - switch(message.what) { - case CMD_IP_CONFIG_SUCCESS: - mReconnectCount = 0; - mLastSignalLevel = -1; // force update of signal strength - mWifiInfo.setIpAddress(mDhcpInfo.ipAddress); - Log.d(TAG, "IP configuration: " + mDhcpInfo); - configureNetworkProperties(); - setDetailedState(DetailedState.CONNECTED); - sendNetworkStateChangeBroadcast(mLastBssid); - transitionTo(mConnectedState); - break; - case CMD_IP_CONFIG_FAILURE: - mWifiInfo.setIpAddress(0); - - Log.e(TAG, "IP configuration failed"); - /** - * If we've exceeded the maximum number of retries for DHCP - * to a given network, disable the network - */ - if (++mReconnectCount > getMaxDhcpRetries()) { - Log.e(TAG, "Failed " + - mReconnectCount + " times, Disabling " + mLastNetworkId); - WifiNative.disableNetworkCommand(mLastNetworkId); - } - - /* DHCP times out after about 30 seconds, we do a - * disconnect and an immediate reconnect to try again - */ - WifiNative.disconnectCommand(); - WifiNative.reconnectCommand(); - transitionTo(mDisconnectingState); - break; - case CMD_DISCONNECT: - if (message.arg2 == SYNCHRONOUS_CALL) { - SyncParams syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand(); - notifyOnMsgObject(message); - } else { - /* asynchronous handling */ - WifiNative.disconnectCommand(); - } - transitionTo(mDisconnectingState); - break; - /* Ignore */ - case NETWORK_CONNECTION_EVENT: - break; - case CMD_STOP_DRIVER: - sendMessage(CMD_DISCONNECT); - deferMessage(message); - break; - case CMD_SET_SCAN_MODE: - if (message.arg1 == SCAN_ONLY_MODE) { - sendMessage(CMD_DISCONNECT); - deferMessage(message); - } - break; - case CMD_RECONFIGURE_IP: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - - @Override - public void exit() { - /* reset power state & bluetooth coexistence if on DHCP */ - if (!mUseStaticIp) { - if (powerMode != DRIVER_POWER_MODE_ACTIVE) { - WifiNative.setPowerModeCommand(powerMode); - } - - if (modifiedBluetoothCoexistenceMode) { - // Set the coexistence mode back to its default value - WifiNative.setBluetoothCoexistenceModeCommand( - WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); - } - } - - } - } - - class ConnectedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch (message.what) { - case CMD_DISCONNECT: - if (message.arg2 == SYNCHRONOUS_CALL) { - SyncParams syncParams = (SyncParams) message.obj; - syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand(); - notifyOnMsgObject(message); - } else { - /* asynchronous handling */ - WifiNative.disconnectCommand(); - } - transitionTo(mDisconnectingState); - break; - case CMD_RECONFIGURE_IP: - Log.d(TAG,"Reconfiguring IP on connection"); - NetworkUtils.resetConnections(mInterfaceName); - transitionTo(mConnectingState); - break; - case CMD_STOP_DRIVER: - sendMessage(CMD_DISCONNECT); - deferMessage(message); - break; - case CMD_SET_SCAN_MODE: - if (message.arg1 == SCAN_ONLY_MODE) { - sendMessage(CMD_DISCONNECT); - deferMessage(message); - } - break; - /* Ignore */ - case NETWORK_CONNECTION_EVENT: - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class DisconnectingState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch (message.what) { - case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */ - deferMessage(message); - break; - case CMD_SET_SCAN_MODE: - if (message.arg1 == SCAN_ONLY_MODE) { - deferMessage(message); - } - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class DisconnectedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch (message.what) { - case CMD_SET_SCAN_MODE: - if (message.arg1 == SCAN_ONLY_MODE) { - WifiNative.setScanResultHandlingCommand(message.arg1); - //Supplicant disconnect to prevent further connects - WifiNative.disconnectCommand(); - mIsScanMode = true; - transitionTo(mScanModeState); - } - break; - /* Ignore network disconnect */ - case NETWORK_DISCONNECTION_EVENT: - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class SoftApStartedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch(message.what) { - case CMD_STOP_AP: - Log.d(TAG,"Stopping Soft AP"); - setWifiApState(WIFI_AP_STATE_DISABLING); - try { - nwService.stopAccessPoint(); - } catch(Exception e) { - Log.e(TAG, "Exception in stopAccessPoint()"); - } - transitionTo(mDriverLoadedState); - break; - case CMD_START_AP: - Log.d(TAG,"SoftAP set on a running access point"); - try { - nwService.setAccessPoint((WifiConfiguration) message.obj, - mInterfaceName, - SOFTAP_IFACE); - } catch(Exception e) { - Log.e(TAG, "Exception in nwService during soft AP set"); - try { - nwService.stopAccessPoint(); - } catch (Exception ee) { - Slog.e(TAG, "Could not stop AP, :" + ee); - } - sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0)); - } - break; - /* Fail client mode operation when soft AP is enabled */ - case CMD_START_SUPPLICANT: - Log.e(TAG,"Cannot start supplicant with a running soft AP"); - setWifiState(WIFI_STATE_UNKNOWN); - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - - class SupplicantStateTracker extends HierarchicalStateMachine { - - private int mRssiPollToken = 0; - - /** - * The max number of the WPA supplicant loop iterations before we - * decide that the loop should be terminated: - */ - private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4; - private int mLoopDetectIndex = 0; - private int mLoopDetectCount = 0; - - /** - * Supplicant state change commands follow - * the ordinal values defined in SupplicantState.java - */ - private static final int DISCONNECTED = 0; - private static final int INACTIVE = 1; - private static final int SCANNING = 2; - private static final int ASSOCIATING = 3; - private static final int ASSOCIATED = 4; - private static final int FOUR_WAY_HANDSHAKE = 5; - private static final int GROUP_HANDSHAKE = 6; - private static final int COMPLETED = 7; - private static final int DORMANT = 8; - private static final int UNINITIALIZED = 9; - private static final int INVALID = 10; - - private HierarchicalState mUninitializedState; - private HierarchicalState mInitializedState; - private HierarchicalState mInactiveState; - private HierarchicalState mDisconnectState; - private HierarchicalState mScanState; - private HierarchicalState mConnectState; - private HierarchicalState mHandshakeState; - private HierarchicalState mCompletedState; - private HierarchicalState mDormantState; - - - public SupplicantStateTracker(Context context, Handler target) { - super(TAG, target.getLooper()); - - mUninitializedState = new UninitializedState(); - mInitializedState = new InitializedState(); - mInactiveState = new InactiveState(); - mDisconnectState = new DisconnectedState(); - mScanState = new ScanState(); - mConnectState = new ConnectState(); - mHandshakeState = new HandshakeState(); - mCompletedState = new CompletedState(); - mDormantState = new DormantState(); - - - addState(mUninitializedState); - addState(mInitializedState); - addState(mInactiveState, mInitializedState); - addState(mDisconnectState, mInitializedState); - addState(mScanState, mInitializedState); - addState(mConnectState, mInitializedState); - addState(mHandshakeState, mConnectState); - addState(mCompletedState, mConnectState); - addState(mDormantState, mInitializedState); - - setInitialState(mUninitializedState); - - //start the state machine - start(); - } - - public void handleEvent(StateChangeResult stateChangeResult) { - SupplicantState newState = (SupplicantState) stateChangeResult.state; - - // Supplicant state change - // [31-13] Reserved for future use - // [8 - 0] Supplicant state (as defined in SupplicantState.java) - // 50023 supplicant_state_changed (custom|1|5) - EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, newState.ordinal()); - - sendMessage(obtainMessage(newState.ordinal(), stateChangeResult)); - } - - public void resetSupplicantState() { - transitionTo(mUninitializedState); - } - - private void resetLoopDetection() { - mLoopDetectCount = 0; - mLoopDetectIndex = 0; - } - - private boolean handleTransition(Message msg) { - if (DBG) Log.d(TAG, getName() + msg.toString() + "\n"); - switch (msg.what) { - case DISCONNECTED: - transitionTo(mDisconnectState); - break; - case SCANNING: - transitionTo(mScanState); - break; - case ASSOCIATING: - StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; - /* BSSID is valid only in ASSOCIATING state */ - mWifiInfo.setBSSID(stateChangeResult.BSSID); - //$FALL-THROUGH$ - case ASSOCIATED: - case FOUR_WAY_HANDSHAKE: - case GROUP_HANDSHAKE: - transitionTo(mHandshakeState); - break; - case COMPLETED: - transitionTo(mCompletedState); - break; - case DORMANT: - transitionTo(mDormantState); - break; - case INACTIVE: - transitionTo(mInactiveState); - break; - case UNINITIALIZED: - case INVALID: - transitionTo(mUninitializedState); - break; - default: - return NOT_HANDLED; - } - StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; - SupplicantState supState = (SupplicantState) stateChangeResult.state; - setDetailedState(WifiInfo.getDetailedStateOf(supState)); - mWifiInfo.setSupplicantState(supState); - mWifiInfo.setNetworkId(stateChangeResult.networkId); - //TODO: Modify WifiMonitor to report SSID on events - //mWifiInfo.setSSID() - return HANDLED; - } - - /******************************************************** - * HSM states - *******************************************************/ - - class InitializedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch (message.what) { - case CMD_START_SCAN: - WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); - break; - default: - if (DBG) Log.w(TAG, "Ignoring " + message); - break; - } - return HANDLED; - } - } - - class UninitializedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - mNetworkInfo.setIsAvailable(false); - resetLoopDetection(); - mPasswordKeyMayBeIncorrect = false; - } - @Override - public boolean processMessage(Message message) { - switch(message.what) { - default: - if (!handleTransition(message)) { - if (DBG) Log.w(TAG, "Ignoring " + message); - } - break; - } - return HANDLED; - } - } - - class InactiveState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - Message message = getCurrentMessage(); - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - - mNetworkInfo.setIsAvailable(false); - resetLoopDetection(); - mPasswordKeyMayBeIncorrect = false; - - sendSupplicantStateChangedBroadcast(stateChangeResult, false); - } - @Override - public boolean processMessage(Message message) { - return handleTransition(message); - } - } - - - class DisconnectedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - Message message = getCurrentMessage(); - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - - mNetworkInfo.setIsAvailable(true); - resetLoopDetection(); - - /* If a disconnect event happens after a password key failure - * event, disable the network - */ - if (mPasswordKeyMayBeIncorrect) { - Log.d(TAG, "Failed to authenticate, disabling network " + - mWifiInfo.getNetworkId()); - WifiNative.disableNetworkCommand(mWifiInfo.getNetworkId()); - mPasswordKeyMayBeIncorrect = false; - sendSupplicantStateChangedBroadcast(stateChangeResult, true); - } - else { - sendSupplicantStateChangedBroadcast(stateChangeResult, false); - } - } - @Override - public boolean processMessage(Message message) { - return handleTransition(message); - } - } - - class ScanState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - Message message = getCurrentMessage(); - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - - mNetworkInfo.setIsAvailable(true); - mPasswordKeyMayBeIncorrect = false; - resetLoopDetection(); - sendSupplicantStateChangedBroadcast(stateChangeResult, false); - } - @Override - public boolean processMessage(Message message) { - return handleTransition(message); - } - } - - class ConnectState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - } - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case CMD_START_SCAN: - WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); - WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class HandshakeState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - final Message message = getCurrentMessage(); - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - - mNetworkInfo.setIsAvailable(true); - - if (mLoopDetectIndex > message.what) { - mLoopDetectCount++; - } - if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) { - WifiNative.disableNetworkCommand(stateChangeResult.networkId); - mLoopDetectCount = 0; - } - - mLoopDetectIndex = message.what; - - mPasswordKeyMayBeIncorrect = false; - sendSupplicantStateChangedBroadcast(stateChangeResult, false); - } - @Override - public boolean processMessage(Message message) { - return handleTransition(message); - } - } - - class CompletedState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - Message message = getCurrentMessage(); - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - - mNetworkInfo.setIsAvailable(true); - - mRssiPollToken++; - if (mEnableRssiPolling) { - sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), - POLL_RSSI_INTERVAL_MSECS); - } - - resetLoopDetection(); - - mPasswordKeyMayBeIncorrect = false; - sendSupplicantStateChangedBroadcast(stateChangeResult, false); - } - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case ASSOCIATING: - case ASSOCIATED: - case FOUR_WAY_HANDSHAKE: - case GROUP_HANDSHAKE: - case COMPLETED: - break; - case CMD_RSSI_POLL: - if (message.arg1 == mRssiPollToken) { - // Get Info and continue polling - requestPolledInfo(); - sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), - POLL_RSSI_INTERVAL_MSECS); - } else { - // Polling has completed - } - break; - case CMD_ENABLE_RSSI_POLL: - mRssiPollToken++; - if (mEnableRssiPolling) { - // first poll - requestPolledInfo(); - sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), - POLL_RSSI_INTERVAL_MSECS); - } - break; - default: - return handleTransition(message); - } - return HANDLED; - } - } - - class DormantState extends HierarchicalState { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - Message message = getCurrentMessage(); - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - - mNetworkInfo.setIsAvailable(true); - resetLoopDetection(); - mPasswordKeyMayBeIncorrect = false; - - sendSupplicantStateChangedBroadcast(stateChangeResult, false); - - /* TODO: reconnect is now being handled at DHCP failure handling - * If we run into issues with staying in Dormant state, might - * need a reconnect here - */ - } - @Override - public boolean processMessage(Message message) { - return handleTransition(message); - } - } - } - - private class NotificationEnabledSettingObserver extends ContentObserver { - - public NotificationEnabledSettingObserver(Handler handler) { - super(handler); - } - - public void register() { - ContentResolver cr = mContext.getContentResolver(); - cr.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this); - mNotificationEnabled = getValue(); - } - - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - - mNotificationEnabled = getValue(); - if (!mNotificationEnabled) { - // Remove any notification that may be showing - setNotificationVisible(false, 0, true, 0); - } - - resetNotificationTimer(); - } - - private boolean getValue() { - return Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1; - } - } -} +}
\ No newline at end of file |