WifiStateMachine.java revision fcc0845cf9990470d498dcaa036f0ae6487ddf34
15f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka/* 25f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project 35f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * 45f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 55f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * you may not use this file except in compliance with the License. 65f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * You may obtain a copy of the License at 75f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * 85f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 95f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * 105f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 115f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 125f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * See the License for the specific language governing permissions and 145f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * limitations under the License. 155f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka */ 165f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 175f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokapackage android.net.wifi; 185f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 195f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 205f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 215f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 225f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 235f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 245f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 255f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka/** 265f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * TODO: Add soft AP states as part of WIFI_STATE_XXX 275f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Retain WIFI_STATE_ENABLING that indicates driver is loading 285f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started 295f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * and WIFI_STATE_FAILED for failure 305f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Deprecate WIFI_STATE_UNKNOWN 315f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * 325f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Doing this will simplify the logic for sending broadcasts 335f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka */ 345f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; 355f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 365f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 375f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 385f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 395f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 405f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.app.AlarmManager; 415f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.app.PendingIntent; 425f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.app.backup.IBackupManager; 435f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.bluetooth.BluetoothAdapter; 445f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.content.BroadcastReceiver; 455f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.content.Context; 465f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.content.Intent; 475f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.content.IntentFilter; 485f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.ConnectivityManager; 495f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.DhcpInfo; 505f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.DhcpInfoInternal; 515f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.InterfaceConfiguration; 525f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.LinkAddress; 535f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.LinkProperties; 545f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.NetworkInfo; 555f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.NetworkInfo.DetailedState; 565f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.NetworkUtils; 575f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.net.wifi.WpsResult.Status; 585f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.Binder; 595f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.IBinder; 605f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.INetworkManagementService; 615f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.Message; 625f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.PowerManager; 635f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.Process; 645f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.RemoteException; 655f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.ServiceManager; 665f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.SystemProperties; 675f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.os.WorkSource; 685f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.provider.Settings; 695f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.util.EventLog; 705f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.util.Log; 715f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport android.util.LruCache; 725f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 735f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport com.android.internal.app.IBatteryStats; 745f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport com.android.internal.util.AsyncChannel; 755f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport com.android.internal.util.HierarchicalState; 765f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport com.android.internal.util.HierarchicalStateMachine; 775f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 785f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport java.net.InetAddress; 795f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport java.util.ArrayList; 805f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport java.util.List; 815f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport java.util.concurrent.atomic.AtomicInteger; 825f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokaimport java.util.regex.Pattern; 835f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 845f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka/** 855f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * Track the state of Wifi connectivity. All event handling is done here, 865f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * and all changes in connectivity state are initiated here. 875f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * 885f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka * @hide 895f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka */ 905f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaokapublic class WifiStateMachine extends HierarchicalStateMachine { 915f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 925f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka private static final String TAG = "WifiStateMachine"; 935f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka private static final String NETWORKTYPE = "WIFI"; 945f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka private static final boolean DBG = false; 955f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 965f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka /* TODO: fetch a configurable interface */ 975f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka private static final String SOFTAP_IFACE = "wl0.1"; 985f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 995f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka private WifiMonitor mWifiMonitor; 1005f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka private INetworkManagementService nwService; 1015f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka private ConnectivityManager mCm; 1025f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka 1035f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka /* Scan results handling */ 1045f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka private List<ScanResult> mScanResults; 1055f32a47e4536ce55fdc8182f1a206e417c951c25Tadashi G. Takaoka private static final Pattern scanResultPattern = Pattern.compile("\t+"); 106 private static final int SCAN_RESULT_CACHE_SIZE = 80; 107 private final LruCache<String, ScanResult> mScanResultCache; 108 109 private String mInterfaceName; 110 111 private int mLastSignalLevel = -1; 112 private String mLastBssid; 113 private int mLastNetworkId; 114 private boolean mEnableRssiPolling = false; 115 private boolean mEnableBackgroundScan = false; 116 private int mRssiPollToken = 0; 117 private int mReconnectCount = 0; 118 private boolean mIsScanMode = false; 119 private boolean mScanResultIsPending = false; 120 121 private boolean mBluetoothConnectionActive = false; 122 123 /** 124 * Interval in milliseconds between polling for RSSI 125 * and linkspeed information 126 */ 127 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 128 129 /** 130 * Delay between supplicant restarts upon failure to establish connection 131 */ 132 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; 133 134 /** 135 * Number of times we attempt to restart supplicant 136 */ 137 private static final int SUPPLICANT_RESTART_TRIES = 5; 138 139 private int mSupplicantRestartCount = 0; 140 141 private LinkProperties mLinkProperties; 142 143 // Wakelock held during wifi start/stop and driver load/unload 144 private PowerManager.WakeLock mWakeLock; 145 146 private Context mContext; 147 148 private DhcpInfoInternal mDhcpInfoInternal; 149 private WifiInfo mWifiInfo; 150 private NetworkInfo mNetworkInfo; 151 private SupplicantStateTracker mSupplicantStateTracker; 152 private WpsStateMachine mWpsStateMachine; 153 154 private AlarmManager mAlarmManager; 155 private PendingIntent mScanIntent; 156 /* Tracks current frequency mode */ 157 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); 158 159 // Channel for sending replies. 160 private AsyncChannel mReplyChannel = new AsyncChannel(); 161 162 // Event log tags (must be in sync with event-log-tags) 163 private static final int EVENTLOG_WIFI_STATE_CHANGED = 50021; 164 private static final int EVENTLOG_WIFI_EVENT_HANDLED = 50022; 165 private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED = 50023; 166 167 /* Load the driver */ 168 static final int CMD_LOAD_DRIVER = 1; 169 /* Unload the driver */ 170 static final int CMD_UNLOAD_DRIVER = 2; 171 /* Indicates driver load succeeded */ 172 static final int CMD_LOAD_DRIVER_SUCCESS = 3; 173 /* Indicates driver load failed */ 174 static final int CMD_LOAD_DRIVER_FAILURE = 4; 175 /* Indicates driver unload succeeded */ 176 static final int CMD_UNLOAD_DRIVER_SUCCESS = 5; 177 /* Indicates driver unload failed */ 178 static final int CMD_UNLOAD_DRIVER_FAILURE = 6; 179 180 /* Start the supplicant */ 181 static final int CMD_START_SUPPLICANT = 11; 182 /* Stop the supplicant */ 183 static final int CMD_STOP_SUPPLICANT = 12; 184 /* Start the driver */ 185 static final int CMD_START_DRIVER = 13; 186 /* Start the driver */ 187 static final int CMD_STOP_DRIVER = 14; 188 /* Indicates DHCP succeded */ 189 static final int CMD_IP_CONFIG_SUCCESS = 15; 190 /* Indicates DHCP failed */ 191 static final int CMD_IP_CONFIG_FAILURE = 16; 192 193 /* Start the soft access point */ 194 static final int CMD_START_AP = 21; 195 /* Stop the soft access point */ 196 static final int CMD_STOP_AP = 22; 197 198 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = 23; 199 200 /* Supplicant events */ 201 /* Connection to supplicant established */ 202 static final int SUP_CONNECTION_EVENT = 31; 203 /* Connection to supplicant lost */ 204 static final int SUP_DISCONNECTION_EVENT = 32; 205 /* Driver start completed */ 206 static final int DRIVER_START_EVENT = 33; 207 /* Driver stop completed */ 208 static final int DRIVER_STOP_EVENT = 34; 209 /* Network connection completed */ 210 static final int NETWORK_CONNECTION_EVENT = 36; 211 /* Network disconnection completed */ 212 static final int NETWORK_DISCONNECTION_EVENT = 37; 213 /* Scan results are available */ 214 static final int SCAN_RESULTS_EVENT = 38; 215 /* Supplicate state changed */ 216 static final int SUPPLICANT_STATE_CHANGE_EVENT = 39; 217 /* Password failure and EAP authentication failure */ 218 static final int AUTHENTICATION_FAILURE_EVENT = 40; 219 /* WPS overlap detected */ 220 static final int WPS_OVERLAP_EVENT = 41; 221 222 223 /* Supplicant commands */ 224 /* Is supplicant alive ? */ 225 static final int CMD_PING_SUPPLICANT = 51; 226 /* Add/update a network configuration */ 227 static final int CMD_ADD_OR_UPDATE_NETWORK = 52; 228 /* Delete a network */ 229 static final int CMD_REMOVE_NETWORK = 53; 230 /* Enable a network. The device will attempt a connection to the given network. */ 231 static final int CMD_ENABLE_NETWORK = 54; 232 /* Enable all networks */ 233 static final int CMD_ENABLE_ALL_NETWORKS = 55; 234 /* Disable a network. The device does not attempt a connection to the given network. */ 235 static final int CMD_DISABLE_NETWORK = 56; 236 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 237 static final int CMD_BLACKLIST_NETWORK = 57; 238 /* Clear the blacklist network list */ 239 static final int CMD_CLEAR_BLACKLIST = 58; 240 /* Save configuration */ 241 static final int CMD_SAVE_CONFIG = 59; 242 243 /* Supplicant commands after driver start*/ 244 /* Initiate a scan */ 245 static final int CMD_START_SCAN = 71; 246 /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */ 247 static final int CMD_SET_SCAN_MODE = 72; 248 /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */ 249 static final int CMD_SET_SCAN_TYPE = 73; 250 /* Disconnect from a network */ 251 static final int CMD_DISCONNECT = 74; 252 /* Reconnect to a network */ 253 static final int CMD_RECONNECT = 75; 254 /* Reassociate to a network */ 255 static final int CMD_REASSOCIATE = 76; 256 /* Controls power mode and suspend mode optimizations 257 * 258 * When high perf mode is enabled, power mode is set to 259 * POWER_MODE_ACTIVE and suspend mode optimizations are disabled 260 * 261 * When high perf mode is disabled, power mode is set to 262 * POWER_MODE_AUTO and suspend mode optimizations are enabled 263 * 264 * Suspend mode optimizations include: 265 * - packet filtering 266 * - turn off roaming 267 * - DTIM wake up settings 268 */ 269 static final int CMD_SET_HIGH_PERF_MODE = 77; 270 /* Set the country code */ 271 static final int CMD_SET_COUNTRY_CODE = 80; 272 /* Request connectivity manager wake lock before driver stop */ 273 static final int CMD_REQUEST_CM_WAKELOCK = 81; 274 /* Enables RSSI poll */ 275 static final int CMD_ENABLE_RSSI_POLL = 82; 276 /* RSSI poll */ 277 static final int CMD_RSSI_POLL = 83; 278 /* Set up packet filtering */ 279 static final int CMD_START_PACKET_FILTERING = 84; 280 /* Clear packet filter */ 281 static final int CMD_STOP_PACKET_FILTERING = 85; 282 /* Connect to a specified network (network id 283 * or WifiConfiguration) This involves increasing 284 * the priority of the network, enabling the network 285 * (while disabling others) and issuing a reconnect. 286 * Note that CMD_RECONNECT just does a reconnect to 287 * an existing network. All the networks get enabled 288 * upon a successful connection or a failure. 289 */ 290 static final int CMD_CONNECT_NETWORK = 86; 291 /* Save the specified network. This involves adding 292 * an enabled network (if new) and updating the 293 * config and issuing a save on supplicant config. 294 */ 295 static final int CMD_SAVE_NETWORK = 87; 296 /* Delete the specified network. This involves 297 * removing the network and issuing a save on 298 * supplicant config. 299 */ 300 static final int CMD_FORGET_NETWORK = 88; 301 /* Start Wi-Fi protected setup */ 302 static final int CMD_START_WPS = 89; 303 /* Set the frequency band */ 304 static final int CMD_SET_FREQUENCY_BAND = 90; 305 /* Enable background scan for configured networks */ 306 static final int CMD_ENABLE_BACKGROUND_SCAN = 91; 307 308 /* Commands from/to the SupplicantStateTracker */ 309 /* Reset the supplicant state tracker */ 310 static final int CMD_RESET_SUPPLICANT_STATE = 111; 311 312 /* Commands/events reported by WpsStateMachine */ 313 /* Indicates the completion of WPS activity */ 314 static final int WPS_COMPLETED_EVENT = 121; 315 /* Reset the WPS state machine */ 316 static final int CMD_RESET_WPS_STATE = 122; 317 318 private static final int CONNECT_MODE = 1; 319 private static final int SCAN_ONLY_MODE = 2; 320 321 private static final int SCAN_ACTIVE = 1; 322 private static final int SCAN_PASSIVE = 2; 323 324 private static final int SUCCESS = 1; 325 private static final int FAILURE = -1; 326 327 /** 328 * The maximum number of times we will retry a connection to an access point 329 * for which we have failed in acquiring an IP address from DHCP. A value of 330 * N means that we will make N+1 connection attempts in all. 331 * <p> 332 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 333 * value if a Settings value is not present. 334 */ 335 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 336 337 private static final int POWER_MODE_ACTIVE = 1; 338 private static final int POWER_MODE_AUTO = 0; 339 340 /** 341 * See {@link Settings.Secure#WIFI_SCAN_INTERVAL_MS}. This is the default value if a 342 * Settings.Secure value is not present. 343 */ 344 private static final long DEFAULT_SCAN_INTERVAL_MS = 60 * 1000; /* 1 minute */ 345 346 /* Default parent state */ 347 private HierarchicalState mDefaultState = new DefaultState(); 348 /* Temporary initial state */ 349 private HierarchicalState mInitialState = new InitialState(); 350 /* Unloading the driver */ 351 private HierarchicalState mDriverUnloadingState = new DriverUnloadingState(); 352 /* Loading the driver */ 353 private HierarchicalState mDriverUnloadedState = new DriverUnloadedState(); 354 /* Driver load/unload failed */ 355 private HierarchicalState mDriverFailedState = new DriverFailedState(); 356 /* Driver loading */ 357 private HierarchicalState mDriverLoadingState = new DriverLoadingState(); 358 /* Driver loaded */ 359 private HierarchicalState mDriverLoadedState = new DriverLoadedState(); 360 /* Driver loaded, waiting for supplicant to start */ 361 private HierarchicalState mSupplicantStartingState = new SupplicantStartingState(); 362 /* Driver loaded and supplicant ready */ 363 private HierarchicalState mSupplicantStartedState = new SupplicantStartedState(); 364 /* Waiting for supplicant to stop and monitor to exit */ 365 private HierarchicalState mSupplicantStoppingState = new SupplicantStoppingState(); 366 /* Driver start issued, waiting for completed event */ 367 private HierarchicalState mDriverStartingState = new DriverStartingState(); 368 /* Driver started */ 369 private HierarchicalState mDriverStartedState = new DriverStartedState(); 370 /* Driver stopping */ 371 private HierarchicalState mDriverStoppingState = new DriverStoppingState(); 372 /* Driver stopped */ 373 private HierarchicalState mDriverStoppedState = new DriverStoppedState(); 374 /* Scan for networks, no connection will be established */ 375 private HierarchicalState mScanModeState = new ScanModeState(); 376 /* Connecting to an access point */ 377 private HierarchicalState mConnectModeState = new ConnectModeState(); 378 /* Fetching IP after network connection (assoc+auth complete) */ 379 private HierarchicalState mConnectingState = new ConnectingState(); 380 /* Connected with IP addr */ 381 private HierarchicalState mConnectedState = new ConnectedState(); 382 /* disconnect issued, waiting for network disconnect confirmation */ 383 private HierarchicalState mDisconnectingState = new DisconnectingState(); 384 /* Network is not connected, supplicant assoc+auth is not complete */ 385 private HierarchicalState mDisconnectedState = new DisconnectedState(); 386 /* Waiting for WPS to be completed*/ 387 private HierarchicalState mWaitForWpsCompletionState = new WaitForWpsCompletionState(); 388 389 /* Soft Ap is running */ 390 private HierarchicalState mSoftApStartedState = new SoftApStartedState(); 391 392 393 /** 394 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 395 * {@link WifiManager#WIFI_STATE_DISABLING}, 396 * {@link WifiManager#WIFI_STATE_ENABLED}, 397 * {@link WifiManager#WIFI_STATE_ENABLING}, 398 * {@link WifiManager#WIFI_STATE_UNKNOWN} 399 * 400 */ 401 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 402 403 /** 404 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 405 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 406 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 407 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 408 * {@link WifiManager#WIFI_AP_STATE_FAILED} 409 * 410 */ 411 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 412 413 private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid()); 414 private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid()); 415 416 private static final int SCAN_REQUEST = 0; 417 private static final String ACTION_START_SCAN = 418 "com.android.server.WifiManager.action.START_SCAN"; 419 420 /** 421 * Keep track of whether WIFI is running. 422 */ 423 private boolean mIsRunning = false; 424 425 /** 426 * Keep track of whether we last told the battery stats we had started. 427 */ 428 private boolean mReportedRunning = false; 429 430 /** 431 * Most recently set source of starting WIFI. 432 */ 433 private final WorkSource mRunningWifiUids = new WorkSource(); 434 435 /** 436 * The last reported UIDs that were responsible for starting WIFI. 437 */ 438 private final WorkSource mLastRunningWifiUids = new WorkSource(); 439 440 private final IBatteryStats mBatteryStats; 441 442 public WifiStateMachine(Context context, String wlanInterface) { 443 super(TAG); 444 445 mContext = context; 446 mInterfaceName = wlanInterface; 447 448 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 449 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); 450 451 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 452 nwService = INetworkManagementService.Stub.asInterface(b); 453 454 mWifiMonitor = new WifiMonitor(this); 455 mDhcpInfoInternal = new DhcpInfoInternal(); 456 mWifiInfo = new WifiInfo(); 457 mSupplicantStateTracker = new SupplicantStateTracker(context, this, getHandler()); 458 mWpsStateMachine = new WpsStateMachine(context, this, getHandler()); 459 mLinkProperties = new LinkProperties(); 460 461 mNetworkInfo.setIsAvailable(false); 462 mLinkProperties.clear(); 463 mLastBssid = null; 464 mLastNetworkId = -1; 465 mLastSignalLevel = -1; 466 467 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 468 Intent scanIntent = new Intent(ACTION_START_SCAN, null); 469 mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); 470 471 mContext.registerReceiver( 472 new BroadcastReceiver() { 473 @Override 474 public void onReceive(Context context, Intent intent) { 475 476 ArrayList<String> available = intent.getStringArrayListExtra( 477 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 478 ArrayList<String> active = intent.getStringArrayListExtra( 479 ConnectivityManager.EXTRA_ACTIVE_TETHER); 480 updateTetherState(available, active); 481 482 } 483 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 484 485 mContext.registerReceiver( 486 new BroadcastReceiver() { 487 @Override 488 public void onReceive(Context context, Intent intent) { 489 startScan(false); 490 } 491 }, 492 new IntentFilter(ACTION_START_SCAN)); 493 494 mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE); 495 496 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 497 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 498 499 addState(mDefaultState); 500 addState(mInitialState, mDefaultState); 501 addState(mDriverUnloadingState, mDefaultState); 502 addState(mDriverUnloadedState, mDefaultState); 503 addState(mDriverFailedState, mDriverUnloadedState); 504 addState(mDriverLoadingState, mDefaultState); 505 addState(mDriverLoadedState, mDefaultState); 506 addState(mSupplicantStartingState, mDefaultState); 507 addState(mSupplicantStartedState, mDefaultState); 508 addState(mDriverStartingState, mSupplicantStartedState); 509 addState(mDriverStartedState, mSupplicantStartedState); 510 addState(mScanModeState, mDriverStartedState); 511 addState(mConnectModeState, mDriverStartedState); 512 addState(mConnectingState, mConnectModeState); 513 addState(mConnectedState, mConnectModeState); 514 addState(mDisconnectingState, mConnectModeState); 515 addState(mDisconnectedState, mConnectModeState); 516 addState(mWaitForWpsCompletionState, mConnectModeState); 517 addState(mDriverStoppingState, mSupplicantStartedState); 518 addState(mDriverStoppedState, mSupplicantStartedState); 519 addState(mSupplicantStoppingState, mDefaultState); 520 addState(mSoftApStartedState, mDefaultState); 521 522 setInitialState(mInitialState); 523 524 if (DBG) setDbg(true); 525 526 //start the state machine 527 start(); 528 } 529 530 /********************************************************* 531 * Methods exposed for public use 532 ********************************************************/ 533 534 /** 535 * TODO: doc 536 */ 537 public boolean syncPingSupplicant(AsyncChannel channel) { 538 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 539 boolean result = (resultMsg.arg1 != FAILURE); 540 resultMsg.recycle(); 541 return result; 542 } 543 544 /** 545 * TODO: doc 546 */ 547 public void startScan(boolean forceActive) { 548 sendMessage(obtainMessage(CMD_START_SCAN, forceActive ? 549 SCAN_ACTIVE : SCAN_PASSIVE, 0)); 550 } 551 552 /** 553 * TODO: doc 554 */ 555 public void setWifiEnabled(boolean enable) { 556 mLastEnableUid.set(Binder.getCallingUid()); 557 if (enable) { 558 /* Argument is the state that is entered prior to load */ 559 sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0)); 560 sendMessage(CMD_START_SUPPLICANT); 561 } else { 562 sendMessage(CMD_STOP_SUPPLICANT); 563 /* Argument is the state that is entered upon success */ 564 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0)); 565 } 566 } 567 568 /** 569 * TODO: doc 570 */ 571 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) { 572 mLastApEnableUid.set(Binder.getCallingUid()); 573 if (enable) { 574 /* Argument is the state that is entered prior to load */ 575 sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0)); 576 sendMessage(obtainMessage(CMD_START_AP, wifiConfig)); 577 } else { 578 sendMessage(CMD_STOP_AP); 579 /* Argument is the state that is entered upon success */ 580 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0)); 581 } 582 } 583 584 /** 585 * TODO: doc 586 */ 587 public int syncGetWifiState() { 588 return mWifiState.get(); 589 } 590 591 /** 592 * TODO: doc 593 */ 594 public String syncGetWifiStateByName() { 595 switch (mWifiState.get()) { 596 case WIFI_STATE_DISABLING: 597 return "disabling"; 598 case WIFI_STATE_DISABLED: 599 return "disabled"; 600 case WIFI_STATE_ENABLING: 601 return "enabling"; 602 case WIFI_STATE_ENABLED: 603 return "enabled"; 604 case WIFI_STATE_UNKNOWN: 605 return "unknown state"; 606 default: 607 return "[invalid state]"; 608 } 609 } 610 611 /** 612 * TODO: doc 613 */ 614 public int syncGetWifiApState() { 615 return mWifiApState.get(); 616 } 617 618 /** 619 * TODO: doc 620 */ 621 public String syncGetWifiApStateByName() { 622 switch (mWifiApState.get()) { 623 case WIFI_AP_STATE_DISABLING: 624 return "disabling"; 625 case WIFI_AP_STATE_DISABLED: 626 return "disabled"; 627 case WIFI_AP_STATE_ENABLING: 628 return "enabling"; 629 case WIFI_AP_STATE_ENABLED: 630 return "enabled"; 631 case WIFI_AP_STATE_FAILED: 632 return "failed"; 633 default: 634 return "[invalid state]"; 635 } 636 } 637 638 /** 639 * Get status information for the current connection, if any. 640 * @return a {@link WifiInfo} object containing information about the current connection 641 * 642 */ 643 public WifiInfo syncRequestConnectionInfo() { 644 return mWifiInfo; 645 } 646 647 public DhcpInfo syncGetDhcpInfo() { 648 synchronized (mDhcpInfoInternal) { 649 return mDhcpInfoInternal.makeDhcpInfo(); 650 } 651 } 652 653 /** 654 * TODO: doc 655 */ 656 public void setDriverStart(boolean enable) { 657 if (enable) { 658 sendMessage(CMD_START_DRIVER); 659 } else { 660 sendMessage(CMD_STOP_DRIVER); 661 } 662 } 663 664 /** 665 * TODO: doc 666 */ 667 public void setScanOnlyMode(boolean enable) { 668 if (enable) { 669 sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0)); 670 } else { 671 sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0)); 672 } 673 } 674 675 /** 676 * TODO: doc 677 */ 678 public void setScanType(boolean active) { 679 if (active) { 680 sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0)); 681 } else { 682 sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0)); 683 } 684 } 685 686 /** 687 * TODO: doc 688 */ 689 public List<ScanResult> syncGetScanResultsList() { 690 return mScanResults; 691 } 692 693 /** 694 * Disconnect from Access Point 695 */ 696 public void disconnectCommand() { 697 sendMessage(CMD_DISCONNECT); 698 } 699 700 /** 701 * Initiate a reconnection to AP 702 */ 703 public void reconnectCommand() { 704 sendMessage(CMD_RECONNECT); 705 } 706 707 /** 708 * Initiate a re-association to AP 709 */ 710 public void reassociateCommand() { 711 sendMessage(CMD_REASSOCIATE); 712 } 713 714 /** 715 * Add a network synchronously 716 * 717 * @return network id of the new network 718 */ 719 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 720 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 721 int result = resultMsg.arg1; 722 resultMsg.recycle(); 723 return result; 724 } 725 726 public List<WifiConfiguration> syncGetConfiguredNetworks() { 727 return WifiConfigStore.getConfiguredNetworks(); 728 } 729 730 /** 731 * Delete a network 732 * 733 * @param networkId id of the network to be removed 734 */ 735 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 736 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 737 boolean result = (resultMsg.arg1 != FAILURE); 738 resultMsg.recycle(); 739 return result; 740 } 741 742 /** 743 * Enable a network 744 * 745 * @param netId network id of the network 746 * @param disableOthers true, if all other networks have to be disabled 747 * @return {@code true} if the operation succeeds, {@code false} otherwise 748 */ 749 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 750 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 751 disableOthers ? 1 : 0); 752 boolean result = (resultMsg.arg1 != FAILURE); 753 resultMsg.recycle(); 754 return result; 755 } 756 757 /** 758 * Disable a network 759 * 760 * @param netId network id of the network 761 * @return {@code true} if the operation succeeds, {@code false} otherwise 762 */ 763 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 764 Message resultMsg = channel.sendMessageSynchronously(CMD_DISABLE_NETWORK, netId); 765 boolean result = (resultMsg.arg1 != FAILURE); 766 resultMsg.recycle(); 767 return result; 768 } 769 770 /** 771 * Blacklist a BSSID. This will avoid the AP if there are 772 * alternate APs to connect 773 * 774 * @param bssid BSSID of the network 775 */ 776 public void addToBlacklist(String bssid) { 777 sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid)); 778 } 779 780 /** 781 * Clear the blacklist list 782 * 783 */ 784 public void clearBlacklist() { 785 sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST)); 786 } 787 788 public void connectNetwork(int netId) { 789 sendMessage(obtainMessage(CMD_CONNECT_NETWORK, netId, 0)); 790 } 791 792 public void connectNetwork(WifiConfiguration wifiConfig) { 793 /* arg1 is used to indicate netId, force a netId value of -1 when 794 * we are passing a configuration since the default value of 795 * 0 is a valid netId 796 */ 797 sendMessage(obtainMessage(CMD_CONNECT_NETWORK, -1, 0, wifiConfig)); 798 } 799 800 public void saveNetwork(WifiConfiguration wifiConfig) { 801 sendMessage(obtainMessage(CMD_SAVE_NETWORK, wifiConfig)); 802 } 803 804 public void forgetNetwork(int netId) { 805 sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0)); 806 } 807 808 public WpsResult startWps(AsyncChannel channel, WpsConfiguration config) { 809 WpsResult result; 810 switch (config.setup) { 811 case PIN_FROM_DEVICE: 812 case PBC: 813 case PIN_FROM_ACCESS_POINT: 814 //TODO: will go away with AsyncChannel use from settings 815 Message resultMsg = channel.sendMessageSynchronously(CMD_START_WPS, config); 816 result = (WpsResult) resultMsg.obj; 817 resultMsg.recycle(); 818 break; 819 default: 820 result = new WpsResult(Status.FAILURE); 821 break; 822 } 823 return result; 824 } 825 826 public void enableRssiPolling(boolean enabled) { 827 sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0)); 828 } 829 830 public void enableBackgroundScan(boolean enabled) { 831 sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0)); 832 } 833 834 public void enableAllNetworks() { 835 sendMessage(CMD_ENABLE_ALL_NETWORKS); 836 } 837 838 /** 839 * Start packet filtering 840 */ 841 public void startPacketFiltering() { 842 sendMessage(CMD_START_PACKET_FILTERING); 843 } 844 845 /** 846 * Stop packet filtering 847 */ 848 public void stopPacketFiltering() { 849 sendMessage(CMD_STOP_PACKET_FILTERING); 850 } 851 852 /** 853 * Set high performance mode of operation. 854 * Enabling would set active power mode and disable suspend optimizations; 855 * disabling would set auto power mode and enable suspend optimizations 856 * @param enable true if enable, false otherwise 857 */ 858 public void setHighPerfModeEnabled(boolean enable) { 859 sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0)); 860 } 861 862 /** 863 * Set the country code 864 * @param countryCode following ISO 3166 format 865 * @param persist {@code true} if the setting should be remembered. 866 */ 867 public void setCountryCode(String countryCode, boolean persist) { 868 if (persist) { 869 Settings.Secure.putString(mContext.getContentResolver(), 870 Settings.Secure.WIFI_COUNTRY_CODE, 871 countryCode); 872 } 873 sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode)); 874 } 875 876 /** 877 * Set the operational frequency band 878 * @param band 879 * @param persist {@code true} if the setting should be remembered. 880 */ 881 public void setFrequencyBand(int band, boolean persist) { 882 if (persist) { 883 Settings.Secure.putInt(mContext.getContentResolver(), 884 Settings.Secure.WIFI_FREQUENCY_BAND, 885 band); 886 } 887 sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0)); 888 } 889 890 /** 891 * Returns the operational frequency band 892 */ 893 public int getFrequencyBand() { 894 return mFrequencyBand.get(); 895 } 896 897 /** 898 * Send a message indicating bluetooth adapter connection state changed 899 */ 900 public void sendBluetoothAdapterStateChange(int state) { 901 sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0)); 902 } 903 904 /** 905 * Save configuration on supplicant 906 * 907 * @return {@code true} if the operation succeeds, {@code false} otherwise 908 * 909 * TODO: deprecate this 910 */ 911 public boolean syncSaveConfig(AsyncChannel channel) { 912 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 913 boolean result = (resultMsg.arg1 != FAILURE); 914 resultMsg.recycle(); 915 return result; 916 } 917 918 /** 919 * Request a wakelock with connectivity service to 920 * keep the device awake until we hand-off from wifi 921 * to an alternate network 922 */ 923 public void requestCmWakeLock() { 924 sendMessage(CMD_REQUEST_CM_WAKELOCK); 925 } 926 927 public void updateBatteryWorkSource(WorkSource newSource) { 928 synchronized (mRunningWifiUids) { 929 try { 930 if (newSource != null) { 931 mRunningWifiUids.set(newSource); 932 } 933 if (mIsRunning) { 934 if (mReportedRunning) { 935 // If the work source has changed since last time, need 936 // to remove old work from battery stats. 937 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 938 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 939 mRunningWifiUids); 940 mLastRunningWifiUids.set(mRunningWifiUids); 941 } 942 } else { 943 // Now being started, report it. 944 mBatteryStats.noteWifiRunning(mRunningWifiUids); 945 mLastRunningWifiUids.set(mRunningWifiUids); 946 mReportedRunning = true; 947 } 948 } else { 949 if (mReportedRunning) { 950 // Last reported we were running, time to stop. 951 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 952 mLastRunningWifiUids.clear(); 953 mReportedRunning = false; 954 } 955 } 956 mWakeLock.setWorkSource(newSource); 957 } catch (RemoteException ignore) { 958 } 959 } 960 } 961 962 @Override 963 public String toString() { 964 StringBuffer sb = new StringBuffer(); 965 String LS = System.getProperty("line.separator"); 966 sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS); 967 sb.append("mLinkProperties ").append(mLinkProperties).append(LS); 968 sb.append("mWifiInfo ").append(mWifiInfo).append(LS); 969 sb.append("mDhcpInfoInternal ").append(mDhcpInfoInternal).append(LS); 970 sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS); 971 sb.append("mLastSignalLevel ").append(mLastSignalLevel).append(LS); 972 sb.append("mLastBssid ").append(mLastBssid).append(LS); 973 sb.append("mLastNetworkId ").append(mLastNetworkId).append(LS); 974 sb.append("mReconnectCount ").append(mReconnectCount).append(LS); 975 sb.append("mIsScanMode ").append(mIsScanMode).append(LS); 976 sb.append("Supplicant status").append(LS) 977 .append(WifiNative.statusCommand()).append(LS).append(LS); 978 979 sb.append(WifiConfigStore.dump()); 980 return sb.toString(); 981 } 982 983 /********************************************************* 984 * Internal private functions 985 ********************************************************/ 986 987 private void updateTetherState(ArrayList<String> available, ArrayList<String> tethered) { 988 989 boolean wifiTethered = false; 990 boolean wifiAvailable = false; 991 992 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 993 INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); 994 995 if (mCm == null) { 996 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 997 } 998 999 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 1000 1001 for (String intf : available) { 1002 for (String regex : wifiRegexs) { 1003 if (intf.matches(regex)) { 1004 1005 InterfaceConfiguration ifcg = null; 1006 try { 1007 ifcg = service.getInterfaceConfig(intf); 1008 if (ifcg != null) { 1009 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 1010 ifcg.addr = new LinkAddress(InetAddress.getByName("192.168.43.1"), 24); 1011 ifcg.interfaceFlags = "[up]"; 1012 1013 service.setInterfaceConfig(intf, ifcg); 1014 } 1015 } catch (Exception e) { 1016 Log.e(TAG, "Error configuring interface " + intf + ", :" + e); 1017 setWifiApEnabled(null, false); 1018 return; 1019 } 1020 1021 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 1022 Log.e(TAG, "Error tethering on " + intf); 1023 setWifiApEnabled(null, false); 1024 return; 1025 } 1026 break; 1027 } 1028 } 1029 } 1030 } 1031 1032 /** 1033 * Set the country code from the system setting value, if any. 1034 */ 1035 private void setCountryCode() { 1036 String countryCode = Settings.Secure.getString(mContext.getContentResolver(), 1037 Settings.Secure.WIFI_COUNTRY_CODE); 1038 if (countryCode != null && !countryCode.isEmpty()) { 1039 setCountryCode(countryCode, false); 1040 } else { 1041 //use driver default 1042 } 1043 } 1044 1045 /** 1046 * Set the frequency band from the system setting value, if any. 1047 */ 1048 private void setFrequencyBand() { 1049 int band = Settings.Secure.getInt(mContext.getContentResolver(), 1050 Settings.Secure.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 1051 setFrequencyBand(band, false); 1052 } 1053 1054 private void setWifiState(int wifiState) { 1055 final int previousWifiState = mWifiState.get(); 1056 1057 try { 1058 if (wifiState == WIFI_STATE_ENABLED) { 1059 mBatteryStats.noteWifiOn(); 1060 } else if (wifiState == WIFI_STATE_DISABLED) { 1061 mBatteryStats.noteWifiOff(); 1062 } 1063 } catch (RemoteException e) { 1064 Log.e(TAG, "Failed to note battery stats in wifi"); 1065 } 1066 1067 mWifiState.set(wifiState); 1068 1069 if (DBG) Log.d(TAG, "setWifiState: " + syncGetWifiStateByName()); 1070 1071 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 1072 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1073 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 1074 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 1075 mContext.sendStickyBroadcast(intent); 1076 } 1077 1078 private void setWifiApState(int wifiApState) { 1079 final int previousWifiApState = mWifiApState.get(); 1080 1081 try { 1082 if (wifiApState == WIFI_AP_STATE_ENABLED) { 1083 mBatteryStats.noteWifiOn(); 1084 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 1085 mBatteryStats.noteWifiOff(); 1086 } 1087 } catch (RemoteException e) { 1088 Log.d(TAG, "Failed to note battery stats in wifi"); 1089 } 1090 1091 // Update state 1092 mWifiApState.set(wifiApState); 1093 1094 if (DBG) Log.d(TAG, "setWifiApState: " + syncGetWifiApStateByName()); 1095 1096 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 1097 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1098 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 1099 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 1100 mContext.sendStickyBroadcast(intent); 1101 } 1102 1103 /** 1104 * Parse the scan result line passed to us by wpa_supplicant (helper). 1105 * @param line the line to parse 1106 * @return the {@link ScanResult} object 1107 */ 1108 private ScanResult parseScanResult(String line) { 1109 ScanResult scanResult = null; 1110 if (line != null) { 1111 /* 1112 * Cache implementation (LinkedHashMap) is not synchronized, thus, 1113 * must synchronized here! 1114 */ 1115 synchronized (mScanResultCache) { 1116 String[] result = scanResultPattern.split(line); 1117 if (3 <= result.length && result.length <= 5) { 1118 String bssid = result[0]; 1119 // bssid | frequency | level | flags | ssid 1120 int frequency; 1121 int level; 1122 try { 1123 frequency = Integer.parseInt(result[1]); 1124 level = Integer.parseInt(result[2]); 1125 /* some implementations avoid negative values by adding 256 1126 * so we need to adjust for that here. 1127 */ 1128 if (level > 0) level -= 256; 1129 } catch (NumberFormatException e) { 1130 frequency = 0; 1131 level = 0; 1132 } 1133 1134 /* 1135 * The formatting of the results returned by 1136 * wpa_supplicant is intended to make the fields 1137 * line up nicely when printed, 1138 * not to make them easy to parse. So we have to 1139 * apply some heuristics to figure out which field 1140 * is the SSID and which field is the flags. 1141 */ 1142 String ssid; 1143 String flags; 1144 if (result.length == 4) { 1145 if (result[3].charAt(0) == '[') { 1146 flags = result[3]; 1147 ssid = ""; 1148 } else { 1149 flags = ""; 1150 ssid = result[3]; 1151 } 1152 } else if (result.length == 5) { 1153 flags = result[3]; 1154 ssid = result[4]; 1155 } else { 1156 // Here, we must have 3 fields: no flags and ssid 1157 // set 1158 flags = ""; 1159 ssid = ""; 1160 } 1161 1162 // bssid + ssid is the hash key 1163 String key = bssid + ssid; 1164 scanResult = mScanResultCache.get(key); 1165 if (scanResult != null) { 1166 scanResult.level = level; 1167 scanResult.SSID = ssid; 1168 scanResult.capabilities = flags; 1169 scanResult.frequency = frequency; 1170 } else { 1171 // Do not add scan results that have no SSID set 1172 if (0 < ssid.trim().length()) { 1173 scanResult = 1174 new ScanResult( 1175 ssid, bssid, flags, level, frequency); 1176 mScanResultCache.put(key, scanResult); 1177 } 1178 } 1179 } else { 1180 Log.w(TAG, "Misformatted scan result text with " + 1181 result.length + " fields: " + line); 1182 } 1183 } 1184 } 1185 1186 return scanResult; 1187 } 1188 1189 /** 1190 * scanResults input format 1191 * 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1 1192 * 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2 1193 */ 1194 private void setScanResults(String scanResults) { 1195 if (scanResults == null) { 1196 return; 1197 } 1198 1199 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1200 1201 int lineCount = 0; 1202 1203 int scanResultsLen = scanResults.length(); 1204 // Parse the result string, keeping in mind that the last line does 1205 // not end with a newline. 1206 for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) { 1207 if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') { 1208 ++lineCount; 1209 1210 if (lineCount == 1) { 1211 lineBeg = lineEnd + 1; 1212 continue; 1213 } 1214 if (lineEnd > lineBeg) { 1215 String line = scanResults.substring(lineBeg, lineEnd); 1216 ScanResult scanResult = parseScanResult(line); 1217 if (scanResult != null) { 1218 scanList.add(scanResult); 1219 } else { 1220 //TODO: hidden network handling 1221 } 1222 } 1223 lineBeg = lineEnd + 1; 1224 } 1225 } 1226 1227 mScanResults = scanList; 1228 } 1229 1230 private String fetchSSID() { 1231 String status = WifiNative.statusCommand(); 1232 if (status == null) { 1233 return null; 1234 } 1235 // extract ssid from a series of "name=value" 1236 String[] lines = status.split("\n"); 1237 for (String line : lines) { 1238 String[] prop = line.split(" *= *"); 1239 if (prop.length < 2) continue; 1240 String name = prop[0]; 1241 String value = prop[1]; 1242 if (name.equalsIgnoreCase("ssid")) return value; 1243 } 1244 return null; 1245 } 1246 1247 /* 1248 * Fetch RSSI and linkspeed on current connection 1249 */ 1250 private void fetchRssiAndLinkSpeedNative() { 1251 int newRssi = WifiNative.getRssiCommand(); 1252 if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values 1253 /* some implementations avoid negative values by adding 256 1254 * so we need to adjust for that here. 1255 */ 1256 if (newRssi > 0) newRssi -= 256; 1257 mWifiInfo.setRssi(newRssi); 1258 /* 1259 * Rather then sending the raw RSSI out every time it 1260 * changes, we precalculate the signal level that would 1261 * be displayed in the status bar, and only send the 1262 * broadcast if that much more coarse-grained number 1263 * changes. This cuts down greatly on the number of 1264 * broadcasts, at the cost of not mWifiInforming others 1265 * interested in RSSI of all the changes in signal 1266 * level. 1267 */ 1268 // TODO: The second arg to the call below needs to be a symbol somewhere, but 1269 // it's actually the size of an array of icons that's private 1270 // to StatusBar Policy. 1271 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4); 1272 if (newSignalLevel != mLastSignalLevel) { 1273 sendRssiChangeBroadcast(newRssi); 1274 } 1275 mLastSignalLevel = newSignalLevel; 1276 } else { 1277 mWifiInfo.setRssi(-200); 1278 } 1279 int newLinkSpeed = WifiNative.getLinkSpeedCommand(); 1280 if (newLinkSpeed != -1) { 1281 mWifiInfo.setLinkSpeed(newLinkSpeed); 1282 } 1283 } 1284 1285 private void setHighPerfModeEnabledNative(boolean enable) { 1286 if(!WifiNative.setSuspendOptimizationsCommand(!enable)) { 1287 Log.e(TAG, "set suspend optimizations failed!"); 1288 } 1289 if (enable) { 1290 if (!WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE)) { 1291 Log.e(TAG, "set power mode active failed!"); 1292 } 1293 } else { 1294 if (!WifiNative.setPowerModeCommand(POWER_MODE_AUTO)) { 1295 Log.e(TAG, "set power mode auto failed!"); 1296 } 1297 } 1298 } 1299 1300 private void configureLinkProperties() { 1301 if (WifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 1302 mLinkProperties = WifiConfigStore.getLinkProperties(mLastNetworkId); 1303 } else { 1304 synchronized (mDhcpInfoInternal) { 1305 mLinkProperties = mDhcpInfoInternal.makeLinkProperties(); 1306 } 1307 mLinkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId)); 1308 } 1309 mLinkProperties.setInterfaceName(mInterfaceName); 1310 Log.d(TAG, "netId=" + mLastNetworkId + " Link configured: " + mLinkProperties.toString()); 1311 } 1312 1313 private int getMaxDhcpRetries() { 1314 return Settings.Secure.getInt(mContext.getContentResolver(), 1315 Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT, 1316 DEFAULT_MAX_DHCP_RETRIES); 1317 } 1318 1319 private void sendScanResultsAvailableBroadcast() { 1320 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 1321 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1322 mContext.sendBroadcast(intent); 1323 } 1324 1325 private void sendRssiChangeBroadcast(final int newRssi) { 1326 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 1327 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1328 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 1329 mContext.sendBroadcast(intent); 1330 } 1331 1332 private void sendNetworkStateChangeBroadcast(String bssid) { 1333 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 1334 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1335 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 1336 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo); 1337 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, mLinkProperties); 1338 if (bssid != null) 1339 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 1340 mContext.sendStickyBroadcast(intent); 1341 } 1342 1343 private void sendErrorBroadcast(int errorCode) { 1344 Intent intent = new Intent(WifiManager.ERROR_ACTION); 1345 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1346 intent.putExtra(WifiManager.EXTRA_ERROR_CODE, errorCode); 1347 mContext.sendBroadcast(intent); 1348 } 1349 1350 private void sendLinkConfigurationChangedBroadcast() { 1351 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 1352 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1353 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, mLinkProperties); 1354 mContext.sendBroadcast(intent); 1355 } 1356 1357 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 1358 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 1359 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1360 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 1361 mContext.sendBroadcast(intent); 1362 } 1363 1364 /** 1365 * Record the detailed state of a network. 1366 * @param state the new @{code DetailedState} 1367 */ 1368 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 1369 Log.d(TAG, "setDetailed state, old =" 1370 + mNetworkInfo.getDetailedState() + " and new state=" + state); 1371 if (state != mNetworkInfo.getDetailedState()) { 1372 mNetworkInfo.setDetailedState(state, null, null); 1373 } 1374 } 1375 1376 private DetailedState getNetworkDetailedState() { 1377 return mNetworkInfo.getDetailedState(); 1378 } 1379 1380 /** 1381 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 1382 * using the interface, stopping DHCP & disabling interface 1383 */ 1384 private void handleNetworkDisconnect() { 1385 Log.d(TAG, "Reset connections and stopping DHCP"); 1386 1387 /* 1388 * Reset connections & stop DHCP 1389 */ 1390 NetworkUtils.resetConnections(mInterfaceName); 1391 1392 if (!NetworkUtils.stopDhcp(mInterfaceName)) { 1393 Log.e(TAG, "Could not stop DHCP"); 1394 } 1395 1396 /* Disable interface */ 1397 NetworkUtils.disableInterface(mInterfaceName); 1398 1399 /* send event to CM & network change broadcast */ 1400 setNetworkDetailedState(DetailedState.DISCONNECTED); 1401 sendNetworkStateChangeBroadcast(mLastBssid); 1402 1403 /* Reset data structures */ 1404 mWifiInfo.setInetAddress(null); 1405 mWifiInfo.setBSSID(null); 1406 mWifiInfo.setSSID(null); 1407 mWifiInfo.setNetworkId(-1); 1408 1409 /* Clear network properties */ 1410 mLinkProperties.clear(); 1411 1412 mLastBssid= null; 1413 mLastNetworkId = -1; 1414 1415 } 1416 1417 1418 /********************************************************* 1419 * Notifications from WifiMonitor 1420 ********************************************************/ 1421 1422 /** 1423 * Stores supplicant state change information passed from WifiMonitor 1424 */ 1425 static class StateChangeResult { 1426 StateChangeResult(int networkId, String BSSID, SupplicantState state) { 1427 this.state = state; 1428 this.BSSID = BSSID; 1429 this.networkId = networkId; 1430 } 1431 int networkId; 1432 String BSSID; 1433 SupplicantState state; 1434 } 1435 1436 /** 1437 * Send the tracker a notification that a user provided 1438 * configuration caused authentication failure - this could 1439 * be a password failure or a EAP authentication failure 1440 */ 1441 void notifyAuthenticationFailure() { 1442 sendMessage(AUTHENTICATION_FAILURE_EVENT); 1443 } 1444 1445 /** 1446 * Send a notification that the supplicant has detected overlapped 1447 * WPS sessions 1448 */ 1449 void notifyWpsOverlap() { 1450 sendMessage(WPS_OVERLAP_EVENT); 1451 } 1452 1453 /** 1454 * Send the tracker a notification that a connection to the supplicant 1455 * daemon has been established. 1456 */ 1457 void notifySupplicantConnection() { 1458 sendMessage(SUP_CONNECTION_EVENT); 1459 } 1460 1461 /** 1462 * Send the tracker a notification that connection to the supplicant 1463 * daemon is lost 1464 */ 1465 void notifySupplicantLost() { 1466 sendMessage(SUP_DISCONNECTION_EVENT); 1467 } 1468 1469 /** 1470 * Send the tracker a notification that the state of Wifi connectivity 1471 * has changed. 1472 * @param networkId the configured network on which the state change occurred 1473 * @param newState the new network state 1474 * @param BSSID when the new state is {@link DetailedState#CONNECTED 1475 * NetworkInfo.DetailedState.CONNECTED}, 1476 * this is the MAC address of the access point. Otherwise, it 1477 * is {@code null}. 1478 */ 1479 void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) { 1480 if (newState == NetworkInfo.DetailedState.CONNECTED) { 1481 sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT, networkId, 0, BSSID)); 1482 } else { 1483 sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT, networkId, 0, BSSID)); 1484 } 1485 } 1486 1487 /** 1488 * Send the tracker a notification that the state of the supplicant 1489 * has changed. 1490 * @param networkId the configured network on which the state change occurred 1491 * @param newState the new {@code SupplicantState} 1492 */ 1493 void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) { 1494 sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, 1495 new StateChangeResult(networkId, BSSID, newState))); 1496 } 1497 1498 /** 1499 * Send the tracker a notification that a scan has completed, and results 1500 * are available. 1501 */ 1502 void notifyScanResultsAvailable() { 1503 /** 1504 * Switch scan mode over to passive. 1505 * Turning off scan-only mode happens only in "Connect" mode 1506 */ 1507 setScanType(false); 1508 sendMessage(SCAN_RESULTS_EVENT); 1509 } 1510 1511 void notifyDriverStarted() { 1512 sendMessage(DRIVER_START_EVENT); 1513 } 1514 1515 void notifyDriverStopped() { 1516 sendMessage(DRIVER_STOP_EVENT); 1517 } 1518 1519 void notifyDriverHung() { 1520 setWifiEnabled(false); 1521 setWifiEnabled(true); 1522 } 1523 1524 /******************************************************** 1525 * HSM states 1526 *******************************************************/ 1527 1528 class DefaultState extends HierarchicalState { 1529 @Override 1530 public boolean processMessage(Message message) { 1531 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1532 switch (message.what) { 1533 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 1534 mBluetoothConnectionActive = (message.arg1 != 1535 BluetoothAdapter.STATE_DISCONNECTED); 1536 break; 1537 /* Synchronous call returns */ 1538 case CMD_PING_SUPPLICANT: 1539 case CMD_ENABLE_NETWORK: 1540 case CMD_DISABLE_NETWORK: 1541 case CMD_ADD_OR_UPDATE_NETWORK: 1542 case CMD_REMOVE_NETWORK: 1543 case CMD_SAVE_CONFIG: 1544 mReplyChannel.replyToMessage(message, message.what, FAILURE); 1545 break; 1546 case CMD_ENABLE_RSSI_POLL: 1547 mEnableRssiPolling = (message.arg1 == 1); 1548 break; 1549 case CMD_ENABLE_BACKGROUND_SCAN: 1550 mEnableBackgroundScan = (message.arg1 == 1); 1551 break; 1552 /* Discard */ 1553 case CMD_LOAD_DRIVER: 1554 case CMD_UNLOAD_DRIVER: 1555 case CMD_START_SUPPLICANT: 1556 case CMD_STOP_SUPPLICANT: 1557 case CMD_START_DRIVER: 1558 case CMD_STOP_DRIVER: 1559 case CMD_START_AP: 1560 case CMD_STOP_AP: 1561 case CMD_START_SCAN: 1562 case CMD_DISCONNECT: 1563 case CMD_RECONNECT: 1564 case CMD_REASSOCIATE: 1565 case SUP_CONNECTION_EVENT: 1566 case SUP_DISCONNECTION_EVENT: 1567 case DRIVER_START_EVENT: 1568 case DRIVER_STOP_EVENT: 1569 case NETWORK_CONNECTION_EVENT: 1570 case NETWORK_DISCONNECTION_EVENT: 1571 case SCAN_RESULTS_EVENT: 1572 case SUPPLICANT_STATE_CHANGE_EVENT: 1573 case AUTHENTICATION_FAILURE_EVENT: 1574 case WPS_OVERLAP_EVENT: 1575 case CMD_BLACKLIST_NETWORK: 1576 case CMD_CLEAR_BLACKLIST: 1577 case CMD_SET_SCAN_MODE: 1578 case CMD_SET_SCAN_TYPE: 1579 case CMD_SET_HIGH_PERF_MODE: 1580 case CMD_SET_COUNTRY_CODE: 1581 case CMD_SET_FREQUENCY_BAND: 1582 case CMD_REQUEST_CM_WAKELOCK: 1583 case CMD_CONNECT_NETWORK: 1584 case CMD_SAVE_NETWORK: 1585 case CMD_FORGET_NETWORK: 1586 case CMD_RSSI_POLL: 1587 case CMD_ENABLE_ALL_NETWORKS: 1588 break; 1589 case CMD_START_WPS: 1590 /* Return failure when the state machine cannot handle WPS initiation*/ 1591 mReplyChannel.replyToMessage(message, message.what, 1592 new WpsResult(Status.FAILURE)); 1593 break; 1594 default: 1595 Log.e(TAG, "Error! unhandled message" + message); 1596 break; 1597 } 1598 return HANDLED; 1599 } 1600 } 1601 1602 class InitialState extends HierarchicalState { 1603 @Override 1604 //TODO: could move logging into a common class 1605 public void enter() { 1606 if (DBG) Log.d(TAG, getName() + "\n"); 1607 // [31-8] Reserved for future use 1608 // [7 - 0] HSM state change 1609 // 50021 wifi_state_changed (custom|1|5) 1610 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1611 1612 if (WifiNative.isDriverLoaded()) { 1613 transitionTo(mDriverLoadedState); 1614 } 1615 else { 1616 transitionTo(mDriverUnloadedState); 1617 } 1618 } 1619 } 1620 1621 class DriverLoadingState extends HierarchicalState { 1622 @Override 1623 public void enter() { 1624 if (DBG) Log.d(TAG, getName() + "\n"); 1625 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1626 1627 final Message message = new Message(); 1628 message.copyFrom(getCurrentMessage()); 1629 /* TODO: add a timeout to fail when driver load is hung. 1630 * Similarly for driver unload. 1631 */ 1632 new Thread(new Runnable() { 1633 public void run() { 1634 mWakeLock.acquire(); 1635 //enabling state 1636 switch(message.arg1) { 1637 case WIFI_STATE_ENABLING: 1638 setWifiState(WIFI_STATE_ENABLING); 1639 break; 1640 case WIFI_AP_STATE_ENABLING: 1641 setWifiApState(WIFI_AP_STATE_ENABLING); 1642 break; 1643 } 1644 1645 if(WifiNative.loadDriver()) { 1646 Log.d(TAG, "Driver load successful"); 1647 sendMessage(CMD_LOAD_DRIVER_SUCCESS); 1648 } else { 1649 Log.e(TAG, "Failed to load driver!"); 1650 switch(message.arg1) { 1651 case WIFI_STATE_ENABLING: 1652 setWifiState(WIFI_STATE_UNKNOWN); 1653 break; 1654 case WIFI_AP_STATE_ENABLING: 1655 setWifiApState(WIFI_AP_STATE_FAILED); 1656 break; 1657 } 1658 sendMessage(CMD_LOAD_DRIVER_FAILURE); 1659 } 1660 mWakeLock.release(); 1661 } 1662 }).start(); 1663 } 1664 1665 @Override 1666 public boolean processMessage(Message message) { 1667 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1668 switch (message.what) { 1669 case CMD_LOAD_DRIVER_SUCCESS: 1670 transitionTo(mDriverLoadedState); 1671 break; 1672 case CMD_LOAD_DRIVER_FAILURE: 1673 transitionTo(mDriverFailedState); 1674 break; 1675 case CMD_LOAD_DRIVER: 1676 case CMD_UNLOAD_DRIVER: 1677 case CMD_START_SUPPLICANT: 1678 case CMD_STOP_SUPPLICANT: 1679 case CMD_START_AP: 1680 case CMD_STOP_AP: 1681 case CMD_START_DRIVER: 1682 case CMD_STOP_DRIVER: 1683 case CMD_SET_SCAN_MODE: 1684 case CMD_SET_SCAN_TYPE: 1685 case CMD_SET_HIGH_PERF_MODE: 1686 case CMD_SET_COUNTRY_CODE: 1687 case CMD_SET_FREQUENCY_BAND: 1688 case CMD_START_PACKET_FILTERING: 1689 case CMD_STOP_PACKET_FILTERING: 1690 deferMessage(message); 1691 break; 1692 default: 1693 return NOT_HANDLED; 1694 } 1695 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1696 return HANDLED; 1697 } 1698 } 1699 1700 class DriverLoadedState extends HierarchicalState { 1701 @Override 1702 public void enter() { 1703 if (DBG) Log.d(TAG, getName() + "\n"); 1704 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1705 } 1706 @Override 1707 public boolean processMessage(Message message) { 1708 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1709 switch(message.what) { 1710 case CMD_UNLOAD_DRIVER: 1711 transitionTo(mDriverUnloadingState); 1712 break; 1713 case CMD_START_SUPPLICANT: 1714 if(WifiNative.startSupplicant()) { 1715 Log.d(TAG, "Supplicant start successful"); 1716 mWifiMonitor.startMonitoring(); 1717 transitionTo(mSupplicantStartingState); 1718 } else { 1719 Log.e(TAG, "Failed to start supplicant!"); 1720 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); 1721 } 1722 break; 1723 case CMD_START_AP: 1724 try { 1725 nwService.startAccessPoint((WifiConfiguration) message.obj, 1726 mInterfaceName, 1727 SOFTAP_IFACE); 1728 } catch (Exception e) { 1729 Log.e(TAG, "Exception in softap start " + e); 1730 try { 1731 nwService.stopAccessPoint(); 1732 nwService.startAccessPoint((WifiConfiguration) message.obj, 1733 mInterfaceName, 1734 SOFTAP_IFACE); 1735 } catch (Exception ee) { 1736 Log.e(TAG, "Exception during softap restart : " + ee); 1737 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0)); 1738 break; 1739 } 1740 } 1741 Log.d(TAG, "Soft AP start successful"); 1742 setWifiApState(WIFI_AP_STATE_ENABLED); 1743 transitionTo(mSoftApStartedState); 1744 break; 1745 default: 1746 return NOT_HANDLED; 1747 } 1748 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1749 return HANDLED; 1750 } 1751 } 1752 1753 class DriverUnloadingState extends HierarchicalState { 1754 @Override 1755 public void enter() { 1756 if (DBG) Log.d(TAG, getName() + "\n"); 1757 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1758 1759 final Message message = new Message(); 1760 message.copyFrom(getCurrentMessage()); 1761 new Thread(new Runnable() { 1762 public void run() { 1763 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1764 mWakeLock.acquire(); 1765 if(WifiNative.unloadDriver()) { 1766 Log.d(TAG, "Driver unload successful"); 1767 sendMessage(CMD_UNLOAD_DRIVER_SUCCESS); 1768 1769 switch(message.arg1) { 1770 case WIFI_STATE_DISABLED: 1771 case WIFI_STATE_UNKNOWN: 1772 setWifiState(message.arg1); 1773 break; 1774 case WIFI_AP_STATE_DISABLED: 1775 case WIFI_AP_STATE_FAILED: 1776 setWifiApState(message.arg1); 1777 break; 1778 } 1779 } else { 1780 Log.e(TAG, "Failed to unload driver!"); 1781 sendMessage(CMD_UNLOAD_DRIVER_FAILURE); 1782 1783 switch(message.arg1) { 1784 case WIFI_STATE_DISABLED: 1785 case WIFI_STATE_UNKNOWN: 1786 setWifiState(WIFI_STATE_UNKNOWN); 1787 break; 1788 case WIFI_AP_STATE_DISABLED: 1789 case WIFI_AP_STATE_FAILED: 1790 setWifiApState(WIFI_AP_STATE_FAILED); 1791 break; 1792 } 1793 } 1794 mWakeLock.release(); 1795 } 1796 }).start(); 1797 } 1798 1799 @Override 1800 public boolean processMessage(Message message) { 1801 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1802 switch (message.what) { 1803 case CMD_UNLOAD_DRIVER_SUCCESS: 1804 transitionTo(mDriverUnloadedState); 1805 break; 1806 case CMD_UNLOAD_DRIVER_FAILURE: 1807 transitionTo(mDriverFailedState); 1808 break; 1809 case CMD_LOAD_DRIVER: 1810 case CMD_UNLOAD_DRIVER: 1811 case CMD_START_SUPPLICANT: 1812 case CMD_STOP_SUPPLICANT: 1813 case CMD_START_AP: 1814 case CMD_STOP_AP: 1815 case CMD_START_DRIVER: 1816 case CMD_STOP_DRIVER: 1817 case CMD_SET_SCAN_MODE: 1818 case CMD_SET_SCAN_TYPE: 1819 case CMD_SET_HIGH_PERF_MODE: 1820 case CMD_SET_COUNTRY_CODE: 1821 case CMD_SET_FREQUENCY_BAND: 1822 case CMD_START_PACKET_FILTERING: 1823 case CMD_STOP_PACKET_FILTERING: 1824 deferMessage(message); 1825 break; 1826 default: 1827 return NOT_HANDLED; 1828 } 1829 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1830 return HANDLED; 1831 } 1832 } 1833 1834 class DriverUnloadedState extends HierarchicalState { 1835 @Override 1836 public void enter() { 1837 if (DBG) Log.d(TAG, getName() + "\n"); 1838 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1839 } 1840 @Override 1841 public boolean processMessage(Message message) { 1842 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1843 switch (message.what) { 1844 case CMD_LOAD_DRIVER: 1845 transitionTo(mDriverLoadingState); 1846 break; 1847 default: 1848 return NOT_HANDLED; 1849 } 1850 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1851 return HANDLED; 1852 } 1853 } 1854 1855 class DriverFailedState extends HierarchicalState { 1856 @Override 1857 public void enter() { 1858 Log.e(TAG, getName() + "\n"); 1859 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1860 } 1861 @Override 1862 public boolean processMessage(Message message) { 1863 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1864 return NOT_HANDLED; 1865 } 1866 } 1867 1868 1869 class SupplicantStartingState extends HierarchicalState { 1870 @Override 1871 public void enter() { 1872 if (DBG) Log.d(TAG, getName() + "\n"); 1873 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1874 } 1875 @Override 1876 public boolean processMessage(Message message) { 1877 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1878 switch(message.what) { 1879 case SUP_CONNECTION_EVENT: 1880 Log.d(TAG, "Supplicant connection established"); 1881 setWifiState(WIFI_STATE_ENABLED); 1882 mSupplicantRestartCount = 0; 1883 /* Reset the supplicant state to indicate the supplicant 1884 * state is not known at this time */ 1885 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 1886 mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE); 1887 /* Initialize data structures */ 1888 mLastBssid = null; 1889 mLastNetworkId = -1; 1890 mLastSignalLevel = -1; 1891 1892 mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand()); 1893 1894 WifiConfigStore.initialize(mContext); 1895 1896 //TODO: initialize and fix multicast filtering 1897 //mWM.initializeMulticastFiltering(); 1898 1899 sendSupplicantConnectionChangedBroadcast(true); 1900 transitionTo(mDriverStartedState); 1901 break; 1902 case SUP_DISCONNECTION_EVENT: 1903 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 1904 Log.e(TAG, "Failed to setup control channel, restart supplicant"); 1905 WifiNative.killSupplicant(); 1906 transitionTo(mDriverLoadedState); 1907 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 1908 } else { 1909 mSupplicantRestartCount = 0; 1910 Log.e(TAG, "Failed " + mSupplicantRestartCount + 1911 " times to start supplicant, unload driver"); 1912 transitionTo(mDriverLoadedState); 1913 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); 1914 } 1915 break; 1916 case CMD_LOAD_DRIVER: 1917 case CMD_UNLOAD_DRIVER: 1918 case CMD_START_SUPPLICANT: 1919 case CMD_STOP_SUPPLICANT: 1920 case CMD_START_AP: 1921 case CMD_STOP_AP: 1922 case CMD_START_DRIVER: 1923 case CMD_STOP_DRIVER: 1924 case CMD_SET_SCAN_MODE: 1925 case CMD_SET_SCAN_TYPE: 1926 case CMD_SET_HIGH_PERF_MODE: 1927 case CMD_SET_COUNTRY_CODE: 1928 case CMD_SET_FREQUENCY_BAND: 1929 case CMD_START_PACKET_FILTERING: 1930 case CMD_STOP_PACKET_FILTERING: 1931 deferMessage(message); 1932 break; 1933 default: 1934 return NOT_HANDLED; 1935 } 1936 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1937 return HANDLED; 1938 } 1939 } 1940 1941 class SupplicantStartedState extends HierarchicalState { 1942 @Override 1943 public void enter() { 1944 if (DBG) Log.d(TAG, getName() + "\n"); 1945 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1946 /* Initialize for connect mode operation at start */ 1947 mIsScanMode = false; 1948 /* Wifi is available as long as we have a connection to supplicant */ 1949 mNetworkInfo.setIsAvailable(true); 1950 } 1951 @Override 1952 public boolean processMessage(Message message) { 1953 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1954 WifiConfiguration config; 1955 boolean eventLoggingEnabled = true; 1956 switch(message.what) { 1957 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 1958 Log.d(TAG, "stopping supplicant"); 1959 if (!WifiNative.stopSupplicant()) { 1960 Log.e(TAG, "Failed to stop supplicant, issue kill"); 1961 WifiNative.killSupplicant(); 1962 } 1963 mNetworkInfo.setIsAvailable(false); 1964 handleNetworkDisconnect(); 1965 setWifiState(WIFI_STATE_DISABLING); 1966 sendSupplicantConnectionChangedBroadcast(false); 1967 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 1968 mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE); 1969 transitionTo(mSupplicantStoppingState); 1970 break; 1971 case SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 1972 Log.e(TAG, "Connection lost, restart supplicant"); 1973 WifiNative.killSupplicant(); 1974 WifiNative.closeSupplicantConnection(); 1975 mNetworkInfo.setIsAvailable(false); 1976 handleNetworkDisconnect(); 1977 sendSupplicantConnectionChangedBroadcast(false); 1978 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 1979 mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE); 1980 transitionTo(mDriverLoadedState); 1981 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 1982 break; 1983 case SCAN_RESULTS_EVENT: 1984 eventLoggingEnabled = false; 1985 setScanResults(WifiNative.scanResultsCommand()); 1986 sendScanResultsAvailableBroadcast(); 1987 mScanResultIsPending = false; 1988 break; 1989 case CMD_PING_SUPPLICANT: 1990 boolean ok = WifiNative.pingCommand(); 1991 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 1992 break; 1993 case CMD_ADD_OR_UPDATE_NETWORK: 1994 config = (WifiConfiguration) message.obj; 1995 mReplyChannel.replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, 1996 WifiConfigStore.addOrUpdateNetwork(config)); 1997 break; 1998 case CMD_REMOVE_NETWORK: 1999 ok = WifiConfigStore.removeNetwork(message.arg1); 2000 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2001 break; 2002 case CMD_ENABLE_NETWORK: 2003 ok = WifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 2004 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2005 break; 2006 case CMD_ENABLE_ALL_NETWORKS: 2007 WifiConfigStore.enableAllNetworks(); 2008 break; 2009 case CMD_DISABLE_NETWORK: 2010 ok = WifiConfigStore.disableNetwork(message.arg1); 2011 mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2012 break; 2013 case CMD_BLACKLIST_NETWORK: 2014 WifiNative.addToBlacklistCommand((String)message.obj); 2015 break; 2016 case CMD_CLEAR_BLACKLIST: 2017 WifiNative.clearBlacklistCommand(); 2018 break; 2019 case CMD_SAVE_CONFIG: 2020 ok = WifiConfigStore.saveConfig(); 2021 mReplyChannel.replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 2022 2023 // Inform the backup manager about a data change 2024 IBackupManager ibm = IBackupManager.Stub.asInterface( 2025 ServiceManager.getService(Context.BACKUP_SERVICE)); 2026 if (ibm != null) { 2027 try { 2028 ibm.dataChanged("com.android.providers.settings"); 2029 } catch (Exception e) { 2030 // Try again later 2031 } 2032 } 2033 break; 2034 /* Cannot start soft AP while in client mode */ 2035 case CMD_START_AP: 2036 Log.d(TAG, "Failed to start soft AP with a running supplicant"); 2037 setWifiApState(WIFI_AP_STATE_FAILED); 2038 break; 2039 case CMD_SET_SCAN_MODE: 2040 mIsScanMode = (message.arg1 == SCAN_ONLY_MODE); 2041 break; 2042 case CMD_SAVE_NETWORK: 2043 config = (WifiConfiguration) message.obj; 2044 WifiConfigStore.saveNetwork(config); 2045 break; 2046 case CMD_FORGET_NETWORK: 2047 WifiConfigStore.forgetNetwork(message.arg1); 2048 break; 2049 default: 2050 return NOT_HANDLED; 2051 } 2052 if (eventLoggingEnabled) { 2053 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2054 } 2055 return HANDLED; 2056 } 2057 2058 @Override 2059 public void exit() { 2060 mNetworkInfo.setIsAvailable(false); 2061 } 2062 } 2063 2064 class SupplicantStoppingState extends HierarchicalState { 2065 @Override 2066 public void enter() { 2067 if (DBG) Log.d(TAG, getName() + "\n"); 2068 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2069 } 2070 @Override 2071 public boolean processMessage(Message message) { 2072 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2073 switch(message.what) { 2074 case SUP_CONNECTION_EVENT: 2075 Log.e(TAG, "Supplicant connection received while stopping"); 2076 break; 2077 case SUP_DISCONNECTION_EVENT: 2078 Log.d(TAG, "Supplicant connection lost"); 2079 WifiNative.closeSupplicantConnection(); 2080 transitionTo(mDriverLoadedState); 2081 break; 2082 case CMD_LOAD_DRIVER: 2083 case CMD_UNLOAD_DRIVER: 2084 case CMD_START_SUPPLICANT: 2085 case CMD_STOP_SUPPLICANT: 2086 case CMD_START_AP: 2087 case CMD_STOP_AP: 2088 case CMD_START_DRIVER: 2089 case CMD_STOP_DRIVER: 2090 case CMD_SET_SCAN_MODE: 2091 case CMD_SET_SCAN_TYPE: 2092 case CMD_SET_HIGH_PERF_MODE: 2093 case CMD_SET_COUNTRY_CODE: 2094 case CMD_SET_FREQUENCY_BAND: 2095 case CMD_START_PACKET_FILTERING: 2096 case CMD_STOP_PACKET_FILTERING: 2097 deferMessage(message); 2098 break; 2099 default: 2100 return NOT_HANDLED; 2101 } 2102 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2103 return HANDLED; 2104 } 2105 } 2106 2107 class DriverStartingState extends HierarchicalState { 2108 @Override 2109 public void enter() { 2110 if (DBG) Log.d(TAG, getName() + "\n"); 2111 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2112 } 2113 @Override 2114 public boolean processMessage(Message message) { 2115 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2116 switch(message.what) { 2117 case DRIVER_START_EVENT: 2118 transitionTo(mDriverStartedState); 2119 break; 2120 /* Queue driver commands & connection events */ 2121 case CMD_START_DRIVER: 2122 case CMD_STOP_DRIVER: 2123 case SUPPLICANT_STATE_CHANGE_EVENT: 2124 case NETWORK_CONNECTION_EVENT: 2125 case NETWORK_DISCONNECTION_EVENT: 2126 case AUTHENTICATION_FAILURE_EVENT: 2127 case WPS_OVERLAP_EVENT: 2128 case CMD_SET_SCAN_TYPE: 2129 case CMD_SET_HIGH_PERF_MODE: 2130 case CMD_SET_COUNTRY_CODE: 2131 case CMD_SET_FREQUENCY_BAND: 2132 case CMD_START_PACKET_FILTERING: 2133 case CMD_STOP_PACKET_FILTERING: 2134 case CMD_START_SCAN: 2135 case CMD_DISCONNECT: 2136 case CMD_REASSOCIATE: 2137 case CMD_RECONNECT: 2138 deferMessage(message); 2139 break; 2140 default: 2141 return NOT_HANDLED; 2142 } 2143 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2144 return HANDLED; 2145 } 2146 } 2147 2148 class DriverStartedState extends HierarchicalState { 2149 @Override 2150 public void enter() { 2151 if (DBG) Log.d(TAG, getName() + "\n"); 2152 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2153 2154 mIsRunning = true; 2155 updateBatteryWorkSource(null); 2156 2157 /** 2158 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 2159 * When this mode is on, some of the low-level scan parameters used by the 2160 * driver are changed to reduce interference with bluetooth 2161 */ 2162 WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive); 2163 /* set country code */ 2164 setCountryCode(); 2165 /* set frequency band of operation */ 2166 setFrequencyBand(); 2167 /* initialize network state */ 2168 setNetworkDetailedState(DetailedState.DISCONNECTED); 2169 2170 if (mIsScanMode) { 2171 WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); 2172 WifiNative.disconnectCommand(); 2173 transitionTo(mScanModeState); 2174 } else { 2175 WifiNative.setScanResultHandlingCommand(CONNECT_MODE); 2176 WifiNative.reconnectCommand(); 2177 transitionTo(mDisconnectedState); 2178 } 2179 } 2180 @Override 2181 public boolean processMessage(Message message) { 2182 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2183 boolean eventLoggingEnabled = true; 2184 switch(message.what) { 2185 case CMD_SET_SCAN_TYPE: 2186 if (message.arg1 == SCAN_ACTIVE) { 2187 WifiNative.setScanModeCommand(true); 2188 } else { 2189 WifiNative.setScanModeCommand(false); 2190 } 2191 break; 2192 case CMD_START_SCAN: 2193 eventLoggingEnabled = false; 2194 WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); 2195 mScanResultIsPending = true; 2196 break; 2197 case CMD_SET_HIGH_PERF_MODE: 2198 setHighPerfModeEnabledNative(message.arg1 == 1); 2199 break; 2200 case CMD_SET_COUNTRY_CODE: 2201 String country = (String) message.obj; 2202 Log.d(TAG, "set country code " + country); 2203 if (!WifiNative.setCountryCodeCommand(country.toUpperCase())) { 2204 Log.e(TAG, "Failed to set country code " + country); 2205 } 2206 break; 2207 case CMD_SET_FREQUENCY_BAND: 2208 int band = message.arg1; 2209 Log.d(TAG, "set frequency band " + band); 2210 if (WifiNative.setBandCommand(band)) { 2211 mFrequencyBand.set(band); 2212 //Fetch the latest scan results when frequency band is set 2213 startScan(true); 2214 } else { 2215 Log.e(TAG, "Failed to set frequency band " + band); 2216 } 2217 break; 2218 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 2219 mBluetoothConnectionActive = (message.arg1 != 2220 BluetoothAdapter.STATE_DISCONNECTED); 2221 WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive); 2222 break; 2223 case CMD_STOP_DRIVER: 2224 mWakeLock.acquire(); 2225 WifiNative.stopDriverCommand(); 2226 transitionTo(mDriverStoppingState); 2227 mWakeLock.release(); 2228 break; 2229 case CMD_START_PACKET_FILTERING: 2230 WifiNative.startPacketFiltering(); 2231 break; 2232 case CMD_STOP_PACKET_FILTERING: 2233 WifiNative.stopPacketFiltering(); 2234 break; 2235 default: 2236 return NOT_HANDLED; 2237 } 2238 if (eventLoggingEnabled) { 2239 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2240 } 2241 return HANDLED; 2242 } 2243 @Override 2244 public void exit() { 2245 if (DBG) Log.d(TAG, getName() + "\n"); 2246 mIsRunning = false; 2247 updateBatteryWorkSource(null); 2248 mScanResults = null; 2249 } 2250 } 2251 2252 class DriverStoppingState extends HierarchicalState { 2253 @Override 2254 public void enter() { 2255 if (DBG) Log.d(TAG, getName() + "\n"); 2256 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2257 } 2258 @Override 2259 public boolean processMessage(Message message) { 2260 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2261 switch(message.what) { 2262 case DRIVER_STOP_EVENT: 2263 transitionTo(mDriverStoppedState); 2264 break; 2265 /* Queue driver commands */ 2266 case CMD_START_DRIVER: 2267 case CMD_STOP_DRIVER: 2268 case CMD_SET_SCAN_TYPE: 2269 case CMD_SET_HIGH_PERF_MODE: 2270 case CMD_SET_COUNTRY_CODE: 2271 case CMD_SET_FREQUENCY_BAND: 2272 case CMD_START_PACKET_FILTERING: 2273 case CMD_STOP_PACKET_FILTERING: 2274 case CMD_START_SCAN: 2275 case CMD_DISCONNECT: 2276 case CMD_REASSOCIATE: 2277 case CMD_RECONNECT: 2278 deferMessage(message); 2279 break; 2280 default: 2281 return NOT_HANDLED; 2282 } 2283 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2284 return HANDLED; 2285 } 2286 } 2287 2288 class DriverStoppedState extends HierarchicalState { 2289 @Override 2290 public void enter() { 2291 if (DBG) Log.d(TAG, getName() + "\n"); 2292 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2293 } 2294 @Override 2295 public boolean processMessage(Message message) { 2296 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2297 switch (message.what) { 2298 case CMD_START_DRIVER: 2299 mWakeLock.acquire(); 2300 WifiNative.startDriverCommand(); 2301 transitionTo(mDriverStartingState); 2302 mWakeLock.release(); 2303 break; 2304 default: 2305 return NOT_HANDLED; 2306 } 2307 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2308 return HANDLED; 2309 } 2310 } 2311 2312 class ScanModeState extends HierarchicalState { 2313 @Override 2314 public void enter() { 2315 if (DBG) Log.d(TAG, getName() + "\n"); 2316 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2317 } 2318 @Override 2319 public boolean processMessage(Message message) { 2320 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2321 switch(message.what) { 2322 case CMD_SET_SCAN_MODE: 2323 if (message.arg1 == SCAN_ONLY_MODE) { 2324 /* Ignore */ 2325 return HANDLED; 2326 } else { 2327 WifiNative.setScanResultHandlingCommand(message.arg1); 2328 WifiNative.reconnectCommand(); 2329 mIsScanMode = false; 2330 transitionTo(mDisconnectedState); 2331 } 2332 break; 2333 /* Ignore */ 2334 case CMD_DISCONNECT: 2335 case CMD_RECONNECT: 2336 case CMD_REASSOCIATE: 2337 case SUPPLICANT_STATE_CHANGE_EVENT: 2338 case NETWORK_CONNECTION_EVENT: 2339 case NETWORK_DISCONNECTION_EVENT: 2340 break; 2341 default: 2342 return NOT_HANDLED; 2343 } 2344 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2345 return HANDLED; 2346 } 2347 } 2348 2349 class ConnectModeState extends HierarchicalState { 2350 @Override 2351 public void enter() { 2352 if (DBG) Log.d(TAG, getName() + "\n"); 2353 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2354 } 2355 @Override 2356 public boolean processMessage(Message message) { 2357 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2358 StateChangeResult stateChangeResult; 2359 switch(message.what) { 2360 case AUTHENTICATION_FAILURE_EVENT: 2361 mSupplicantStateTracker.sendMessage(AUTHENTICATION_FAILURE_EVENT); 2362 break; 2363 case WPS_OVERLAP_EVENT: 2364 /* We just need to broadcast the error */ 2365 sendErrorBroadcast(WifiManager.WPS_OVERLAP_ERROR); 2366 break; 2367 case SUPPLICANT_STATE_CHANGE_EVENT: 2368 stateChangeResult = (StateChangeResult) message.obj; 2369 SupplicantState state = stateChangeResult.state; 2370 // Supplicant state change 2371 // [31-13] Reserved for future use 2372 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 2373 // 50023 supplicant_state_changed (custom|1|5) 2374 EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal()); 2375 mWifiInfo.setSupplicantState(state); 2376 mWifiInfo.setNetworkId(stateChangeResult.networkId); 2377 if (state == SupplicantState.ASSOCIATING) { 2378 /* BSSID is valid only in ASSOCIATING state */ 2379 mWifiInfo.setBSSID(stateChangeResult.BSSID); 2380 } 2381 2382 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 2383 mWpsStateMachine.sendMessage(Message.obtain(message)); 2384 break; 2385 /* Do a redundant disconnect without transition */ 2386 case CMD_DISCONNECT: 2387 WifiNative.disconnectCommand(); 2388 break; 2389 case CMD_RECONNECT: 2390 WifiNative.reconnectCommand(); 2391 break; 2392 case CMD_REASSOCIATE: 2393 WifiNative.reassociateCommand(); 2394 break; 2395 case CMD_CONNECT_NETWORK: 2396 int netId = message.arg1; 2397 WifiConfiguration config = (WifiConfiguration) message.obj; 2398 2399 /* We connect to a specific network by issuing a select 2400 * to the WifiConfigStore. This enables the network, 2401 * while disabling all other networks in the supplicant. 2402 * Disabling a connected network will cause a disconnection 2403 * from the network. A reconnectCommand() will then initiate 2404 * a connection to the enabled network. 2405 */ 2406 if (config != null) { 2407 WifiConfigStore.selectNetwork(config); 2408 } else { 2409 WifiConfigStore.selectNetwork(netId); 2410 } 2411 2412 /* The state tracker handles enabling networks upon completion/failure */ 2413 mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK); 2414 2415 WifiNative.reconnectCommand(); 2416 2417 /* Expect a disconnection from the old connection */ 2418 transitionTo(mDisconnectingState); 2419 break; 2420 case CMD_START_WPS: 2421 mWpsStateMachine.sendMessage(Message.obtain(message)); 2422 transitionTo(mWaitForWpsCompletionState); 2423 break; 2424 case SCAN_RESULTS_EVENT: 2425 /* Set the scan setting back to "connect" mode */ 2426 WifiNative.setScanResultHandlingCommand(CONNECT_MODE); 2427 /* Handle scan results */ 2428 return NOT_HANDLED; 2429 case NETWORK_CONNECTION_EVENT: 2430 Log.d(TAG,"Network connection established"); 2431 mLastNetworkId = message.arg1; 2432 mLastBssid = (String) message.obj; 2433 2434 //TODO: make supplicant modification to push this in events 2435 mWifiInfo.setSSID(fetchSSID()); 2436 mWifiInfo.setBSSID(mLastBssid); 2437 mWifiInfo.setNetworkId(mLastNetworkId); 2438 /* send event to CM & network change broadcast */ 2439 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 2440 sendNetworkStateChangeBroadcast(mLastBssid); 2441 transitionTo(mConnectingState); 2442 break; 2443 case NETWORK_DISCONNECTION_EVENT: 2444 Log.d(TAG,"Network connection lost"); 2445 handleNetworkDisconnect(); 2446 transitionTo(mDisconnectedState); 2447 break; 2448 default: 2449 return NOT_HANDLED; 2450 } 2451 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2452 return HANDLED; 2453 } 2454 } 2455 2456 class ConnectingState extends HierarchicalState { 2457 boolean mModifiedBluetoothCoexistenceMode; 2458 int mPowerMode; 2459 boolean mUseStaticIp; 2460 Thread mDhcpThread; 2461 2462 @Override 2463 public void enter() { 2464 if (DBG) Log.d(TAG, getName() + "\n"); 2465 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2466 mUseStaticIp = WifiConfigStore.isUsingStaticIp(mLastNetworkId); 2467 if (!mUseStaticIp) { 2468 mDhcpThread = null; 2469 mModifiedBluetoothCoexistenceMode = false; 2470 mPowerMode = POWER_MODE_AUTO; 2471 2472 if (!mBluetoothConnectionActive) { 2473 /* 2474 * There are problems setting the Wi-Fi driver's power 2475 * mode to active when bluetooth coexistence mode is 2476 * enabled or sense. 2477 * <p> 2478 * We set Wi-Fi to active mode when 2479 * obtaining an IP address because we've found 2480 * compatibility issues with some routers with low power 2481 * mode. 2482 * <p> 2483 * In order for this active power mode to properly be set, 2484 * we disable coexistence mode until we're done with 2485 * obtaining an IP address. One exception is if we 2486 * are currently connected to a headset, since disabling 2487 * coexistence would interrupt that connection. 2488 */ 2489 mModifiedBluetoothCoexistenceMode = true; 2490 2491 // Disable the coexistence mode 2492 WifiNative.setBluetoothCoexistenceModeCommand( 2493 WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 2494 } 2495 2496 mPowerMode = WifiNative.getPowerModeCommand(); 2497 if (mPowerMode < 0) { 2498 // Handle the case where supplicant driver does not support 2499 // getPowerModeCommand. 2500 mPowerMode = POWER_MODE_AUTO; 2501 } 2502 if (mPowerMode != POWER_MODE_ACTIVE) { 2503 WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE); 2504 } 2505 2506 Log.d(TAG, "DHCP request started"); 2507 mDhcpThread = new Thread(new Runnable() { 2508 public void run() { 2509 DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); 2510 if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal)) { 2511 Log.d(TAG, "DHCP request succeeded"); 2512 synchronized (mDhcpInfoInternal) { 2513 mDhcpInfoInternal = dhcpInfoInternal; 2514 } 2515 sendMessage(CMD_IP_CONFIG_SUCCESS); 2516 } else { 2517 Log.d(TAG, "DHCP request failed: " + 2518 NetworkUtils.getDhcpError()); 2519 sendMessage(CMD_IP_CONFIG_FAILURE); 2520 } 2521 } 2522 }); 2523 mDhcpThread.start(); 2524 } else { 2525 DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration( 2526 mLastNetworkId); 2527 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 2528 INetworkManagementService netd = INetworkManagementService.Stub.asInterface(b); 2529 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 2530 ifcg.addr = dhcpInfoInternal.makeLinkAddress(); 2531 ifcg.interfaceFlags = "[up]"; 2532 try { 2533 netd.setInterfaceConfig(mInterfaceName, ifcg); 2534 Log.v(TAG, "Static IP configuration succeeded"); 2535 synchronized (mDhcpInfoInternal) { 2536 mDhcpInfoInternal = dhcpInfoInternal; 2537 } 2538 sendMessage(CMD_IP_CONFIG_SUCCESS); 2539 } catch (RemoteException re) { 2540 Log.v(TAG, "Static IP configuration failed: " + re); 2541 sendMessage(CMD_IP_CONFIG_FAILURE); 2542 } catch (IllegalStateException e) { 2543 Log.v(TAG, "Static IP configuration failed: " + e); 2544 sendMessage(CMD_IP_CONFIG_FAILURE); 2545 } 2546 } 2547 } 2548 @Override 2549 public boolean processMessage(Message message) { 2550 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2551 2552 switch(message.what) { 2553 case CMD_IP_CONFIG_SUCCESS: 2554 mLastSignalLevel = -1; // force update of signal strength 2555 InetAddress addr; 2556 synchronized (mDhcpInfoInternal) { 2557 addr = NetworkUtils.numericToInetAddress(mDhcpInfoInternal.ipAddress); 2558 } 2559 mWifiInfo.setInetAddress(addr); 2560 configureLinkProperties(); 2561 if (getNetworkDetailedState() == DetailedState.CONNECTED) { 2562 sendLinkConfigurationChangedBroadcast(); 2563 } else { 2564 setNetworkDetailedState(DetailedState.CONNECTED); 2565 sendNetworkStateChangeBroadcast(mLastBssid); 2566 } 2567 //TODO: The framework is not detecting a DHCP renewal and a possible 2568 //IP change. we should detect this and send out a config change broadcast 2569 transitionTo(mConnectedState); 2570 break; 2571 case CMD_IP_CONFIG_FAILURE: 2572 mWifiInfo.setInetAddress(null); 2573 2574 Log.e(TAG, "IP configuration failed"); 2575 /** 2576 * If we've exceeded the maximum number of retries for DHCP 2577 * to a given network, disable the network 2578 */ 2579 if (++mReconnectCount > getMaxDhcpRetries()) { 2580 Log.e(TAG, "Failed " + 2581 mReconnectCount + " times, Disabling " + mLastNetworkId); 2582 WifiConfigStore.disableNetwork(mLastNetworkId); 2583 mReconnectCount = 0; 2584 } 2585 2586 /* DHCP times out after about 30 seconds, we do a 2587 * disconnect and an immediate reconnect to try again 2588 */ 2589 WifiNative.disconnectCommand(); 2590 WifiNative.reconnectCommand(); 2591 transitionTo(mDisconnectingState); 2592 break; 2593 case CMD_DISCONNECT: 2594 WifiNative.disconnectCommand(); 2595 transitionTo(mDisconnectingState); 2596 break; 2597 /* Ignore connection to same network */ 2598 case CMD_CONNECT_NETWORK: 2599 int netId = message.arg1; 2600 if (mWifiInfo.getNetworkId() == netId) { 2601 break; 2602 } 2603 return NOT_HANDLED; 2604 case CMD_SAVE_NETWORK: 2605 deferMessage(message); 2606 break; 2607 /* Ignore */ 2608 case NETWORK_CONNECTION_EVENT: 2609 break; 2610 case CMD_STOP_DRIVER: 2611 sendMessage(CMD_DISCONNECT); 2612 deferMessage(message); 2613 break; 2614 case CMD_SET_SCAN_MODE: 2615 if (message.arg1 == SCAN_ONLY_MODE) { 2616 sendMessage(CMD_DISCONNECT); 2617 deferMessage(message); 2618 } 2619 break; 2620 /* Defer scan when IP is being fetched */ 2621 case CMD_START_SCAN: 2622 deferMessage(message); 2623 break; 2624 /* Defer any power mode changes since we must keep active power mode at DHCP */ 2625 case CMD_SET_HIGH_PERF_MODE: 2626 deferMessage(message); 2627 break; 2628 default: 2629 return NOT_HANDLED; 2630 } 2631 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2632 return HANDLED; 2633 } 2634 2635 @Override 2636 public void exit() { 2637 /* reset power state & bluetooth coexistence if on DHCP */ 2638 if (!mUseStaticIp) { 2639 if (mPowerMode != POWER_MODE_ACTIVE) { 2640 WifiNative.setPowerModeCommand(mPowerMode); 2641 } 2642 2643 if (mModifiedBluetoothCoexistenceMode) { 2644 // Set the coexistence mode back to its default value 2645 WifiNative.setBluetoothCoexistenceModeCommand( 2646 WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 2647 } 2648 } 2649 2650 } 2651 } 2652 2653 class ConnectedState extends HierarchicalState { 2654 @Override 2655 public void enter() { 2656 if (DBG) Log.d(TAG, getName() + "\n"); 2657 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2658 mRssiPollToken++; 2659 if (mEnableRssiPolling) { 2660 sendMessage(obtainMessage(WifiStateMachine.CMD_RSSI_POLL, mRssiPollToken, 0)); 2661 } 2662 } 2663 @Override 2664 public boolean processMessage(Message message) { 2665 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2666 boolean eventLoggingEnabled = true; 2667 switch (message.what) { 2668 case CMD_DISCONNECT: 2669 WifiNative.disconnectCommand(); 2670 transitionTo(mDisconnectingState); 2671 break; 2672 case CMD_STOP_DRIVER: 2673 sendMessage(CMD_DISCONNECT); 2674 deferMessage(message); 2675 break; 2676 case CMD_REQUEST_CM_WAKELOCK: 2677 if (mCm == null) { 2678 mCm = (ConnectivityManager)mContext.getSystemService( 2679 Context.CONNECTIVITY_SERVICE); 2680 } 2681 mCm.requestNetworkTransitionWakelock(TAG); 2682 break; 2683 case CMD_SET_SCAN_MODE: 2684 if (message.arg1 == SCAN_ONLY_MODE) { 2685 sendMessage(CMD_DISCONNECT); 2686 deferMessage(message); 2687 } 2688 break; 2689 case CMD_START_SCAN: 2690 eventLoggingEnabled = false; 2691 /* When the network is connected, re-scanning can trigger 2692 * a reconnection. Put it in scan-only mode during scan. 2693 * When scan results are received, the mode is switched 2694 * back to CONNECT_MODE. 2695 */ 2696 WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); 2697 /* Have the parent state handle the rest */ 2698 return NOT_HANDLED; 2699 /* Ignore connection to same network */ 2700 case CMD_CONNECT_NETWORK: 2701 int netId = message.arg1; 2702 if (mWifiInfo.getNetworkId() == netId) { 2703 break; 2704 } 2705 return NOT_HANDLED; 2706 case CMD_SAVE_NETWORK: 2707 WifiConfiguration config = (WifiConfiguration) message.obj; 2708 NetworkUpdateResult result = WifiConfigStore.saveNetwork(config); 2709 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 2710 if (result.hasIpChanged()) { 2711 Log.d(TAG,"Reconfiguring IP on connection"); 2712 NetworkUtils.resetConnections(mInterfaceName); 2713 transitionTo(mConnectingState); 2714 } 2715 if (result.hasProxyChanged()) { 2716 Log.d(TAG,"Reconfiguring proxy on connection"); 2717 configureLinkProperties(); 2718 sendLinkConfigurationChangedBroadcast(); 2719 } 2720 } 2721 break; 2722 /* Ignore */ 2723 case NETWORK_CONNECTION_EVENT: 2724 break; 2725 case CMD_RSSI_POLL: 2726 eventLoggingEnabled = false; 2727 if (message.arg1 == mRssiPollToken) { 2728 // Get Info and continue polling 2729 fetchRssiAndLinkSpeedNative(); 2730 sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL, 2731 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 2732 } else { 2733 // Polling has completed 2734 } 2735 break; 2736 case CMD_ENABLE_RSSI_POLL: 2737 mEnableRssiPolling = (message.arg1 == 1); 2738 mRssiPollToken++; 2739 if (mEnableRssiPolling) { 2740 // first poll 2741 fetchRssiAndLinkSpeedNative(); 2742 sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL, 2743 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 2744 } 2745 break; 2746 default: 2747 return NOT_HANDLED; 2748 } 2749 if (eventLoggingEnabled) { 2750 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2751 } 2752 return HANDLED; 2753 } 2754 } 2755 2756 class DisconnectingState extends HierarchicalState { 2757 @Override 2758 public void enter() { 2759 if (DBG) Log.d(TAG, getName() + "\n"); 2760 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2761 } 2762 @Override 2763 public boolean processMessage(Message message) { 2764 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2765 switch (message.what) { 2766 case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */ 2767 deferMessage(message); 2768 break; 2769 case CMD_SET_SCAN_MODE: 2770 if (message.arg1 == SCAN_ONLY_MODE) { 2771 deferMessage(message); 2772 } 2773 break; 2774 /* Handle in DisconnectedState */ 2775 case SUPPLICANT_STATE_CHANGE_EVENT: 2776 deferMessage(message); 2777 break; 2778 default: 2779 return NOT_HANDLED; 2780 } 2781 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2782 return HANDLED; 2783 } 2784 } 2785 2786 class DisconnectedState extends HierarchicalState { 2787 private boolean mAlarmEnabled = false; 2788 @Override 2789 public void enter() { 2790 if (DBG) Log.d(TAG, getName() + "\n"); 2791 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2792 2793 /* 2794 * We initiate background scanning if it is enabled, otherwise we 2795 * initiate an infrequent scan that wakes up the device to ensure 2796 * a user connects to an access point on the move 2797 */ 2798 if (mEnableBackgroundScan) { 2799 /* If a regular scan result is pending, do not initiate background 2800 * scan until the scan results are returned. This is needed because 2801 * initiating a background scan will cancel the regular scan and 2802 * scan results will not be returned until background scanning is 2803 * cleared 2804 */ 2805 if (!mScanResultIsPending) { 2806 WifiNative.enableBackgroundScan(true); 2807 } 2808 } else { 2809 long scanMs = Settings.Secure.getLong(mContext.getContentResolver(), 2810 Settings.Secure.WIFI_SCAN_INTERVAL_MS, DEFAULT_SCAN_INTERVAL_MS); 2811 2812 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 2813 System.currentTimeMillis() + scanMs, scanMs, mScanIntent); 2814 mAlarmEnabled = true; 2815 } 2816 } 2817 @Override 2818 public boolean processMessage(Message message) { 2819 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2820 switch (message.what) { 2821 case CMD_SET_SCAN_MODE: 2822 if (message.arg1 == SCAN_ONLY_MODE) { 2823 WifiNative.setScanResultHandlingCommand(message.arg1); 2824 //Supplicant disconnect to prevent further connects 2825 WifiNative.disconnectCommand(); 2826 mIsScanMode = true; 2827 transitionTo(mScanModeState); 2828 } 2829 break; 2830 case CMD_ENABLE_BACKGROUND_SCAN: 2831 mEnableBackgroundScan = (message.arg1 == 1); 2832 WifiNative.enableBackgroundScan(mEnableBackgroundScan); 2833 break; 2834 /* Ignore network disconnect */ 2835 case NETWORK_DISCONNECTION_EVENT: 2836 break; 2837 case SUPPLICANT_STATE_CHANGE_EVENT: 2838 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2839 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 2840 /* DriverStartedState does the rest of the handling */ 2841 return NOT_HANDLED; 2842 case CMD_START_SCAN: 2843 /* Disable background scan temporarily during a regular scan */ 2844 if (mEnableBackgroundScan) { 2845 WifiNative.enableBackgroundScan(false); 2846 } 2847 /* Handled in parent state */ 2848 return NOT_HANDLED; 2849 case SCAN_RESULTS_EVENT: 2850 /* Re-enable background scan when a pending scan result is received */ 2851 if (mEnableBackgroundScan && mScanResultIsPending) { 2852 WifiNative.enableBackgroundScan(true); 2853 } 2854 /* Handled in parent state */ 2855 return NOT_HANDLED; 2856 default: 2857 return NOT_HANDLED; 2858 } 2859 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2860 return HANDLED; 2861 } 2862 2863 @Override 2864 public void exit() { 2865 /* No need for a background scan upon exit from a disconnected state */ 2866 if (mEnableBackgroundScan) { 2867 WifiNative.enableBackgroundScan(false); 2868 } 2869 if (mAlarmEnabled) { 2870 mAlarmManager.cancel(mScanIntent); 2871 mAlarmEnabled = false; 2872 } 2873 } 2874 } 2875 2876 class WaitForWpsCompletionState extends HierarchicalState { 2877 @Override 2878 public void enter() { 2879 if (DBG) Log.d(TAG, getName() + "\n"); 2880 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2881 } 2882 @Override 2883 public boolean processMessage(Message message) { 2884 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2885 switch (message.what) { 2886 /* Defer all commands that can cause connections to a different network 2887 * or put the state machine out of connect mode 2888 */ 2889 case CMD_STOP_DRIVER: 2890 case CMD_SET_SCAN_MODE: 2891 case CMD_CONNECT_NETWORK: 2892 case CMD_ENABLE_NETWORK: 2893 case CMD_RECONNECT: 2894 case CMD_REASSOCIATE: 2895 case NETWORK_CONNECTION_EVENT: /* Handled after IP & proxy update */ 2896 deferMessage(message); 2897 break; 2898 case NETWORK_DISCONNECTION_EVENT: 2899 Log.d(TAG,"Network connection lost"); 2900 handleNetworkDisconnect(); 2901 break; 2902 case WPS_COMPLETED_EVENT: 2903 /* we are still disconnected until we see a network connection 2904 * notification */ 2905 transitionTo(mDisconnectedState); 2906 break; 2907 default: 2908 return NOT_HANDLED; 2909 } 2910 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2911 return HANDLED; 2912 } 2913 } 2914 2915 class SoftApStartedState extends HierarchicalState { 2916 @Override 2917 public void enter() { 2918 if (DBG) Log.d(TAG, getName() + "\n"); 2919 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2920 } 2921 @Override 2922 public boolean processMessage(Message message) { 2923 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2924 switch(message.what) { 2925 case CMD_STOP_AP: 2926 Log.d(TAG,"Stopping Soft AP"); 2927 setWifiApState(WIFI_AP_STATE_DISABLING); 2928 2929 if (mCm == null) { 2930 mCm = (ConnectivityManager) mContext.getSystemService( 2931 Context.CONNECTIVITY_SERVICE); 2932 } 2933 if (mCm.untether(SOFTAP_IFACE) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2934 Log.e(TAG, "Untether initiate failed!"); 2935 } 2936 try { 2937 nwService.stopAccessPoint(); 2938 } catch(Exception e) { 2939 Log.e(TAG, "Exception in stopAccessPoint()"); 2940 } 2941 transitionTo(mDriverLoadedState); 2942 break; 2943 case CMD_START_AP: 2944 Log.d(TAG,"SoftAP set on a running access point"); 2945 try { 2946 nwService.setAccessPoint((WifiConfiguration) message.obj, 2947 mInterfaceName, 2948 SOFTAP_IFACE); 2949 } catch(Exception e) { 2950 Log.e(TAG, "Exception in softap set " + e); 2951 try { 2952 nwService.stopAccessPoint(); 2953 nwService.startAccessPoint((WifiConfiguration) message.obj, 2954 mInterfaceName, 2955 SOFTAP_IFACE); 2956 } catch (Exception ee) { 2957 Log.e(TAG, "Could not restart softap after set failed " + ee); 2958 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0)); 2959 } 2960 } 2961 break; 2962 /* Fail client mode operation when soft AP is enabled */ 2963 case CMD_START_SUPPLICANT: 2964 Log.e(TAG,"Cannot start supplicant with a running soft AP"); 2965 setWifiState(WIFI_STATE_UNKNOWN); 2966 break; 2967 default: 2968 return NOT_HANDLED; 2969 } 2970 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2971 return HANDLED; 2972 } 2973 } 2974} 2975