Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net.wifi;
     18 
     19 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
     20 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
     21 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
     22 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
     23 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
     24 
     25 /**
     26  * TODO: Add soft AP states as part of WIFI_STATE_XXX
     27  * Retain WIFI_STATE_ENABLING that indicates driver is loading
     28  * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started
     29  * and WIFI_STATE_FAILED for failure
     30  * Deprecate WIFI_STATE_UNKNOWN
     31  *
     32  * Doing this will simplify the logic for sending broadcasts
     33  */
     34 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
     35 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
     36 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
     37 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
     38 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
     39 
     40 import android.app.AlarmManager;
     41 import android.app.PendingIntent;
     42 import android.app.backup.IBackupManager;
     43 import android.bluetooth.BluetoothAdapter;
     44 import android.content.BroadcastReceiver;
     45 import android.content.Context;
     46 import android.content.Intent;
     47 import android.content.IntentFilter;
     48 import android.net.ConnectivityManager;
     49 import android.net.DhcpInfo;
     50 import android.net.DhcpInfoInternal;
     51 import android.net.DhcpStateMachine;
     52 import android.net.InterfaceConfiguration;
     53 import android.net.LinkAddress;
     54 import android.net.LinkProperties;
     55 import android.net.NetworkInfo;
     56 import android.net.NetworkInfo.DetailedState;
     57 import android.net.NetworkUtils;
     58 import android.net.wifi.WpsResult.Status;
     59 import android.net.wifi.p2p.WifiP2pManager;
     60 import android.net.wifi.p2p.WifiP2pService;
     61 import android.net.wifi.StateChangeResult;
     62 import android.os.Binder;
     63 import android.os.IBinder;
     64 import android.os.INetworkManagementService;
     65 import android.os.Message;
     66 import android.os.Messenger;
     67 import android.os.PowerManager;
     68 import android.os.Process;
     69 import android.os.RemoteException;
     70 import android.os.ServiceManager;
     71 import android.os.SystemClock;
     72 import android.os.SystemProperties;
     73 import android.os.WorkSource;
     74 import android.provider.Settings;
     75 import android.util.EventLog;
     76 import android.util.Log;
     77 import android.util.LruCache;
     78 
     79 import com.android.internal.app.IBatteryStats;
     80 import com.android.internal.util.AsyncChannel;
     81 import com.android.internal.util.Protocol;
     82 import com.android.internal.util.State;
     83 import com.android.internal.util.StateMachine;
     84 
     85 import java.net.InetAddress;
     86 import java.util.ArrayList;
     87 import java.util.List;
     88 import java.util.concurrent.atomic.AtomicInteger;
     89 import java.util.concurrent.atomic.AtomicBoolean;
     90 import java.util.regex.Pattern;
     91 
     92 /**
     93  * Track the state of Wifi connectivity. All event handling is done here,
     94  * and all changes in connectivity state are initiated here.
     95  *
     96  * Wi-Fi now supports three modes of operation: Client, Soft Ap and Direct
     97  * In the current implementation, we do not support any concurrency and thus only
     98  * one of Client, Soft Ap or Direct operation is supported at any time.
     99  *
    100  * The WifiStateMachine supports Soft Ap and Client operations while WifiP2pService
    101  * handles Direct. WifiP2pService and WifiStateMachine co-ordinate to ensure only
    102  * one exists at a certain time.
    103  *
    104  * @hide
    105  */
    106 public class WifiStateMachine extends StateMachine {
    107 
    108     private static final String TAG = "WifiStateMachine";
    109     private static final String NETWORKTYPE = "WIFI";
    110     private static final boolean DBG = false;
    111 
    112     /* TODO: This is no more used with the hostapd code. Clean up */
    113     private static final String SOFTAP_IFACE = "wl0.1";
    114 
    115     private WifiMonitor mWifiMonitor;
    116     private INetworkManagementService mNwService;
    117     private ConnectivityManager mCm;
    118 
    119     /* Scan results handling */
    120     private List<ScanResult> mScanResults;
    121     private static final Pattern scanResultPattern = Pattern.compile("\t+");
    122     private static final int SCAN_RESULT_CACHE_SIZE = 80;
    123     private final LruCache<String, ScanResult> mScanResultCache;
    124 
    125     private String mInterfaceName;
    126     /* Tethering interface could be seperate from wlan interface */
    127     private String mTetherInterfaceName;
    128 
    129     private int mLastSignalLevel = -1;
    130     private String mLastBssid;
    131     private int mLastNetworkId;
    132     private boolean mEnableRssiPolling = false;
    133     private boolean mEnableBackgroundScan = false;
    134     private int mRssiPollToken = 0;
    135     private int mReconnectCount = 0;
    136     private boolean mIsScanMode = false;
    137     private boolean mScanResultIsPending = false;
    138 
    139     private boolean mBluetoothConnectionActive = false;
    140 
    141     /**
    142      * Interval in milliseconds between polling for RSSI
    143      * and linkspeed information
    144      */
    145     private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
    146 
    147     /**
    148      * Delay between supplicant restarts upon failure to establish connection
    149      */
    150     private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
    151 
    152     /**
    153      * Number of times we attempt to restart supplicant
    154      */
    155     private static final int SUPPLICANT_RESTART_TRIES = 5;
    156 
    157     private int mSupplicantRestartCount = 0;
    158     /* Tracks sequence number on stop failure message */
    159     private int mSupplicantStopFailureToken = 0;
    160 
    161     /**
    162      * Tether state change notification time out
    163      */
    164     private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000;
    165 
    166     /* Tracks sequence number on a tether notification time out */
    167     private int mTetherToken = 0;
    168 
    169     private LinkProperties mLinkProperties;
    170 
    171     // Wakelock held during wifi start/stop and driver load/unload
    172     private PowerManager.WakeLock mWakeLock;
    173 
    174     private Context mContext;
    175 
    176     private DhcpInfoInternal mDhcpInfoInternal;
    177     private WifiInfo mWifiInfo;
    178     private NetworkInfo mNetworkInfo;
    179     private SupplicantStateTracker mSupplicantStateTracker;
    180     private WpsStateMachine mWpsStateMachine;
    181     private DhcpStateMachine mDhcpStateMachine;
    182 
    183     private AlarmManager mAlarmManager;
    184     private PendingIntent mScanIntent;
    185     /* Tracks current frequency mode */
    186     private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
    187 
    188     /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */
    189     private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true);
    190 
    191     // Channel for sending replies.
    192     private AsyncChannel mReplyChannel = new AsyncChannel();
    193 
    194     private WifiP2pManager mWifiP2pManager;
    195     //Used to initiate a connection with WifiP2pService
    196     private AsyncChannel mWifiP2pChannel = new AsyncChannel();
    197     private AsyncChannel mWifiApConfigChannel = new AsyncChannel();
    198 
    199     // Event log tags (must be in sync with event-log-tags)
    200     private static final int EVENTLOG_WIFI_STATE_CHANGED        = 50021;
    201     private static final int EVENTLOG_WIFI_EVENT_HANDLED        = 50022;
    202     private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED  = 50023;
    203 
    204     /* The base for wifi message types */
    205     static final int BASE = Protocol.BASE_WIFI;
    206     /* Load the driver */
    207     static final int CMD_LOAD_DRIVER                      = BASE + 1;
    208     /* Unload the driver */
    209     static final int CMD_UNLOAD_DRIVER                    = BASE + 2;
    210     /* Indicates driver load succeeded */
    211     static final int CMD_LOAD_DRIVER_SUCCESS              = BASE + 3;
    212     /* Indicates driver load failed */
    213     static final int CMD_LOAD_DRIVER_FAILURE              = BASE + 4;
    214     /* Indicates driver unload succeeded */
    215     static final int CMD_UNLOAD_DRIVER_SUCCESS            = BASE + 5;
    216     /* Indicates driver unload failed */
    217     static final int CMD_UNLOAD_DRIVER_FAILURE            = BASE + 6;
    218 
    219     /* Start the supplicant */
    220     static final int CMD_START_SUPPLICANT                 = BASE + 11;
    221     /* Stop the supplicant */
    222     static final int CMD_STOP_SUPPLICANT                  = BASE + 12;
    223     /* Start the driver */
    224     static final int CMD_START_DRIVER                     = BASE + 13;
    225     /* Stop the driver */
    226     static final int CMD_STOP_DRIVER                      = BASE + 14;
    227     /* Indicates Static IP succeded */
    228     static final int CMD_STATIC_IP_SUCCESS                = BASE + 15;
    229     /* Indicates Static IP failed */
    230     static final int CMD_STATIC_IP_FAILURE                = BASE + 16;
    231     /* Indicates supplicant stop failed */
    232     static final int CMD_STOP_SUPPLICANT_FAILED           = BASE + 17;
    233     /* Delayed stop to avoid shutting down driver too quick*/
    234     static final int CMD_DELAYED_STOP_DRIVER              = BASE + 18;
    235 
    236 
    237     /* Start the soft access point */
    238     static final int CMD_START_AP                         = BASE + 21;
    239     /* Indicates soft ap start succeded */
    240     static final int CMD_START_AP_SUCCESS                 = BASE + 22;
    241     /* Indicates soft ap start failed */
    242     static final int CMD_START_AP_FAILURE                 = BASE + 23;
    243     /* Stop the soft access point */
    244     static final int CMD_STOP_AP                          = BASE + 24;
    245     /* Set the soft access point configuration */
    246     static final int CMD_SET_AP_CONFIG                    = BASE + 25;
    247     /* Soft access point configuration set completed */
    248     static final int CMD_SET_AP_CONFIG_COMPLETED          = BASE + 26;
    249     /* Request the soft access point configuration */
    250     static final int CMD_REQUEST_AP_CONFIG                = BASE + 27;
    251     /* Response to access point configuration request */
    252     static final int CMD_RESPONSE_AP_CONFIG               = BASE + 28;
    253     /* Invoked when getting a tether state change notification */
    254     static final int CMD_TETHER_STATE_CHANGE              = BASE + 29;
    255     /* A delayed message sent to indicate tether state change failed to arrive */
    256     static final int CMD_TETHER_NOTIFICATION_TIMED_OUT    = BASE + 30;
    257 
    258     static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 31;
    259 
    260     /* Supplicant commands */
    261     /* Is supplicant alive ? */
    262     static final int CMD_PING_SUPPLICANT                  = BASE + 51;
    263     /* Add/update a network configuration */
    264     static final int CMD_ADD_OR_UPDATE_NETWORK            = BASE + 52;
    265     /* Delete a network */
    266     static final int CMD_REMOVE_NETWORK                   = BASE + 53;
    267     /* Enable a network. The device will attempt a connection to the given network. */
    268     static final int CMD_ENABLE_NETWORK                   = BASE + 54;
    269     /* Enable all networks */
    270     static final int CMD_ENABLE_ALL_NETWORKS              = BASE + 55;
    271     /* Disable a network. The device does not attempt a connection to the given network. */
    272     static final int CMD_DISABLE_NETWORK                  = BASE + 56;
    273     /* Blacklist network. De-prioritizes the given BSSID for connection. */
    274     static final int CMD_BLACKLIST_NETWORK                = BASE + 57;
    275     /* Clear the blacklist network list */
    276     static final int CMD_CLEAR_BLACKLIST                  = BASE + 58;
    277     /* Save configuration */
    278     static final int CMD_SAVE_CONFIG                      = BASE + 59;
    279 
    280     /* Supplicant commands after driver start*/
    281     /* Initiate a scan */
    282     static final int CMD_START_SCAN                       = BASE + 71;
    283     /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
    284     static final int CMD_SET_SCAN_MODE                    = BASE + 72;
    285     /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
    286     static final int CMD_SET_SCAN_TYPE                    = BASE + 73;
    287     /* Disconnect from a network */
    288     static final int CMD_DISCONNECT                       = BASE + 74;
    289     /* Reconnect to a network */
    290     static final int CMD_RECONNECT                        = BASE + 75;
    291     /* Reassociate to a network */
    292     static final int CMD_REASSOCIATE                      = BASE + 76;
    293     /* Controls power mode and suspend mode optimizations
    294      *
    295      * When high perf mode is enabled, power mode is set to
    296      * POWER_MODE_ACTIVE and suspend mode optimizations are disabled
    297      *
    298      * When high perf mode is disabled, power mode is set to
    299      * POWER_MODE_AUTO and suspend mode optimizations are enabled
    300      *
    301      * Suspend mode optimizations include:
    302      * - packet filtering
    303      * - turn off roaming
    304      * - DTIM wake up settings
    305      */
    306     static final int CMD_SET_HIGH_PERF_MODE               = BASE + 77;
    307     /* Set the country code */
    308     static final int CMD_SET_COUNTRY_CODE                 = BASE + 80;
    309     /* Enables RSSI poll */
    310     static final int CMD_ENABLE_RSSI_POLL                 = BASE + 82;
    311     /* RSSI poll */
    312     static final int CMD_RSSI_POLL                        = BASE + 83;
    313     /* Set up packet filtering */
    314     static final int CMD_START_PACKET_FILTERING           = BASE + 84;
    315     /* Clear packet filter */
    316     static final int CMD_STOP_PACKET_FILTERING            = BASE + 85;
    317 
    318     /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */
    319     static final int MULTICAST_V6  = 1;
    320     static final int MULTICAST_V4  = 0;
    321 
    322     /* Connect to a specified network (network id
    323      * or WifiConfiguration) This involves increasing
    324      * the priority of the network, enabling the network
    325      * (while disabling others) and issuing a reconnect.
    326      * Note that CMD_RECONNECT just does a reconnect to
    327      * an existing network. All the networks get enabled
    328      * upon a successful connection or a failure.
    329      */
    330     static final int CMD_CONNECT_NETWORK                  = BASE + 86;
    331     /* Save the specified network. This involves adding
    332      * an enabled network (if new) and updating the
    333      * config and issuing a save on supplicant config.
    334      */
    335     static final int CMD_SAVE_NETWORK                     = BASE + 87;
    336     /* Delete the specified network. This involves
    337      * removing the network and issuing a save on
    338      * supplicant config.
    339      */
    340     static final int CMD_FORGET_NETWORK                   = BASE + 88;
    341     /* Start Wi-Fi protected setup */
    342     static final int CMD_START_WPS                        = BASE + 89;
    343     /* Set the frequency band */
    344     static final int CMD_SET_FREQUENCY_BAND               = BASE + 90;
    345     /* Enable background scan for configured networks */
    346     static final int CMD_ENABLE_BACKGROUND_SCAN           = BASE + 91;
    347 
    348     /* Commands from/to the SupplicantStateTracker */
    349     /* Reset the supplicant state tracker */
    350     static final int CMD_RESET_SUPPLICANT_STATE           = BASE + 111;
    351 
    352     /* Commands/events reported by WpsStateMachine */
    353     /* Indicates the completion of WPS activity */
    354     static final int WPS_COMPLETED_EVENT                  = BASE + 121;
    355     /* Reset the WPS state machine */
    356     static final int CMD_RESET_WPS_STATE                  = BASE + 122;
    357 
    358     /* Interaction with WifiP2pService */
    359     public static final int WIFI_ENABLE_PENDING           = BASE + 131;
    360     public static final int P2P_ENABLE_PROCEED            = BASE + 132;
    361 
    362     private static final int CONNECT_MODE   = 1;
    363     private static final int SCAN_ONLY_MODE = 2;
    364 
    365     private static final int SCAN_ACTIVE = 1;
    366     private static final int SCAN_PASSIVE = 2;
    367 
    368     private static final int SUCCESS = 1;
    369     private static final int FAILURE = -1;
    370 
    371     /* Phone in emergency call back mode */
    372     private static final int IN_ECM_STATE = 1;
    373     private static final int NOT_IN_ECM_STATE = 0;
    374 
    375     /**
    376      * The maximum number of times we will retry a connection to an access point
    377      * for which we have failed in acquiring an IP address from DHCP. A value of
    378      * N means that we will make N+1 connection attempts in all.
    379      * <p>
    380      * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
    381      * value if a Settings value is not present.
    382      */
    383     private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
    384 
    385     static final int POWER_MODE_ACTIVE = 1;
    386     static final int POWER_MODE_AUTO = 0;
    387 
    388     /* Tracks the power mode for restoration after a DHCP request/renewal goes through */
    389     private int mPowerMode = POWER_MODE_AUTO;
    390 
    391     /**
    392      * Default framework scan interval in milliseconds. This is used in the scenario in which
    393      * wifi chipset does not support background scanning to set up a
    394      * periodic wake up scan so that the device can connect to a new access
    395      * point on the move. {@link Settings.Secure#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can
    396      * override this.
    397      */
    398     private final int mDefaultFrameworkScanIntervalMs;
    399 
    400     /**
    401      * Default supplicant scan interval in milliseconds.
    402      * {@link Settings.Secure#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} can override this.
    403      */
    404     private final int mDefaultSupplicantScanIntervalMs;
    405 
    406     /**
    407      * Minimum time interval between enabling all networks.
    408      * A device can end up repeatedly connecting to a bad network on screen on/off toggle
    409      * due to enabling every time. We add a threshold to avoid this.
    410      */
    411     private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */
    412     private long mLastEnableAllNetworksTime;
    413 
    414     /**
    415      * Starting and shutting down driver too quick causes problems leading to driver
    416      * being in a bad state. Delay driver stop.
    417      */
    418     private static final int DELAYED_DRIVER_STOP_MS = 2 * 60 * 1000; /* 2 minutes */
    419     private int mDelayedStopCounter;
    420     private boolean mInDelayedStop = false;
    421 
    422     private static final int MIN_RSSI = -200;
    423     private static final int MAX_RSSI = 256;
    424 
    425     /* Default parent state */
    426     private State mDefaultState = new DefaultState();
    427     /* Temporary initial state */
    428     private State mInitialState = new InitialState();
    429     /* Unloading the driver */
    430     private State mDriverUnloadingState = new DriverUnloadingState();
    431     /* Loading the driver */
    432     private State mDriverUnloadedState = new DriverUnloadedState();
    433     /* Driver load/unload failed */
    434     private State mDriverFailedState = new DriverFailedState();
    435     /* Driver loading */
    436     private State mDriverLoadingState = new DriverLoadingState();
    437     /* Driver loaded */
    438     private State mDriverLoadedState = new DriverLoadedState();
    439     /* Driver loaded, waiting for supplicant to start */
    440     private State mSupplicantStartingState = new SupplicantStartingState();
    441     /* Driver loaded and supplicant ready */
    442     private State mSupplicantStartedState = new SupplicantStartedState();
    443     /* Waiting for supplicant to stop and monitor to exit */
    444     private State mSupplicantStoppingState = new SupplicantStoppingState();
    445     /* Driver start issued, waiting for completed event */
    446     private State mDriverStartingState = new DriverStartingState();
    447     /* Driver started */
    448     private State mDriverStartedState = new DriverStartedState();
    449     /* Driver stopping */
    450     private State mDriverStoppingState = new DriverStoppingState();
    451     /* Driver stopped */
    452     private State mDriverStoppedState = new DriverStoppedState();
    453     /* Scan for networks, no connection will be established */
    454     private State mScanModeState = new ScanModeState();
    455     /* Connecting to an access point */
    456     private State mConnectModeState = new ConnectModeState();
    457     /* Fetching IP after network connection (assoc+auth complete) */
    458     private State mConnectingState = new ConnectingState();
    459     /* Connected with IP addr */
    460     private State mConnectedState = new ConnectedState();
    461     /* disconnect issued, waiting for network disconnect confirmation */
    462     private State mDisconnectingState = new DisconnectingState();
    463     /* Network is not connected, supplicant assoc+auth is not complete */
    464     private State mDisconnectedState = new DisconnectedState();
    465     /* Waiting for WPS to be completed*/
    466     private State mWaitForWpsCompletionState = new WaitForWpsCompletionState();
    467 
    468     /* Soft ap is starting up */
    469     private State mSoftApStartingState = new SoftApStartingState();
    470     /* Soft ap is running */
    471     private State mSoftApStartedState = new SoftApStartedState();
    472     /* Soft ap is running and we are waiting for tether notification */
    473     private State mTetheringState = new TetheringState();
    474     /* Soft ap is running and we are tethered through connectivity service */
    475     private State mTetheredState = new TetheredState();
    476     /* Waiting for untether confirmation to stop soft Ap */
    477     private State mSoftApStoppingState = new SoftApStoppingState();
    478 
    479     /* Wait till p2p is disabled */
    480     private State mWaitForP2pDisableState = new WaitForP2pDisableState();
    481 
    482     private class TetherStateChange {
    483         ArrayList<String> available;
    484         ArrayList<String> active;
    485         TetherStateChange(ArrayList<String> av, ArrayList<String> ac) {
    486             available = av;
    487             active = ac;
    488         }
    489     }
    490 
    491 
    492     /**
    493      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
    494      *         {@link WifiManager#WIFI_STATE_DISABLING},
    495      *         {@link WifiManager#WIFI_STATE_ENABLED},
    496      *         {@link WifiManager#WIFI_STATE_ENABLING},
    497      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
    498      *
    499      */
    500     private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
    501 
    502     /**
    503      * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
    504      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
    505      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
    506      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
    507      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
    508      *
    509      */
    510     private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
    511 
    512     private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
    513     private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
    514 
    515     private static final int SCAN_REQUEST = 0;
    516     private static final String ACTION_START_SCAN =
    517         "com.android.server.WifiManager.action.START_SCAN";
    518 
    519     /**
    520      * Keep track of whether WIFI is running.
    521      */
    522     private boolean mIsRunning = false;
    523 
    524     /**
    525      * Keep track of whether we last told the battery stats we had started.
    526      */
    527     private boolean mReportedRunning = false;
    528 
    529     /**
    530      * Most recently set source of starting WIFI.
    531      */
    532     private final WorkSource mRunningWifiUids = new WorkSource();
    533 
    534     /**
    535      * The last reported UIDs that were responsible for starting WIFI.
    536      */
    537     private final WorkSource mLastRunningWifiUids = new WorkSource();
    538 
    539     private final IBatteryStats mBatteryStats;
    540     private boolean mNextWifiActionExplicit = false;
    541     private int mLastExplicitNetworkId;
    542     private long mLastNetworkChoiceTime;
    543     private static final long EXPLICIT_CONNECT_ALLOWED_DELAY_MS = 2 * 60 * 1000;
    544 
    545 
    546     public WifiStateMachine(Context context, String wlanInterface) {
    547         super(TAG);
    548 
    549         mContext = context;
    550         mInterfaceName = wlanInterface;
    551 
    552         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
    553         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
    554 
    555         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
    556         mNwService = INetworkManagementService.Stub.asInterface(b);
    557 
    558         mWifiMonitor = new WifiMonitor(this);
    559         mDhcpInfoInternal = new DhcpInfoInternal();
    560         mWifiInfo = new WifiInfo();
    561         mSupplicantStateTracker = new SupplicantStateTracker(context, this, getHandler());
    562         mWpsStateMachine = new WpsStateMachine(context, this, getHandler());
    563         mLinkProperties = new LinkProperties();
    564 
    565         WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
    566                 context, getHandler());
    567         wifiApConfigStore.loadApConfiguration();
    568         mWifiApConfigChannel.connectSync(mContext, getHandler(), wifiApConfigStore.getMessenger());
    569 
    570         mNetworkInfo.setIsAvailable(false);
    571         mLinkProperties.clear();
    572         mLastBssid = null;
    573         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
    574         mLastSignalLevel = -1;
    575 
    576         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
    577         Intent scanIntent = new Intent(ACTION_START_SCAN, null);
    578         mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
    579 
    580         mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger(
    581                 com.android.internal.R.integer.config_wifi_framework_scan_interval);
    582 
    583         mDefaultSupplicantScanIntervalMs = mContext.getResources().getInteger(
    584                 com.android.internal.R.integer.config_wifi_supplicant_scan_interval);
    585 
    586         mContext.registerReceiver(
    587             new BroadcastReceiver() {
    588                 @Override
    589                 public void onReceive(Context context, Intent intent) {
    590                     ArrayList<String> available = intent.getStringArrayListExtra(
    591                             ConnectivityManager.EXTRA_AVAILABLE_TETHER);
    592                     ArrayList<String> active = intent.getStringArrayListExtra(
    593                             ConnectivityManager.EXTRA_ACTIVE_TETHER);
    594                     sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active));
    595                 }
    596             },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
    597 
    598         mContext.registerReceiver(
    599                 new BroadcastReceiver() {
    600                     @Override
    601                     public void onReceive(Context context, Intent intent) {
    602                         startScan(false);
    603                     }
    604                 },
    605                 new IntentFilter(ACTION_START_SCAN));
    606 
    607         mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
    608 
    609         PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
    610         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    611 
    612         addState(mDefaultState);
    613             addState(mInitialState, mDefaultState);
    614             addState(mDriverUnloadingState, mDefaultState);
    615             addState(mDriverUnloadedState, mDefaultState);
    616                 addState(mDriverFailedState, mDriverUnloadedState);
    617             addState(mDriverLoadingState, mDefaultState);
    618             addState(mDriverLoadedState, mDefaultState);
    619             addState(mSupplicantStartingState, mDefaultState);
    620             addState(mSupplicantStartedState, mDefaultState);
    621                 addState(mDriverStartingState, mSupplicantStartedState);
    622                 addState(mDriverStartedState, mSupplicantStartedState);
    623                     addState(mScanModeState, mDriverStartedState);
    624                     addState(mConnectModeState, mDriverStartedState);
    625                         addState(mConnectingState, mConnectModeState);
    626                         addState(mConnectedState, mConnectModeState);
    627                         addState(mDisconnectingState, mConnectModeState);
    628                         addState(mDisconnectedState, mConnectModeState);
    629                         addState(mWaitForWpsCompletionState, mConnectModeState);
    630                 addState(mDriverStoppingState, mSupplicantStartedState);
    631                 addState(mDriverStoppedState, mSupplicantStartedState);
    632             addState(mSupplicantStoppingState, mDefaultState);
    633             addState(mSoftApStartingState, mDefaultState);
    634             addState(mSoftApStartedState, mDefaultState);
    635                 addState(mTetheringState, mSoftApStartedState);
    636                 addState(mTetheredState, mSoftApStartedState);
    637             addState(mSoftApStoppingState, mDefaultState);
    638             addState(mWaitForP2pDisableState, mDefaultState);
    639 
    640         setInitialState(mInitialState);
    641 
    642         if (DBG) setDbg(true);
    643 
    644         //start the state machine
    645         start();
    646     }
    647 
    648     /*********************************************************
    649      * Methods exposed for public use
    650      ********************************************************/
    651 
    652     /**
    653      * TODO: doc
    654      */
    655     public boolean syncPingSupplicant(AsyncChannel channel) {
    656         Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
    657         boolean result = (resultMsg.arg1 != FAILURE);
    658         resultMsg.recycle();
    659         return result;
    660     }
    661 
    662     /**
    663      * TODO: doc
    664      */
    665     public void startScan(boolean forceActive) {
    666         sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?
    667                 SCAN_ACTIVE : SCAN_PASSIVE, 0));
    668     }
    669 
    670     /**
    671      * TODO: doc
    672      */
    673     public void setWifiEnabled(boolean enable) {
    674         mLastEnableUid.set(Binder.getCallingUid());
    675         if (enable) {
    676             /* Argument is the state that is entered prior to load */
    677             sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
    678             sendMessage(CMD_START_SUPPLICANT);
    679         } else {
    680             sendMessage(CMD_STOP_SUPPLICANT);
    681             /* Argument is the state that is entered upon success */
    682             sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
    683         }
    684     }
    685 
    686     /**
    687      * TODO: doc
    688      */
    689     public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
    690         mLastApEnableUid.set(Binder.getCallingUid());
    691         if (enable) {
    692             /* Argument is the state that is entered prior to load */
    693             sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
    694             sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
    695         } else {
    696             sendMessage(CMD_STOP_AP);
    697             /* Argument is the state that is entered upon success */
    698             sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
    699         }
    700     }
    701 
    702     public void setWifiApConfiguration(WifiConfiguration config) {
    703         mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
    704     }
    705 
    706     public WifiConfiguration syncGetWifiApConfiguration() {
    707         Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
    708         WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
    709         resultMsg.recycle();
    710         return ret;
    711     }
    712 
    713     /**
    714      * TODO: doc
    715      */
    716     public int syncGetWifiState() {
    717         return mWifiState.get();
    718     }
    719 
    720     /**
    721      * TODO: doc
    722      */
    723     public String syncGetWifiStateByName() {
    724         switch (mWifiState.get()) {
    725             case WIFI_STATE_DISABLING:
    726                 return "disabling";
    727             case WIFI_STATE_DISABLED:
    728                 return "disabled";
    729             case WIFI_STATE_ENABLING:
    730                 return "enabling";
    731             case WIFI_STATE_ENABLED:
    732                 return "enabled";
    733             case WIFI_STATE_UNKNOWN:
    734                 return "unknown state";
    735             default:
    736                 return "[invalid state]";
    737         }
    738     }
    739 
    740     /**
    741      * TODO: doc
    742      */
    743     public int syncGetWifiApState() {
    744         return mWifiApState.get();
    745     }
    746 
    747     /**
    748      * TODO: doc
    749      */
    750     public String syncGetWifiApStateByName() {
    751         switch (mWifiApState.get()) {
    752             case WIFI_AP_STATE_DISABLING:
    753                 return "disabling";
    754             case WIFI_AP_STATE_DISABLED:
    755                 return "disabled";
    756             case WIFI_AP_STATE_ENABLING:
    757                 return "enabling";
    758             case WIFI_AP_STATE_ENABLED:
    759                 return "enabled";
    760             case WIFI_AP_STATE_FAILED:
    761                 return "failed";
    762             default:
    763                 return "[invalid state]";
    764         }
    765     }
    766 
    767     /**
    768      * Get status information for the current connection, if any.
    769      * @return a {@link WifiInfo} object containing information about the current connection
    770      *
    771      */
    772     public WifiInfo syncRequestConnectionInfo() {
    773         return mWifiInfo;
    774     }
    775 
    776     public DhcpInfo syncGetDhcpInfo() {
    777         synchronized (mDhcpInfoInternal) {
    778             return mDhcpInfoInternal.makeDhcpInfo();
    779         }
    780     }
    781 
    782     /**
    783      * TODO: doc
    784      */
    785     public void setDriverStart(boolean enable, boolean ecm) {
    786         if (enable) {
    787             sendMessage(CMD_START_DRIVER);
    788         } else {
    789             sendMessage(obtainMessage(CMD_STOP_DRIVER, ecm ? IN_ECM_STATE : NOT_IN_ECM_STATE, 0));
    790         }
    791     }
    792 
    793     /**
    794      * TODO: doc
    795      */
    796     public void setScanOnlyMode(boolean enable) {
    797       if (enable) {
    798           sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
    799       } else {
    800           sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
    801       }
    802     }
    803 
    804     /**
    805      * TODO: doc
    806      */
    807     public void setScanType(boolean active) {
    808       if (active) {
    809           sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
    810       } else {
    811           sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
    812       }
    813     }
    814 
    815     /**
    816      * TODO: doc
    817      */
    818     public List<ScanResult> syncGetScanResultsList() {
    819         return mScanResults;
    820     }
    821 
    822     /**
    823      * Disconnect from Access Point
    824      */
    825     public void disconnectCommand() {
    826         sendMessage(CMD_DISCONNECT);
    827     }
    828 
    829     /**
    830      * Initiate a reconnection to AP
    831      */
    832     public void reconnectCommand() {
    833         sendMessage(CMD_RECONNECT);
    834     }
    835 
    836     /**
    837      * Initiate a re-association to AP
    838      */
    839     public void reassociateCommand() {
    840         sendMessage(CMD_REASSOCIATE);
    841     }
    842 
    843     /**
    844      * Add a network synchronously
    845      *
    846      * @return network id of the new network
    847      */
    848     public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
    849         Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
    850         int result = resultMsg.arg1;
    851         resultMsg.recycle();
    852         return result;
    853     }
    854 
    855     public List<WifiConfiguration> syncGetConfiguredNetworks() {
    856         return WifiConfigStore.getConfiguredNetworks();
    857     }
    858 
    859     /**
    860      * Delete a network
    861      *
    862      * @param networkId id of the network to be removed
    863      */
    864     public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
    865         Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
    866         boolean result = (resultMsg.arg1 != FAILURE);
    867         resultMsg.recycle();
    868         return result;
    869     }
    870 
    871     /**
    872      * Enable a network
    873      *
    874      * @param netId network id of the network
    875      * @param disableOthers true, if all other networks have to be disabled
    876      * @return {@code true} if the operation succeeds, {@code false} otherwise
    877      */
    878     public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
    879         Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
    880                 disableOthers ? 1 : 0);
    881         boolean result = (resultMsg.arg1 != FAILURE);
    882         resultMsg.recycle();
    883         return result;
    884     }
    885 
    886     /**
    887      * Disable a network
    888      *
    889      * @param netId network id of the network
    890      * @return {@code true} if the operation succeeds, {@code false} otherwise
    891      */
    892     public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
    893         Message resultMsg = channel.sendMessageSynchronously(CMD_DISABLE_NETWORK, netId,
    894                 WifiConfiguration.DISABLED_UNKNOWN_REASON);
    895         boolean result = (resultMsg.arg1 != FAILURE);
    896         resultMsg.recycle();
    897         return result;
    898     }
    899 
    900     /**
    901      * Blacklist a BSSID. This will avoid the AP if there are
    902      * alternate APs to connect
    903      *
    904      * @param bssid BSSID of the network
    905      */
    906     public void addToBlacklist(String bssid) {
    907         sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
    908     }
    909 
    910     /**
    911      * Clear the blacklist list
    912      *
    913      */
    914     public void clearBlacklist() {
    915         sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
    916     }
    917 
    918     public void connectNetwork(int netId) {
    919         sendMessage(obtainMessage(CMD_CONNECT_NETWORK, netId, 0));
    920     }
    921 
    922     public void connectNetwork(WifiConfiguration wifiConfig) {
    923         /* arg1 is used to indicate netId, force a netId value of
    924          * WifiConfiguration.INVALID_NETWORK_ID when we are passing
    925          * a configuration since the default value of 0 is a valid netId
    926          */
    927         sendMessage(obtainMessage(CMD_CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
    928                 0, wifiConfig));
    929     }
    930 
    931     public void saveNetwork(WifiConfiguration wifiConfig) {
    932         sendMessage(obtainMessage(CMD_SAVE_NETWORK, wifiConfig));
    933     }
    934 
    935     public void forgetNetwork(int netId) {
    936         sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0));
    937     }
    938 
    939     public void disableNetwork(Messenger replyTo, int netId, int reason) {
    940         Message message = obtainMessage(CMD_DISABLE_NETWORK, netId, reason);
    941         message.replyTo = replyTo;
    942         sendMessage(message);
    943     }
    944 
    945     public void startWps(Messenger replyTo, WpsInfo config) {
    946         Message msg = obtainMessage(CMD_START_WPS, config);
    947         msg.replyTo = replyTo;
    948         sendMessage(msg);
    949     }
    950 
    951     public void enableRssiPolling(boolean enabled) {
    952        sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
    953     }
    954 
    955     public void enableBackgroundScanCommand(boolean enabled) {
    956        sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0));
    957     }
    958 
    959     public void enableAllNetworks() {
    960         sendMessage(CMD_ENABLE_ALL_NETWORKS);
    961     }
    962 
    963     /**
    964      * Start filtering Multicast v4 packets
    965      */
    966     public void startFilteringMulticastV4Packets() {
    967         mFilteringMulticastV4Packets.set(true);
    968         sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0));
    969     }
    970 
    971     /**
    972      * Stop filtering Multicast v4 packets
    973      */
    974     public void stopFilteringMulticastV4Packets() {
    975         mFilteringMulticastV4Packets.set(false);
    976         sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0));
    977     }
    978 
    979     /**
    980      * Start filtering Multicast v4 packets
    981      */
    982     public void startFilteringMulticastV6Packets() {
    983         sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0));
    984     }
    985 
    986     /**
    987      * Stop filtering Multicast v4 packets
    988      */
    989     public void stopFilteringMulticastV6Packets() {
    990         sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0));
    991     }
    992 
    993     /**
    994      * Set high performance mode of operation.
    995      * Enabling would set active power mode and disable suspend optimizations;
    996      * disabling would set auto power mode and enable suspend optimizations
    997      * @param enable true if enable, false otherwise
    998      */
    999     public void setHighPerfModeEnabled(boolean enable) {
   1000         sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0));
   1001     }
   1002 
   1003     /**
   1004      * Set the country code
   1005      * @param countryCode following ISO 3166 format
   1006      * @param persist {@code true} if the setting should be remembered.
   1007      */
   1008     public void setCountryCode(String countryCode, boolean persist) {
   1009         if (persist) {
   1010             Settings.Secure.putString(mContext.getContentResolver(),
   1011                     Settings.Secure.WIFI_COUNTRY_CODE,
   1012                     countryCode);
   1013         }
   1014         sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode));
   1015     }
   1016 
   1017     /**
   1018      * Set the operational frequency band
   1019      * @param band
   1020      * @param persist {@code true} if the setting should be remembered.
   1021      */
   1022     public void setFrequencyBand(int band, boolean persist) {
   1023         if (persist) {
   1024             Settings.Secure.putInt(mContext.getContentResolver(),
   1025                     Settings.Secure.WIFI_FREQUENCY_BAND,
   1026                     band);
   1027         }
   1028         sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0));
   1029     }
   1030 
   1031     /**
   1032      * Returns the operational frequency band
   1033      */
   1034     public int getFrequencyBand() {
   1035         return mFrequencyBand.get();
   1036     }
   1037 
   1038     /**
   1039      * Returns the wifi configuration file
   1040      */
   1041     public String getConfigFile() {
   1042         return WifiConfigStore.getConfigFile();
   1043     }
   1044 
   1045     /**
   1046      * Send a message indicating bluetooth adapter connection state changed
   1047      */
   1048     public void sendBluetoothAdapterStateChange(int state) {
   1049         sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0));
   1050     }
   1051 
   1052     /**
   1053      * Save configuration on supplicant
   1054      *
   1055      * @return {@code true} if the operation succeeds, {@code false} otherwise
   1056      *
   1057      * TODO: deprecate this
   1058      */
   1059     public boolean syncSaveConfig(AsyncChannel channel) {
   1060         Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
   1061         boolean result = (resultMsg.arg1 != FAILURE);
   1062         resultMsg.recycle();
   1063         return result;
   1064     }
   1065 
   1066     public void updateBatteryWorkSource(WorkSource newSource) {
   1067         synchronized (mRunningWifiUids) {
   1068             try {
   1069                 if (newSource != null) {
   1070                     mRunningWifiUids.set(newSource);
   1071                 }
   1072                 if (mIsRunning) {
   1073                     if (mReportedRunning) {
   1074                         // If the work source has changed since last time, need
   1075                         // to remove old work from battery stats.
   1076                         if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
   1077                             mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
   1078                                     mRunningWifiUids);
   1079                             mLastRunningWifiUids.set(mRunningWifiUids);
   1080                         }
   1081                     } else {
   1082                         // Now being started, report it.
   1083                         mBatteryStats.noteWifiRunning(mRunningWifiUids);
   1084                         mLastRunningWifiUids.set(mRunningWifiUids);
   1085                         mReportedRunning = true;
   1086                     }
   1087                 } else {
   1088                     if (mReportedRunning) {
   1089                         // Last reported we were running, time to stop.
   1090                         mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
   1091                         mLastRunningWifiUids.clear();
   1092                         mReportedRunning = false;
   1093                     }
   1094                 }
   1095                 mWakeLock.setWorkSource(newSource);
   1096             } catch (RemoteException ignore) {
   1097             }
   1098         }
   1099     }
   1100 
   1101     @Override
   1102     public String toString() {
   1103         StringBuffer sb = new StringBuffer();
   1104         String LS = System.getProperty("line.separator");
   1105         sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS);
   1106         sb.append("mLinkProperties ").append(mLinkProperties).append(LS);
   1107         sb.append("mWifiInfo ").append(mWifiInfo).append(LS);
   1108         sb.append("mDhcpInfoInternal ").append(mDhcpInfoInternal).append(LS);
   1109         sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS);
   1110         sb.append("mLastSignalLevel ").append(mLastSignalLevel).append(LS);
   1111         sb.append("mLastBssid ").append(mLastBssid).append(LS);
   1112         sb.append("mLastNetworkId ").append(mLastNetworkId).append(LS);
   1113         sb.append("mReconnectCount ").append(mReconnectCount).append(LS);
   1114         sb.append("mIsScanMode ").append(mIsScanMode).append(LS);
   1115         sb.append("Supplicant status").append(LS)
   1116                 .append(WifiNative.statusCommand()).append(LS).append(LS);
   1117 
   1118         sb.append(WifiConfigStore.dump());
   1119         return sb.toString();
   1120     }
   1121 
   1122     /*********************************************************
   1123      * Internal private functions
   1124      ********************************************************/
   1125 
   1126     private void checkAndSetConnectivityInstance() {
   1127         if (mCm == null) {
   1128             mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
   1129         }
   1130     }
   1131 
   1132     private boolean startTethering(ArrayList<String> available) {
   1133 
   1134         boolean wifiAvailable = false;
   1135 
   1136         checkAndSetConnectivityInstance();
   1137 
   1138         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
   1139 
   1140         for (String intf : available) {
   1141             for (String regex : wifiRegexs) {
   1142                 if (intf.matches(regex)) {
   1143 
   1144                     InterfaceConfiguration ifcg = null;
   1145                     try {
   1146                         ifcg = mNwService.getInterfaceConfig(intf);
   1147                         if (ifcg != null) {
   1148                             /* IP/netmask: 192.168.43.1/255.255.255.0 */
   1149                             ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress(
   1150                                     "192.168.43.1"), 24);
   1151                             ifcg.interfaceFlags = "[up]";
   1152 
   1153                             mNwService.setInterfaceConfig(intf, ifcg);
   1154                         }
   1155                     } catch (Exception e) {
   1156                         loge("Error configuring interface " + intf + ", :" + e);
   1157                         return false;
   1158                     }
   1159 
   1160                     if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
   1161                         loge("Error tethering on " + intf);
   1162                         return false;
   1163                     }
   1164                     mTetherInterfaceName = intf;
   1165                     return true;
   1166                 }
   1167             }
   1168         }
   1169         // We found no interfaces to tether
   1170         return false;
   1171     }
   1172 
   1173     private void stopTethering() {
   1174 
   1175         checkAndSetConnectivityInstance();
   1176 
   1177         /* Clear the interface config to allow dhcp correctly configure new
   1178            ip settings */
   1179         InterfaceConfiguration ifcg = null;
   1180         try {
   1181             ifcg = mNwService.getInterfaceConfig(mInterfaceName);
   1182             if (ifcg != null) {
   1183                 ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress(
   1184                             "0.0.0.0"), 0);
   1185                 mNwService.setInterfaceConfig(mInterfaceName, ifcg);
   1186             }
   1187         } catch (Exception e) {
   1188             loge("Error resetting interface " + mInterfaceName + ", :" + e);
   1189         }
   1190 
   1191         if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
   1192             loge("Untether initiate failed!");
   1193         }
   1194     }
   1195 
   1196     private boolean isWifiTethered(ArrayList<String> active) {
   1197 
   1198         checkAndSetConnectivityInstance();
   1199 
   1200         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
   1201         for (String intf : active) {
   1202             for (String regex : wifiRegexs) {
   1203                 if (intf.matches(regex)) {
   1204                     return true;
   1205                 }
   1206             }
   1207         }
   1208         // We found no interfaces that are tethered
   1209         return false;
   1210     }
   1211 
   1212     /**
   1213      * Set the country code from the system setting value, if any.
   1214      */
   1215     private void setCountryCode() {
   1216         String countryCode = Settings.Secure.getString(mContext.getContentResolver(),
   1217                 Settings.Secure.WIFI_COUNTRY_CODE);
   1218         if (countryCode != null && !countryCode.isEmpty()) {
   1219             setCountryCode(countryCode, false);
   1220         } else {
   1221             //use driver default
   1222         }
   1223     }
   1224 
   1225     /**
   1226      * Set the frequency band from the system setting value, if any.
   1227      */
   1228     private void setFrequencyBand() {
   1229         int band = Settings.Secure.getInt(mContext.getContentResolver(),
   1230                 Settings.Secure.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
   1231         setFrequencyBand(band, false);
   1232     }
   1233 
   1234     private void setWifiState(int wifiState) {
   1235         final int previousWifiState = mWifiState.get();
   1236 
   1237         try {
   1238             if (wifiState == WIFI_STATE_ENABLED) {
   1239                 mBatteryStats.noteWifiOn();
   1240             } else if (wifiState == WIFI_STATE_DISABLED) {
   1241                 mBatteryStats.noteWifiOff();
   1242             }
   1243         } catch (RemoteException e) {
   1244             loge("Failed to note battery stats in wifi");
   1245         }
   1246 
   1247         mWifiState.set(wifiState);
   1248 
   1249         if (DBG) log("setWifiState: " + syncGetWifiStateByName());
   1250 
   1251         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
   1252         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1253         intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
   1254         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
   1255         mContext.sendStickyBroadcast(intent);
   1256     }
   1257 
   1258     private void setWifiApState(int wifiApState) {
   1259         final int previousWifiApState = mWifiApState.get();
   1260 
   1261         try {
   1262             if (wifiApState == WIFI_AP_STATE_ENABLED) {
   1263                 mBatteryStats.noteWifiOn();
   1264             } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
   1265                 mBatteryStats.noteWifiOff();
   1266             }
   1267         } catch (RemoteException e) {
   1268             loge("Failed to note battery stats in wifi");
   1269         }
   1270 
   1271         // Update state
   1272         mWifiApState.set(wifiApState);
   1273 
   1274         if (DBG) log("setWifiApState: " + syncGetWifiApStateByName());
   1275 
   1276         final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
   1277         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1278         intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
   1279         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
   1280         mContext.sendStickyBroadcast(intent);
   1281     }
   1282 
   1283     /**
   1284      * Parse the scan result line passed to us by wpa_supplicant (helper).
   1285      * @param line the line to parse
   1286      * @return the {@link ScanResult} object
   1287      */
   1288     private ScanResult parseScanResult(String line) {
   1289         ScanResult scanResult = null;
   1290         if (line != null) {
   1291             /*
   1292              * Cache implementation (LinkedHashMap) is not synchronized, thus,
   1293              * must synchronized here!
   1294              */
   1295             synchronized (mScanResultCache) {
   1296                 String[] result = scanResultPattern.split(line);
   1297                 if (3 <= result.length && result.length <= 5) {
   1298                     String bssid = result[0];
   1299                     // bssid | frequency | level | flags | ssid
   1300                     int frequency;
   1301                     int level;
   1302                     try {
   1303                         frequency = Integer.parseInt(result[1]);
   1304                         level = Integer.parseInt(result[2]);
   1305                         /* some implementations avoid negative values by adding 256
   1306                          * so we need to adjust for that here.
   1307                          */
   1308                         if (level > 0) level -= 256;
   1309                     } catch (NumberFormatException e) {
   1310                         frequency = 0;
   1311                         level = 0;
   1312                     }
   1313 
   1314                     /*
   1315                      * The formatting of the results returned by
   1316                      * wpa_supplicant is intended to make the fields
   1317                      * line up nicely when printed,
   1318                      * not to make them easy to parse. So we have to
   1319                      * apply some heuristics to figure out which field
   1320                      * is the SSID and which field is the flags.
   1321                      */
   1322                     String ssid;
   1323                     String flags;
   1324                     if (result.length == 4) {
   1325                         if (result[3].charAt(0) == '[') {
   1326                             flags = result[3];
   1327                             ssid = "";
   1328                         } else {
   1329                             flags = "";
   1330                             ssid = result[3];
   1331                         }
   1332                     } else if (result.length == 5) {
   1333                         flags = result[3];
   1334                         ssid = result[4];
   1335                     } else {
   1336                         // Here, we must have 3 fields: no flags and ssid
   1337                         // set
   1338                         flags = "";
   1339                         ssid = "";
   1340                     }
   1341 
   1342                     // bssid + ssid is the hash key
   1343                     String key = bssid + ssid;
   1344                     scanResult = mScanResultCache.get(key);
   1345                     if (scanResult != null) {
   1346                         scanResult.level = level;
   1347                         scanResult.SSID = ssid;
   1348                         scanResult.capabilities = flags;
   1349                         scanResult.frequency = frequency;
   1350                     } else {
   1351                         // Do not add scan results that have no SSID set
   1352                         if (0 < ssid.trim().length()) {
   1353                             scanResult =
   1354                                 new ScanResult(
   1355                                     ssid, bssid, flags, level, frequency);
   1356                             mScanResultCache.put(key, scanResult);
   1357                         }
   1358                     }
   1359                 } else {
   1360                     loge("Misformatted scan result text with " +
   1361                           result.length + " fields: " + line);
   1362                 }
   1363             }
   1364         }
   1365 
   1366         return scanResult;
   1367     }
   1368 
   1369     /**
   1370      * scanResults input format
   1371      * 00:bb:cc:dd:cc:ee       2427    166     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net1
   1372      * 00:bb:cc:dd:cc:ff       2412    165     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net2
   1373      */
   1374     private void setScanResults(String scanResults) {
   1375         if (scanResults == null) {
   1376             return;
   1377         }
   1378 
   1379         List<ScanResult> scanList = new ArrayList<ScanResult>();
   1380 
   1381         int lineCount = 0;
   1382 
   1383         int scanResultsLen = scanResults.length();
   1384         // Parse the result string, keeping in mind that the last line does
   1385         // not end with a newline.
   1386         for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
   1387             if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
   1388                 ++lineCount;
   1389 
   1390                 if (lineCount == 1) {
   1391                     lineBeg = lineEnd + 1;
   1392                     continue;
   1393                 }
   1394                 if (lineEnd > lineBeg) {
   1395                     String line = scanResults.substring(lineBeg, lineEnd);
   1396                     ScanResult scanResult = parseScanResult(line);
   1397                     if (scanResult != null) {
   1398                         scanList.add(scanResult);
   1399                     } else {
   1400                         //TODO: hidden network handling
   1401                     }
   1402                 }
   1403                 lineBeg = lineEnd + 1;
   1404             }
   1405         }
   1406 
   1407         mScanResults = scanList;
   1408     }
   1409 
   1410     private String fetchSSID() {
   1411         String status = WifiNative.statusCommand();
   1412         if (status == null) {
   1413             return null;
   1414         }
   1415         // extract ssid from a series of "name=value"
   1416         String[] lines = status.split("\n");
   1417         for (String line : lines) {
   1418             String[] prop = line.split(" *= *");
   1419             if (prop.length < 2) continue;
   1420             String name = prop[0];
   1421             String value = prop[1];
   1422             if (name.equalsIgnoreCase("ssid")) return value;
   1423         }
   1424         return null;
   1425     }
   1426 
   1427     /*
   1428      * Fetch RSSI and linkspeed on current connection
   1429      */
   1430     private void fetchRssiAndLinkSpeedNative() {
   1431         int newRssi = -1;
   1432         int newLinkSpeed = -1;
   1433 
   1434         String signalPoll = WifiNative.signalPoll();
   1435 
   1436         if (signalPoll != null) {
   1437             String[] lines = signalPoll.split("\n");
   1438             for (String line : lines) {
   1439                 String[] prop = line.split("=");
   1440                 if (prop.length < 2) continue;
   1441                 try {
   1442                     if (prop[0].equals("RSSI")) {
   1443                         newRssi = Integer.parseInt(prop[1]);
   1444                     } else if (prop[0].equals("LINKSPEED")) {
   1445                         newLinkSpeed = Integer.parseInt(prop[1]);
   1446                     }
   1447                 } catch (NumberFormatException e) {
   1448                     //Ignore, defaults on rssi and linkspeed are assigned
   1449                 }
   1450             }
   1451         }
   1452 
   1453         if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values
   1454             /* some implementations avoid negative values by adding 256
   1455              * so we need to adjust for that here.
   1456              */
   1457             if (newRssi > 0) newRssi -= 256;
   1458             mWifiInfo.setRssi(newRssi);
   1459             /*
   1460              * Rather then sending the raw RSSI out every time it
   1461              * changes, we precalculate the signal level that would
   1462              * be displayed in the status bar, and only send the
   1463              * broadcast if that much more coarse-grained number
   1464              * changes. This cuts down greatly on the number of
   1465              * broadcasts, at the cost of not mWifiInforming others
   1466              * interested in RSSI of all the changes in signal
   1467              * level.
   1468              */
   1469             // TODO: The second arg to the call below needs to be a symbol somewhere, but
   1470             // it's actually the size of an array of icons that's private
   1471             // to StatusBar Policy.
   1472             int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
   1473             if (newSignalLevel != mLastSignalLevel) {
   1474                 sendRssiChangeBroadcast(newRssi);
   1475             }
   1476             mLastSignalLevel = newSignalLevel;
   1477         } else {
   1478             mWifiInfo.setRssi(MIN_RSSI);
   1479         }
   1480 
   1481         if (newLinkSpeed != -1) {
   1482             mWifiInfo.setLinkSpeed(newLinkSpeed);
   1483         }
   1484     }
   1485 
   1486     private void setHighPerfModeEnabledNative(boolean enable) {
   1487         if(!WifiNative.setSuspendOptimizationsCommand(!enable)) {
   1488             loge("set suspend optimizations failed!");
   1489         }
   1490         if (enable) {
   1491             if (!WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE)) {
   1492                 loge("set power mode active failed!");
   1493             }
   1494         } else {
   1495             if (!WifiNative.setPowerModeCommand(POWER_MODE_AUTO)) {
   1496                 loge("set power mode auto failed!");
   1497             }
   1498         }
   1499     }
   1500 
   1501     private void configureLinkProperties() {
   1502         if (WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
   1503             mLinkProperties = WifiConfigStore.getLinkProperties(mLastNetworkId);
   1504         } else {
   1505             synchronized (mDhcpInfoInternal) {
   1506                 mLinkProperties = mDhcpInfoInternal.makeLinkProperties();
   1507             }
   1508             mLinkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
   1509         }
   1510         mLinkProperties.setInterfaceName(mInterfaceName);
   1511         if (DBG) {
   1512             log("netId=" + mLastNetworkId  + " Link configured: " +
   1513                     mLinkProperties.toString());
   1514         }
   1515     }
   1516 
   1517     private int getMaxDhcpRetries() {
   1518         return Settings.Secure.getInt(mContext.getContentResolver(),
   1519                                       Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
   1520                                       DEFAULT_MAX_DHCP_RETRIES);
   1521     }
   1522 
   1523     private void sendScanResultsAvailableBroadcast() {
   1524         Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
   1525         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1526         mContext.sendBroadcast(intent);
   1527     }
   1528 
   1529     private void sendRssiChangeBroadcast(final int newRssi) {
   1530         Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
   1531         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1532         intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
   1533         mContext.sendBroadcast(intent);
   1534     }
   1535 
   1536     private void sendNetworkStateChangeBroadcast(String bssid) {
   1537         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
   1538         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
   1539                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1540         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
   1541         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
   1542         if (bssid != null)
   1543             intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
   1544         if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED)
   1545             intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo));
   1546         mContext.sendStickyBroadcast(intent);
   1547     }
   1548 
   1549     private void sendErrorBroadcast(int errorCode) {
   1550         Intent intent = new Intent(WifiManager.ERROR_ACTION);
   1551         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1552         intent.putExtra(WifiManager.EXTRA_ERROR_CODE, errorCode);
   1553         mContext.sendBroadcast(intent);
   1554     }
   1555 
   1556     private void sendLinkConfigurationChangedBroadcast() {
   1557         Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
   1558         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1559         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
   1560         mContext.sendBroadcast(intent);
   1561     }
   1562 
   1563     private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
   1564         Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
   1565         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1566         intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
   1567         mContext.sendBroadcast(intent);
   1568     }
   1569 
   1570     /**
   1571      * Record the detailed state of a network.
   1572      * @param state the new @{code DetailedState}
   1573      */
   1574     private void setNetworkDetailedState(NetworkInfo.DetailedState state) {
   1575         if (DBG) {
   1576             log("setDetailed state, old ="
   1577                     + mNetworkInfo.getDetailedState() + " and new state=" + state);
   1578         }
   1579 
   1580         if (state != mNetworkInfo.getDetailedState()) {
   1581             mNetworkInfo.setDetailedState(state, null, null);
   1582         }
   1583     }
   1584 
   1585     private DetailedState getNetworkDetailedState() {
   1586         return mNetworkInfo.getDetailedState();
   1587     }
   1588 
   1589 
   1590     private SupplicantState handleSupplicantStateChange(Message message) {
   1591         StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   1592         SupplicantState state = stateChangeResult.state;
   1593         // Supplicant state change
   1594         // [31-13] Reserved for future use
   1595         // [8 - 0] Supplicant state (as defined in SupplicantState.java)
   1596         // 50023 supplicant_state_changed (custom|1|5)
   1597         EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
   1598         mWifiInfo.setSupplicantState(state);
   1599         // Network id is only valid when we start connecting
   1600         if (SupplicantState.isConnecting(state)) {
   1601             mWifiInfo.setNetworkId(stateChangeResult.networkId);
   1602         } else {
   1603             mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
   1604         }
   1605 
   1606         if (state == SupplicantState.ASSOCIATING) {
   1607             /* BSSID is valid only in ASSOCIATING state */
   1608             mWifiInfo.setBSSID(stateChangeResult.BSSID);
   1609         }
   1610 
   1611         mSupplicantStateTracker.sendMessage(Message.obtain(message));
   1612         mWpsStateMachine.sendMessage(Message.obtain(message));
   1613 
   1614         return state;
   1615     }
   1616 
   1617     /**
   1618      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
   1619      * using the interface, stopping DHCP & disabling interface
   1620      */
   1621     private void handleNetworkDisconnect() {
   1622         if (DBG) log("Stopping DHCP and clearing IP");
   1623 
   1624         /*
   1625          * stop DHCP
   1626          */
   1627         if (mDhcpStateMachine != null) {
   1628             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
   1629             mDhcpStateMachine.quit();
   1630             mDhcpStateMachine = null;
   1631         }
   1632 
   1633         try {
   1634             mNwService.clearInterfaceAddresses(mInterfaceName);
   1635             mNwService.disableIpv6(mInterfaceName);
   1636         } catch (Exception e) {
   1637             loge("Failed to clear addresses or disable ipv6" + e);
   1638         }
   1639 
   1640         /* Reset data structures */
   1641         mWifiInfo.setInetAddress(null);
   1642         mWifiInfo.setBSSID(null);
   1643         mWifiInfo.setSSID(null);
   1644         mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
   1645         mWifiInfo.setRssi(MIN_RSSI);
   1646         mWifiInfo.setLinkSpeed(-1);
   1647         mWifiInfo.setExplicitConnect(false);
   1648 
   1649         /* send event to CM & network change broadcast */
   1650         setNetworkDetailedState(DetailedState.DISCONNECTED);
   1651         sendNetworkStateChangeBroadcast(mLastBssid);
   1652 
   1653         /* Clear network properties */
   1654         mLinkProperties.clear();
   1655         /* Clear IP settings if the network used DHCP */
   1656         if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
   1657             WifiConfigStore.clearIpConfiguration(mLastNetworkId);
   1658         }
   1659 
   1660         mLastBssid= null;
   1661         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
   1662     }
   1663 
   1664     void handlePreDhcpSetup() {
   1665         if (!mBluetoothConnectionActive) {
   1666             /*
   1667              * There are problems setting the Wi-Fi driver's power
   1668              * mode to active when bluetooth coexistence mode is
   1669              * enabled or sense.
   1670              * <p>
   1671              * We set Wi-Fi to active mode when
   1672              * obtaining an IP address because we've found
   1673              * compatibility issues with some routers with low power
   1674              * mode.
   1675              * <p>
   1676              * In order for this active power mode to properly be set,
   1677              * we disable coexistence mode until we're done with
   1678              * obtaining an IP address.  One exception is if we
   1679              * are currently connected to a headset, since disabling
   1680              * coexistence would interrupt that connection.
   1681              */
   1682             // Disable the coexistence mode
   1683             WifiNative.setBluetoothCoexistenceModeCommand(
   1684                     WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
   1685         }
   1686 
   1687         mPowerMode =  WifiNative.getPowerModeCommand();
   1688         if (mPowerMode < 0) {
   1689             // Handle the case where supplicant driver does not support
   1690             // getPowerModeCommand.
   1691             mPowerMode = WifiStateMachine.POWER_MODE_AUTO;
   1692         }
   1693         if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) {
   1694             WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE);
   1695         }
   1696     }
   1697 
   1698 
   1699     void handlePostDhcpSetup() {
   1700         /* restore power mode */
   1701         WifiNative.setPowerModeCommand(mPowerMode);
   1702 
   1703         // Set the coexistence mode back to its default value
   1704         WifiNative.setBluetoothCoexistenceModeCommand(
   1705                 WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
   1706     }
   1707 
   1708     private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
   1709         synchronized (mDhcpInfoInternal) {
   1710             mDhcpInfoInternal = dhcpInfoInternal;
   1711         }
   1712         mLastSignalLevel = -1; // force update of signal strength
   1713         mReconnectCount = 0; //Reset IP failure tracking
   1714         WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
   1715         InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
   1716         mWifiInfo.setInetAddress(addr);
   1717         if (getNetworkDetailedState() == DetailedState.CONNECTED) {
   1718             //DHCP renewal in connected state
   1719             LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
   1720             linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
   1721             linkProperties.setInterfaceName(mInterfaceName);
   1722             if (!linkProperties.equals(mLinkProperties)) {
   1723                 if (DBG) {
   1724                     log("Link configuration changed for netId: " + mLastNetworkId
   1725                             + " old: " + mLinkProperties + "new: " + linkProperties);
   1726                 }
   1727                 mLinkProperties = linkProperties;
   1728                 sendLinkConfigurationChangedBroadcast();
   1729             }
   1730         } else {
   1731             configureLinkProperties();
   1732             setNetworkDetailedState(DetailedState.CONNECTED);
   1733             sendNetworkStateChangeBroadcast(mLastBssid);
   1734         }
   1735     }
   1736 
   1737     private void handleFailedIpConfiguration() {
   1738         loge("IP configuration failed");
   1739 
   1740         mWifiInfo.setInetAddress(null);
   1741         /**
   1742          * If we've exceeded the maximum number of retries for DHCP
   1743          * to a given network, disable the network
   1744          */
   1745         if (++mReconnectCount > getMaxDhcpRetries()) {
   1746             loge("Failed " +
   1747                     mReconnectCount + " times, Disabling " + mLastNetworkId);
   1748             WifiConfigStore.disableNetwork(mLastNetworkId,
   1749                     WifiConfiguration.DISABLED_DHCP_FAILURE);
   1750             mReconnectCount = 0;
   1751         }
   1752 
   1753         /* DHCP times out after about 30 seconds, we do a
   1754          * disconnect and an immediate reconnect to try again
   1755          */
   1756         WifiNative.disconnectCommand();
   1757         WifiNative.reconnectCommand();
   1758     }
   1759 
   1760     /* Current design is to not set the config on a running hostapd but instead
   1761      * stop and start tethering when user changes config on a running access point
   1762      *
   1763      * TODO: Add control channel setup through hostapd that allows changing config
   1764      * on a running daemon
   1765      */
   1766     private void startSoftApWithConfig(final WifiConfiguration config) {
   1767         // start hostapd on a seperate thread
   1768         new Thread(new Runnable() {
   1769             public void run() {
   1770                 try {
   1771                     mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
   1772                 } catch (Exception e) {
   1773                     loge("Exception in softap start " + e);
   1774                     try {
   1775                         mNwService.stopAccessPoint(mInterfaceName);
   1776                         mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
   1777                     } catch (Exception e1) {
   1778                         loge("Exception in softap re-start " + e1);
   1779                         sendMessage(CMD_START_AP_FAILURE);
   1780                         return;
   1781                     }
   1782                 }
   1783                 if (DBG) log("Soft AP start successful");
   1784                 sendMessage(CMD_START_AP_SUCCESS);
   1785             }
   1786         }).start();
   1787     }
   1788 
   1789     /********************************************************
   1790      * HSM states
   1791      *******************************************************/
   1792 
   1793     class DefaultState extends State {
   1794         @Override
   1795         public boolean processMessage(Message message) {
   1796             if (DBG) log(getName() + message.toString() + "\n");
   1797             switch (message.what) {
   1798                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
   1799                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
   1800                         mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
   1801                     } else {
   1802                         loge("WifiP2pService connection failure, error=" + message.arg1);
   1803                     }
   1804                     break;
   1805                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
   1806                     loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
   1807                     //TODO: Re-establish connection to state machine after a delay
   1808                     //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
   1809                     break;
   1810                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
   1811                     mBluetoothConnectionActive = (message.arg1 !=
   1812                             BluetoothAdapter.STATE_DISCONNECTED);
   1813                     break;
   1814                     /* Synchronous call returns */
   1815                 case CMD_PING_SUPPLICANT:
   1816                 case CMD_ENABLE_NETWORK:
   1817                 case CMD_DISABLE_NETWORK:
   1818                 case CMD_ADD_OR_UPDATE_NETWORK:
   1819                 case CMD_REMOVE_NETWORK:
   1820                 case CMD_SAVE_CONFIG:
   1821                     mReplyChannel.replyToMessage(message, message.what, FAILURE);
   1822                     break;
   1823                 case CMD_ENABLE_RSSI_POLL:
   1824                     mEnableRssiPolling = (message.arg1 == 1);
   1825                     break;
   1826                 case CMD_ENABLE_BACKGROUND_SCAN:
   1827                     mEnableBackgroundScan = (message.arg1 == 1);
   1828                     break;
   1829                     /* Discard */
   1830                 case CMD_LOAD_DRIVER:
   1831                 case CMD_UNLOAD_DRIVER:
   1832                 case CMD_START_SUPPLICANT:
   1833                 case CMD_STOP_SUPPLICANT:
   1834                 case CMD_STOP_SUPPLICANT_FAILED:
   1835                 case CMD_START_DRIVER:
   1836                 case CMD_STOP_DRIVER:
   1837                 case CMD_DELAYED_STOP_DRIVER:
   1838                 case CMD_START_AP:
   1839                 case CMD_START_AP_SUCCESS:
   1840                 case CMD_START_AP_FAILURE:
   1841                 case CMD_STOP_AP:
   1842                 case CMD_TETHER_STATE_CHANGE:
   1843                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   1844                 case CMD_START_SCAN:
   1845                 case CMD_DISCONNECT:
   1846                 case CMD_RECONNECT:
   1847                 case CMD_REASSOCIATE:
   1848                 case WifiMonitor.SUP_CONNECTION_EVENT:
   1849                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   1850                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   1851                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   1852                 case WifiMonitor.SCAN_RESULTS_EVENT:
   1853                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   1854                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   1855                 case WifiMonitor.WPS_OVERLAP_EVENT:
   1856                 case CMD_BLACKLIST_NETWORK:
   1857                 case CMD_CLEAR_BLACKLIST:
   1858                 case CMD_SET_SCAN_MODE:
   1859                 case CMD_SET_SCAN_TYPE:
   1860                 case CMD_SET_HIGH_PERF_MODE:
   1861                 case CMD_SET_COUNTRY_CODE:
   1862                 case CMD_SET_FREQUENCY_BAND:
   1863                 case CMD_CONNECT_NETWORK:
   1864                 case CMD_SAVE_NETWORK:
   1865                 case CMD_FORGET_NETWORK:
   1866                 case CMD_RSSI_POLL:
   1867                 case CMD_ENABLE_ALL_NETWORKS:
   1868                 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   1869                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   1870                 /* Handled by WifiApConfigStore */
   1871                 case CMD_SET_AP_CONFIG:
   1872                 case CMD_SET_AP_CONFIG_COMPLETED:
   1873                 case CMD_REQUEST_AP_CONFIG:
   1874                 case CMD_RESPONSE_AP_CONFIG:
   1875                     break;
   1876                 case WifiMonitor.DRIVER_HUNG_EVENT:
   1877                     setWifiEnabled(false);
   1878                     setWifiEnabled(true);
   1879                     break;
   1880                 case CMD_START_WPS:
   1881                     /* Return failure when the state machine cannot handle WPS initiation*/
   1882                     mReplyChannel.replyToMessage(message, WifiManager.CMD_WPS_COMPLETED,
   1883                                 new WpsResult(Status.FAILURE));
   1884                     break;
   1885                 case WifiP2pService.P2P_ENABLE_PENDING:
   1886                     // turn off wifi and defer to be handled in DriverUnloadedState
   1887                     setWifiEnabled(false);
   1888                     deferMessage(message);
   1889                     break;
   1890                 default:
   1891                     loge("Error! unhandled message" + message);
   1892                     break;
   1893             }
   1894             return HANDLED;
   1895         }
   1896     }
   1897 
   1898     class InitialState extends State {
   1899         @Override
   1900         //TODO: could move logging into a common class
   1901         public void enter() {
   1902             if (DBG) log(getName() + "\n");
   1903             // [31-8] Reserved for future use
   1904             // [7 - 0] HSM state change
   1905             // 50021 wifi_state_changed (custom|1|5)
   1906             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   1907 
   1908             if (WifiNative.isDriverLoaded()) {
   1909                 transitionTo(mDriverLoadedState);
   1910             }
   1911             else {
   1912                 transitionTo(mDriverUnloadedState);
   1913             }
   1914 
   1915             //Connect to WifiP2pService
   1916             mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
   1917             mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
   1918 
   1919             /* IPv6 is disabled at boot time and is controlled by framework
   1920              * to be enabled only as long as we are connected to an access point
   1921              *
   1922              * This fixes issues, a few being:
   1923              * - IPv6 addresses and routes stick around after disconnection
   1924              * - When connected, the kernel is unaware and can fail to start IPv6 negotiation
   1925              * - The kernel sometimes starts autoconfiguration when 802.1x is not complete
   1926              */
   1927             try {
   1928                 mNwService.disableIpv6(mInterfaceName);
   1929             } catch (RemoteException re) {
   1930                 loge("Failed to disable IPv6: " + re);
   1931             } catch (IllegalStateException e) {
   1932                 loge("Failed to disable IPv6: " + e);
   1933             }
   1934         }
   1935     }
   1936 
   1937     class DriverLoadingState extends State {
   1938         @Override
   1939         public void enter() {
   1940             if (DBG) log(getName() + "\n");
   1941             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   1942 
   1943             final Message message = new Message();
   1944             message.copyFrom(getCurrentMessage());
   1945             /* TODO: add a timeout to fail when driver load is hung.
   1946              * Similarly for driver unload.
   1947              */
   1948             new Thread(new Runnable() {
   1949                 public void run() {
   1950                     mWakeLock.acquire();
   1951                     //enabling state
   1952                     switch(message.arg1) {
   1953                         case WIFI_STATE_ENABLING:
   1954                             setWifiState(WIFI_STATE_ENABLING);
   1955                             break;
   1956                         case WIFI_AP_STATE_ENABLING:
   1957                             setWifiApState(WIFI_AP_STATE_ENABLING);
   1958                             break;
   1959                     }
   1960 
   1961                     if(WifiNative.loadDriver()) {
   1962                         if (DBG) log("Driver load successful");
   1963                         sendMessage(CMD_LOAD_DRIVER_SUCCESS);
   1964                     } else {
   1965                         loge("Failed to load driver!");
   1966                         switch(message.arg1) {
   1967                             case WIFI_STATE_ENABLING:
   1968                                 setWifiState(WIFI_STATE_UNKNOWN);
   1969                                 break;
   1970                             case WIFI_AP_STATE_ENABLING:
   1971                                 setWifiApState(WIFI_AP_STATE_FAILED);
   1972                                 break;
   1973                         }
   1974                         sendMessage(CMD_LOAD_DRIVER_FAILURE);
   1975                     }
   1976                     mWakeLock.release();
   1977                 }
   1978             }).start();
   1979         }
   1980 
   1981         @Override
   1982         public boolean processMessage(Message message) {
   1983             if (DBG) log(getName() + message.toString() + "\n");
   1984             switch (message.what) {
   1985                 case CMD_LOAD_DRIVER_SUCCESS:
   1986                     transitionTo(mDriverLoadedState);
   1987                     break;
   1988                 case CMD_LOAD_DRIVER_FAILURE:
   1989                     transitionTo(mDriverFailedState);
   1990                     break;
   1991                 case CMD_LOAD_DRIVER:
   1992                 case CMD_UNLOAD_DRIVER:
   1993                 case CMD_START_SUPPLICANT:
   1994                 case CMD_STOP_SUPPLICANT:
   1995                 case CMD_START_AP:
   1996                 case CMD_STOP_AP:
   1997                 case CMD_START_DRIVER:
   1998                 case CMD_STOP_DRIVER:
   1999                 case CMD_SET_SCAN_MODE:
   2000                 case CMD_SET_SCAN_TYPE:
   2001                 case CMD_SET_HIGH_PERF_MODE:
   2002                 case CMD_SET_COUNTRY_CODE:
   2003                 case CMD_SET_FREQUENCY_BAND:
   2004                 case CMD_START_PACKET_FILTERING:
   2005                 case CMD_STOP_PACKET_FILTERING:
   2006                     deferMessage(message);
   2007                     break;
   2008                 default:
   2009                     return NOT_HANDLED;
   2010             }
   2011             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2012             return HANDLED;
   2013         }
   2014     }
   2015 
   2016     class DriverLoadedState extends State {
   2017         @Override
   2018         public void enter() {
   2019             if (DBG) log(getName() + "\n");
   2020             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2021         }
   2022         @Override
   2023         public boolean processMessage(Message message) {
   2024             if (DBG) log(getName() + message.toString() + "\n");
   2025             switch(message.what) {
   2026                 case CMD_UNLOAD_DRIVER:
   2027                     transitionTo(mDriverUnloadingState);
   2028                     break;
   2029                 case CMD_START_SUPPLICANT:
   2030                     try {
   2031                         mNwService.wifiFirmwareReload(mInterfaceName, "STA");
   2032                     } catch (Exception e) {
   2033                         loge("Failed to reload STA firmware " + e);
   2034                         // continue
   2035                     }
   2036                    try {
   2037                        //A runtime crash can leave the interface up and
   2038                        //this affects connectivity when supplicant starts up.
   2039                        //Ensure interface is down before a supplicant start.
   2040                         mNwService.setInterfaceDown(mInterfaceName);
   2041                         //Set privacy extensions
   2042                         mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
   2043                     } catch (RemoteException re) {
   2044                         loge("Unable to change interface settings: " + re);
   2045                     } catch (IllegalStateException ie) {
   2046                         loge("Unable to change interface settings: " + ie);
   2047                     }
   2048 
   2049                     if(WifiNative.startSupplicant()) {
   2050                         if (DBG) log("Supplicant start successful");
   2051                         mWifiMonitor.startMonitoring();
   2052                         transitionTo(mSupplicantStartingState);
   2053                     } else {
   2054                         loge("Failed to start supplicant!");
   2055                         sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
   2056                     }
   2057                     break;
   2058                 case CMD_START_AP:
   2059                     transitionTo(mSoftApStartingState);
   2060                     break;
   2061                 default:
   2062                     return NOT_HANDLED;
   2063             }
   2064             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2065             return HANDLED;
   2066         }
   2067     }
   2068 
   2069     class DriverUnloadingState extends State {
   2070         @Override
   2071         public void enter() {
   2072             if (DBG) log(getName() + "\n");
   2073             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2074 
   2075             final Message message = new Message();
   2076             message.copyFrom(getCurrentMessage());
   2077             new Thread(new Runnable() {
   2078                 public void run() {
   2079                     if (DBG) log(getName() + message.toString() + "\n");
   2080                     mWakeLock.acquire();
   2081                     if(WifiNative.unloadDriver()) {
   2082                         if (DBG) log("Driver unload successful");
   2083                         sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
   2084 
   2085                         switch(message.arg1) {
   2086                             case WIFI_STATE_DISABLED:
   2087                             case WIFI_STATE_UNKNOWN:
   2088                                 setWifiState(message.arg1);
   2089                                 break;
   2090                             case WIFI_AP_STATE_DISABLED:
   2091                             case WIFI_AP_STATE_FAILED:
   2092                                 setWifiApState(message.arg1);
   2093                                 break;
   2094                         }
   2095                     } else {
   2096                         loge("Failed to unload driver!");
   2097                         sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
   2098 
   2099                         switch(message.arg1) {
   2100                             case WIFI_STATE_DISABLED:
   2101                             case WIFI_STATE_UNKNOWN:
   2102                                 setWifiState(WIFI_STATE_UNKNOWN);
   2103                                 break;
   2104                             case WIFI_AP_STATE_DISABLED:
   2105                             case WIFI_AP_STATE_FAILED:
   2106                                 setWifiApState(WIFI_AP_STATE_FAILED);
   2107                                 break;
   2108                         }
   2109                     }
   2110                     mWakeLock.release();
   2111                 }
   2112             }).start();
   2113         }
   2114 
   2115         @Override
   2116         public boolean processMessage(Message message) {
   2117             if (DBG) log(getName() + message.toString() + "\n");
   2118             switch (message.what) {
   2119                 case CMD_UNLOAD_DRIVER_SUCCESS:
   2120                     transitionTo(mDriverUnloadedState);
   2121                     break;
   2122                 case CMD_UNLOAD_DRIVER_FAILURE:
   2123                     transitionTo(mDriverFailedState);
   2124                     break;
   2125                 case CMD_LOAD_DRIVER:
   2126                 case CMD_UNLOAD_DRIVER:
   2127                 case CMD_START_SUPPLICANT:
   2128                 case CMD_STOP_SUPPLICANT:
   2129                 case CMD_START_AP:
   2130                 case CMD_STOP_AP:
   2131                 case CMD_START_DRIVER:
   2132                 case CMD_STOP_DRIVER:
   2133                 case CMD_SET_SCAN_MODE:
   2134                 case CMD_SET_SCAN_TYPE:
   2135                 case CMD_SET_HIGH_PERF_MODE:
   2136                 case CMD_SET_COUNTRY_CODE:
   2137                 case CMD_SET_FREQUENCY_BAND:
   2138                 case CMD_START_PACKET_FILTERING:
   2139                 case CMD_STOP_PACKET_FILTERING:
   2140                     deferMessage(message);
   2141                     break;
   2142                 default:
   2143                     return NOT_HANDLED;
   2144             }
   2145             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2146             return HANDLED;
   2147         }
   2148     }
   2149 
   2150     class DriverUnloadedState extends State {
   2151         @Override
   2152         public void enter() {
   2153             if (DBG) log(getName() + "\n");
   2154             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2155         }
   2156         @Override
   2157         public boolean processMessage(Message message) {
   2158             if (DBG) log(getName() + message.toString() + "\n");
   2159             switch (message.what) {
   2160                 case CMD_LOAD_DRIVER:
   2161                     mWifiP2pChannel.sendMessage(WIFI_ENABLE_PENDING);
   2162                     transitionTo(mWaitForP2pDisableState);
   2163                     break;
   2164                 case WifiP2pService.P2P_ENABLE_PENDING:
   2165                     mReplyChannel.replyToMessage(message, P2P_ENABLE_PROCEED);
   2166                     break;
   2167                 default:
   2168                     return NOT_HANDLED;
   2169             }
   2170             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2171             return HANDLED;
   2172         }
   2173     }
   2174 
   2175     class DriverFailedState extends State {
   2176         @Override
   2177         public void enter() {
   2178             loge(getName() + "\n");
   2179             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2180         }
   2181         @Override
   2182         public boolean processMessage(Message message) {
   2183             if (DBG) log(getName() + message.toString() + "\n");
   2184             return NOT_HANDLED;
   2185         }
   2186     }
   2187 
   2188 
   2189     class SupplicantStartingState extends State {
   2190         @Override
   2191         public void enter() {
   2192             if (DBG) log(getName() + "\n");
   2193             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2194         }
   2195         @Override
   2196         public boolean processMessage(Message message) {
   2197             if (DBG) log(getName() + message.toString() + "\n");
   2198             switch(message.what) {
   2199                 case WifiMonitor.SUP_CONNECTION_EVENT:
   2200                     if (DBG) log("Supplicant connection established");
   2201                     setWifiState(WIFI_STATE_ENABLED);
   2202                     mSupplicantRestartCount = 0;
   2203                     /* Reset the supplicant state to indicate the supplicant
   2204                      * state is not known at this time */
   2205                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
   2206                     mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
   2207                     /* Initialize data structures */
   2208                     mLastBssid = null;
   2209                     mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
   2210                     mLastSignalLevel = -1;
   2211 
   2212                     mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
   2213 
   2214                     WifiConfigStore.initialize(mContext);
   2215 
   2216                     sendSupplicantConnectionChangedBroadcast(true);
   2217                     transitionTo(mDriverStartedState);
   2218                     break;
   2219                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   2220                     if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
   2221                         loge("Failed to setup control channel, restart supplicant");
   2222                         WifiNative.killSupplicant();
   2223                         transitionTo(mDriverLoadedState);
   2224                         sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
   2225                     } else {
   2226                         loge("Failed " + mSupplicantRestartCount +
   2227                                 " times to start supplicant, unload driver");
   2228                         mSupplicantRestartCount = 0;
   2229                         transitionTo(mDriverLoadedState);
   2230                         sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
   2231                     }
   2232                     break;
   2233                 case CMD_LOAD_DRIVER:
   2234                 case CMD_UNLOAD_DRIVER:
   2235                 case CMD_START_SUPPLICANT:
   2236                 case CMD_STOP_SUPPLICANT:
   2237                 case CMD_START_AP:
   2238                 case CMD_STOP_AP:
   2239                 case CMD_START_DRIVER:
   2240                 case CMD_STOP_DRIVER:
   2241                 case CMD_SET_SCAN_MODE:
   2242                 case CMD_SET_SCAN_TYPE:
   2243                 case CMD_SET_HIGH_PERF_MODE:
   2244                 case CMD_SET_COUNTRY_CODE:
   2245                 case CMD_SET_FREQUENCY_BAND:
   2246                 case CMD_START_PACKET_FILTERING:
   2247                 case CMD_STOP_PACKET_FILTERING:
   2248                     deferMessage(message);
   2249                     break;
   2250                 default:
   2251                     return NOT_HANDLED;
   2252             }
   2253             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2254             return HANDLED;
   2255         }
   2256     }
   2257 
   2258     class SupplicantStartedState extends State {
   2259         @Override
   2260         public void enter() {
   2261             if (DBG) log(getName() + "\n");
   2262             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2263             /* Initialize for connect mode operation at start */
   2264             mIsScanMode = false;
   2265             /* Wifi is available as long as we have a connection to supplicant */
   2266             mNetworkInfo.setIsAvailable(true);
   2267             /* Set scan interval */
   2268             long supplicantScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
   2269                     Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
   2270                     mDefaultSupplicantScanIntervalMs);
   2271             WifiNative.setScanIntervalCommand((int)supplicantScanIntervalMs / 1000);
   2272         }
   2273         @Override
   2274         public boolean processMessage(Message message) {
   2275             if (DBG) log(getName() + message.toString() + "\n");
   2276             WifiConfiguration config;
   2277             boolean eventLoggingEnabled = true;
   2278             switch(message.what) {
   2279                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
   2280                     transitionTo(mSupplicantStoppingState);
   2281                     break;
   2282                 case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
   2283                     loge("Connection lost, restart supplicant");
   2284                     WifiNative.killSupplicant();
   2285                     WifiNative.closeSupplicantConnection();
   2286                     mNetworkInfo.setIsAvailable(false);
   2287                     handleNetworkDisconnect();
   2288                     sendSupplicantConnectionChangedBroadcast(false);
   2289                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
   2290                     mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
   2291                     transitionTo(mDriverLoadedState);
   2292                     sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
   2293                     break;
   2294                 case WifiMonitor.SCAN_RESULTS_EVENT:
   2295                     eventLoggingEnabled = false;
   2296                     setScanResults(WifiNative.scanResultsCommand());
   2297                     sendScanResultsAvailableBroadcast();
   2298                     mScanResultIsPending = false;
   2299                     break;
   2300                 case CMD_PING_SUPPLICANT:
   2301                     boolean ok = WifiNative.pingCommand();
   2302                     mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
   2303                     break;
   2304                 case CMD_ADD_OR_UPDATE_NETWORK:
   2305                     config = (WifiConfiguration) message.obj;
   2306                     mReplyChannel.replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
   2307                             WifiConfigStore.addOrUpdateNetwork(config));
   2308                     break;
   2309                 case CMD_REMOVE_NETWORK:
   2310                     ok = WifiConfigStore.removeNetwork(message.arg1);
   2311                     mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
   2312                     break;
   2313                 case CMD_ENABLE_NETWORK:
   2314                     ok = WifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
   2315                     mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
   2316                     break;
   2317                 case CMD_ENABLE_ALL_NETWORKS:
   2318                     long time =  android.os.SystemClock.elapsedRealtime();
   2319                     if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
   2320                         WifiConfigStore.enableAllNetworks();
   2321                         mLastEnableAllNetworksTime = time;
   2322                     }
   2323                     break;
   2324                 case CMD_DISABLE_NETWORK:
   2325                     ok = WifiConfigStore.disableNetwork(message.arg1, message.arg2);
   2326                     mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
   2327                     break;
   2328                 case CMD_BLACKLIST_NETWORK:
   2329                     WifiNative.addToBlacklistCommand((String)message.obj);
   2330                     break;
   2331                 case CMD_CLEAR_BLACKLIST:
   2332                     WifiNative.clearBlacklistCommand();
   2333                     break;
   2334                 case CMD_SAVE_CONFIG:
   2335                     ok = WifiConfigStore.saveConfig();
   2336                     mReplyChannel.replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
   2337 
   2338                     // Inform the backup manager about a data change
   2339                     IBackupManager ibm = IBackupManager.Stub.asInterface(
   2340                             ServiceManager.getService(Context.BACKUP_SERVICE));
   2341                     if (ibm != null) {
   2342                         try {
   2343                             ibm.dataChanged("com.android.providers.settings");
   2344                         } catch (Exception e) {
   2345                             // Try again later
   2346                         }
   2347                     }
   2348                     break;
   2349                     /* Cannot start soft AP while in client mode */
   2350                 case CMD_START_AP:
   2351                     loge("Failed to start soft AP with a running supplicant");
   2352                     setWifiApState(WIFI_AP_STATE_FAILED);
   2353                     break;
   2354                 case CMD_SET_SCAN_MODE:
   2355                     mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
   2356                     break;
   2357                 case CMD_SAVE_NETWORK:
   2358                     config = (WifiConfiguration) message.obj;
   2359                     WifiConfigStore.saveNetwork(config);
   2360                     break;
   2361                 case CMD_FORGET_NETWORK:
   2362                     WifiConfigStore.forgetNetwork(message.arg1);
   2363                     break;
   2364                 default:
   2365                     return NOT_HANDLED;
   2366             }
   2367             if (eventLoggingEnabled) {
   2368                 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2369             }
   2370             return HANDLED;
   2371         }
   2372 
   2373         @Override
   2374         public void exit() {
   2375             mNetworkInfo.setIsAvailable(false);
   2376         }
   2377     }
   2378 
   2379     class SupplicantStoppingState extends State {
   2380         @Override
   2381         public void enter() {
   2382             if (DBG) log(getName() + "\n");
   2383             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2384             if (DBG) log("stopping supplicant");
   2385             if (!WifiNative.stopSupplicant()) {
   2386                 loge("Failed to stop supplicant");
   2387             }
   2388 
   2389             /* Send ourselves a delayed message to indicate failure after a wait time */
   2390             sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
   2391                     ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
   2392 
   2393             mNetworkInfo.setIsAvailable(false);
   2394             handleNetworkDisconnect();
   2395             setWifiState(WIFI_STATE_DISABLING);
   2396             sendSupplicantConnectionChangedBroadcast(false);
   2397             mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
   2398             mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
   2399         }
   2400         @Override
   2401         public boolean processMessage(Message message) {
   2402             if (DBG) log(getName() + message.toString() + "\n");
   2403             switch(message.what) {
   2404                 case WifiMonitor.SUP_CONNECTION_EVENT:
   2405                     loge("Supplicant connection received while stopping");
   2406                     break;
   2407                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   2408                     if (DBG) log("Supplicant connection lost");
   2409                     /* Socket connection can be lost when we do a graceful shutdown
   2410                      * or when the driver is hung. Ensure supplicant is stopped here.
   2411                      */
   2412                     WifiNative.killSupplicant();
   2413                     WifiNative.closeSupplicantConnection();
   2414                     transitionTo(mDriverLoadedState);
   2415                     break;
   2416                 case CMD_STOP_SUPPLICANT_FAILED:
   2417                     if (message.arg1 == mSupplicantStopFailureToken) {
   2418                         loge("Timed out on a supplicant stop, kill and proceed");
   2419                         WifiNative.killSupplicant();
   2420                         WifiNative.closeSupplicantConnection();
   2421                         transitionTo(mDriverLoadedState);
   2422                     }
   2423                     break;
   2424                 case CMD_LOAD_DRIVER:
   2425                 case CMD_UNLOAD_DRIVER:
   2426                 case CMD_START_SUPPLICANT:
   2427                 case CMD_STOP_SUPPLICANT:
   2428                 case CMD_START_AP:
   2429                 case CMD_STOP_AP:
   2430                 case CMD_START_DRIVER:
   2431                 case CMD_STOP_DRIVER:
   2432                 case CMD_SET_SCAN_MODE:
   2433                 case CMD_SET_SCAN_TYPE:
   2434                 case CMD_SET_HIGH_PERF_MODE:
   2435                 case CMD_SET_COUNTRY_CODE:
   2436                 case CMD_SET_FREQUENCY_BAND:
   2437                 case CMD_START_PACKET_FILTERING:
   2438                 case CMD_STOP_PACKET_FILTERING:
   2439                     deferMessage(message);
   2440                     break;
   2441                 default:
   2442                     return NOT_HANDLED;
   2443             }
   2444             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2445             return HANDLED;
   2446         }
   2447     }
   2448 
   2449     class DriverStartingState extends State {
   2450         @Override
   2451         public void enter() {
   2452             if (DBG) log(getName() + "\n");
   2453             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2454         }
   2455         @Override
   2456         public boolean processMessage(Message message) {
   2457             if (DBG) log(getName() + message.toString() + "\n");
   2458             switch(message.what) {
   2459                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   2460                     SupplicantState state = handleSupplicantStateChange(message);
   2461                     /* If suplicant is exiting out of INTERFACE_DISABLED state into
   2462                      * a state that indicates driver has started, it is ready to
   2463                      * receive driver commands
   2464                      */
   2465                     if (SupplicantState.isDriverActive(state)) {
   2466                         transitionTo(mDriverStartedState);
   2467                     }
   2468                     break;
   2469                     /* Queue driver commands & connection events */
   2470                 case CMD_START_DRIVER:
   2471                 case CMD_STOP_DRIVER:
   2472                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   2473                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   2474                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   2475                 case WifiMonitor.WPS_OVERLAP_EVENT:
   2476                 case CMD_SET_SCAN_TYPE:
   2477                 case CMD_SET_HIGH_PERF_MODE:
   2478                 case CMD_SET_COUNTRY_CODE:
   2479                 case CMD_SET_FREQUENCY_BAND:
   2480                 case CMD_START_PACKET_FILTERING:
   2481                 case CMD_STOP_PACKET_FILTERING:
   2482                 case CMD_START_SCAN:
   2483                 case CMD_DISCONNECT:
   2484                 case CMD_REASSOCIATE:
   2485                 case CMD_RECONNECT:
   2486                     deferMessage(message);
   2487                     break;
   2488                 default:
   2489                     return NOT_HANDLED;
   2490             }
   2491             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2492             return HANDLED;
   2493         }
   2494     }
   2495 
   2496     class DriverStartedState extends State {
   2497         @Override
   2498         public void enter() {
   2499             if (DBG) log(getName() + "\n");
   2500             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2501 
   2502             mIsRunning = true;
   2503             mInDelayedStop = false;
   2504             updateBatteryWorkSource(null);
   2505 
   2506             /**
   2507              * Enable bluetooth coexistence scan mode when bluetooth connection is active.
   2508              * When this mode is on, some of the low-level scan parameters used by the
   2509              * driver are changed to reduce interference with bluetooth
   2510              */
   2511             WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
   2512             /* set country code */
   2513             setCountryCode();
   2514             /* set frequency band of operation */
   2515             setFrequencyBand();
   2516             /* initialize network state */
   2517             setNetworkDetailedState(DetailedState.DISCONNECTED);
   2518 
   2519             /* Remove any filtering on Multicast v6 at start */
   2520             WifiNative.stopFilteringMulticastV6Packets();
   2521 
   2522             /* Reset Multicast v4 filtering state */
   2523             if (mFilteringMulticastV4Packets.get()) {
   2524                 WifiNative.startFilteringMulticastV4Packets();
   2525             } else {
   2526                 WifiNative.stopFilteringMulticastV4Packets();
   2527             }
   2528 
   2529             if (mIsScanMode) {
   2530                 WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
   2531                 WifiNative.disconnectCommand();
   2532                 transitionTo(mScanModeState);
   2533             } else {
   2534                 WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
   2535                 WifiNative.reconnectCommand();
   2536                 transitionTo(mDisconnectedState);
   2537             }
   2538         }
   2539         @Override
   2540         public boolean processMessage(Message message) {
   2541             if (DBG) log(getName() + message.toString() + "\n");
   2542             boolean eventLoggingEnabled = true;
   2543             switch(message.what) {
   2544                 case CMD_SET_SCAN_TYPE:
   2545                     if (message.arg1 == SCAN_ACTIVE) {
   2546                         WifiNative.setScanModeCommand(true);
   2547                     } else {
   2548                         WifiNative.setScanModeCommand(false);
   2549                     }
   2550                     break;
   2551                 case CMD_START_SCAN:
   2552                     eventLoggingEnabled = false;
   2553                     WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
   2554                     mScanResultIsPending = true;
   2555                     break;
   2556                 case CMD_SET_HIGH_PERF_MODE:
   2557                     setHighPerfModeEnabledNative(message.arg1 == 1);
   2558                     break;
   2559                 case CMD_SET_COUNTRY_CODE:
   2560                     String country = (String) message.obj;
   2561                     if (DBG) log("set country code " + country);
   2562                     if (!WifiNative.setCountryCodeCommand(country.toUpperCase())) {
   2563                         loge("Failed to set country code " + country);
   2564                     }
   2565                     break;
   2566                 case CMD_SET_FREQUENCY_BAND:
   2567                     int band =  message.arg1;
   2568                     if (DBG) log("set frequency band " + band);
   2569                     if (WifiNative.setBandCommand(band)) {
   2570                         mFrequencyBand.set(band);
   2571                         //Fetch the latest scan results when frequency band is set
   2572                         startScan(true);
   2573                     } else {
   2574                         loge("Failed to set frequency band " + band);
   2575                     }
   2576                     break;
   2577                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
   2578                     mBluetoothConnectionActive = (message.arg1 !=
   2579                             BluetoothAdapter.STATE_DISCONNECTED);
   2580                     WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
   2581                     break;
   2582                 case CMD_STOP_DRIVER:
   2583                     int mode = message.arg1;
   2584 
   2585                     /* Already doing a delayed stop && not in ecm state */
   2586                     if (mInDelayedStop && mode != IN_ECM_STATE) {
   2587                         if (DBG) log("Already in delayed stop");
   2588                         break;
   2589                     }
   2590                     mInDelayedStop = true;
   2591                     mDelayedStopCounter++;
   2592                     if (DBG) log("Delayed stop message " + mDelayedStopCounter);
   2593 
   2594                     if (mode == IN_ECM_STATE) {
   2595                         /* send a shut down immediately */
   2596                         sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0));
   2597                     } else {
   2598                         /* send regular delayed shut down */
   2599                         sendMessageDelayed(obtainMessage(CMD_DELAYED_STOP_DRIVER,
   2600                                 mDelayedStopCounter, 0), DELAYED_DRIVER_STOP_MS);
   2601                     }
   2602                     break;
   2603                 case CMD_START_DRIVER:
   2604                     if (mInDelayedStop) {
   2605                         mInDelayedStop = false;
   2606                         mDelayedStopCounter++;
   2607                         if (DBG) log("Delayed stop ignored due to start");
   2608                     }
   2609                     break;
   2610                 case CMD_DELAYED_STOP_DRIVER:
   2611                     if (message.arg1 != mDelayedStopCounter) break;
   2612                     if (getCurrentState() != mDisconnectedState) {
   2613                         WifiNative.disconnectCommand();
   2614                         handleNetworkDisconnect();
   2615                     }
   2616                     mWakeLock.acquire();
   2617                     WifiNative.stopDriverCommand();
   2618                     transitionTo(mDriverStoppingState);
   2619                     mWakeLock.release();
   2620                     break;
   2621                 case CMD_START_PACKET_FILTERING:
   2622                     if (message.arg1 == MULTICAST_V6) {
   2623                         WifiNative.startFilteringMulticastV6Packets();
   2624                     } else if (message.arg1 == MULTICAST_V4) {
   2625                         WifiNative.startFilteringMulticastV4Packets();
   2626                     } else {
   2627                         loge("Illegal arugments to CMD_START_PACKET_FILTERING");
   2628                     }
   2629                     break;
   2630                 case CMD_STOP_PACKET_FILTERING:
   2631                     if (message.arg1 == MULTICAST_V6) {
   2632                         WifiNative.stopFilteringMulticastV6Packets();
   2633                     } else if (message.arg1 == MULTICAST_V4) {
   2634                         WifiNative.stopFilteringMulticastV4Packets();
   2635                     } else {
   2636                         loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
   2637                     }
   2638                     break;
   2639                 default:
   2640                     return NOT_HANDLED;
   2641             }
   2642             if (eventLoggingEnabled) {
   2643                 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2644             }
   2645             return HANDLED;
   2646         }
   2647         @Override
   2648         public void exit() {
   2649             if (DBG) log(getName() + "\n");
   2650             mIsRunning = false;
   2651             updateBatteryWorkSource(null);
   2652             mScanResults = null;
   2653         }
   2654     }
   2655 
   2656     class DriverStoppingState extends State {
   2657         @Override
   2658         public void enter() {
   2659             if (DBG) log(getName() + "\n");
   2660             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2661         }
   2662         @Override
   2663         public boolean processMessage(Message message) {
   2664             if (DBG) log(getName() + message.toString() + "\n");
   2665             switch(message.what) {
   2666                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   2667                     SupplicantState state = handleSupplicantStateChange(message);
   2668                     if (state == SupplicantState.INTERFACE_DISABLED) {
   2669                         transitionTo(mDriverStoppedState);
   2670                     }
   2671                     break;
   2672                     /* Queue driver commands */
   2673                 case CMD_START_DRIVER:
   2674                 case CMD_STOP_DRIVER:
   2675                 case CMD_SET_SCAN_TYPE:
   2676                 case CMD_SET_HIGH_PERF_MODE:
   2677                 case CMD_SET_COUNTRY_CODE:
   2678                 case CMD_SET_FREQUENCY_BAND:
   2679                 case CMD_START_PACKET_FILTERING:
   2680                 case CMD_STOP_PACKET_FILTERING:
   2681                 case CMD_START_SCAN:
   2682                 case CMD_DISCONNECT:
   2683                 case CMD_REASSOCIATE:
   2684                 case CMD_RECONNECT:
   2685                     deferMessage(message);
   2686                     break;
   2687                 default:
   2688                     return NOT_HANDLED;
   2689             }
   2690             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2691             return HANDLED;
   2692         }
   2693     }
   2694 
   2695     class DriverStoppedState extends State {
   2696         @Override
   2697         public void enter() {
   2698             if (DBG) log(getName() + "\n");
   2699             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2700         }
   2701         @Override
   2702         public boolean processMessage(Message message) {
   2703             if (DBG) log(getName() + message.toString() + "\n");
   2704             switch (message.what) {
   2705                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   2706                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   2707                     SupplicantState state = stateChangeResult.state;
   2708                     // A WEXT bug means that we can be back to driver started state
   2709                     // unexpectedly
   2710                     if (SupplicantState.isDriverActive(state)) {
   2711                         transitionTo(mDriverStartedState);
   2712                     }
   2713                     break;
   2714                 case CMD_START_DRIVER:
   2715                     mWakeLock.acquire();
   2716                     WifiNative.startDriverCommand();
   2717                     mWakeLock.release();
   2718                     transitionTo(mDriverStartingState);
   2719                     break;
   2720                 default:
   2721                     return NOT_HANDLED;
   2722             }
   2723             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2724             return HANDLED;
   2725         }
   2726     }
   2727 
   2728     class ScanModeState extends State {
   2729         @Override
   2730         public void enter() {
   2731             if (DBG) log(getName() + "\n");
   2732             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2733         }
   2734         @Override
   2735         public boolean processMessage(Message message) {
   2736             if (DBG) log(getName() + message.toString() + "\n");
   2737             switch(message.what) {
   2738                 case CMD_SET_SCAN_MODE:
   2739                     if (message.arg1 == SCAN_ONLY_MODE) {
   2740                         /* Ignore */
   2741                         return HANDLED;
   2742                     } else {
   2743                         WifiNative.setScanResultHandlingCommand(message.arg1);
   2744                         WifiNative.reconnectCommand();
   2745                         mIsScanMode = false;
   2746                         transitionTo(mDisconnectedState);
   2747                     }
   2748                     break;
   2749                     /* Ignore */
   2750                 case CMD_DISCONNECT:
   2751                 case CMD_RECONNECT:
   2752                 case CMD_REASSOCIATE:
   2753                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   2754                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   2755                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   2756                     break;
   2757                 default:
   2758                     return NOT_HANDLED;
   2759             }
   2760             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2761             return HANDLED;
   2762         }
   2763     }
   2764 
   2765     class ConnectModeState extends State {
   2766         @Override
   2767         public void enter() {
   2768             if (DBG) log(getName() + "\n");
   2769             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2770         }
   2771         @Override
   2772         public boolean processMessage(Message message) {
   2773             if (DBG) log(getName() + message.toString() + "\n");
   2774             StateChangeResult stateChangeResult;
   2775             switch(message.what) {
   2776                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   2777                     mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
   2778                     break;
   2779                 case WifiMonitor.WPS_OVERLAP_EVENT:
   2780                     /* We just need to broadcast the error */
   2781                     sendErrorBroadcast(WifiManager.WPS_OVERLAP_ERROR);
   2782                     break;
   2783                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   2784                     SupplicantState state = handleSupplicantStateChange(message);
   2785                     // Due to a WEXT bug, during the time of driver start/stop
   2786                     // we can go into a driver stopped state in an unexpected way.
   2787                     // The sequence eventually puts interface
   2788                     // up and we should be back to a connected state
   2789                     if (!SupplicantState.isDriverActive(state)) {
   2790                         if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
   2791                             handleNetworkDisconnect();
   2792                         }
   2793                         transitionTo(mDriverStoppedState);
   2794                         break;
   2795                     }
   2796 
   2797                     // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
   2798                     // when authentication times out after a successful connection,
   2799                     // we can figure this from the supplicant state. If supplicant
   2800                     // state is DISCONNECTED, but the mNetworkInfo says we are not
   2801                     // disconnected, we need to handle a disconnection
   2802                     if (state == SupplicantState.DISCONNECTED &&
   2803                             mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
   2804                         if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
   2805                         handleNetworkDisconnect();
   2806                         transitionTo(mDisconnectedState);
   2807                     }
   2808                     break;
   2809                     /* Do a redundant disconnect without transition */
   2810                 case CMD_DISCONNECT:
   2811                     WifiNative.disconnectCommand();
   2812                     break;
   2813                 case CMD_RECONNECT:
   2814                     WifiNative.reconnectCommand();
   2815                     break;
   2816                 case CMD_REASSOCIATE:
   2817                     WifiNative.reassociateCommand();
   2818                     break;
   2819                 case CMD_CONNECT_NETWORK:
   2820                     int netId = message.arg1;
   2821                     WifiConfiguration config = (WifiConfiguration) message.obj;
   2822 
   2823                     /* We connect to a specific network by issuing a select
   2824                      * to the WifiConfigStore. This enables the network,
   2825                      * while disabling all other networks in the supplicant.
   2826                      * Disabling a connected network will cause a disconnection
   2827                      * from the network. A reconnectCommand() will then initiate
   2828                      * a connection to the enabled network.
   2829                      */
   2830                     if (config != null) {
   2831                         netId = WifiConfigStore.selectNetwork(config);
   2832                     } else {
   2833                         WifiConfigStore.selectNetwork(netId);
   2834                     }
   2835 
   2836                     /* The state tracker handles enabling networks upon completion/failure */
   2837                     mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);
   2838 
   2839                     WifiNative.reconnectCommand();
   2840                     mLastExplicitNetworkId = netId;
   2841                     mLastNetworkChoiceTime  = SystemClock.elapsedRealtime();
   2842                     mNextWifiActionExplicit = true;
   2843                     if (DBG) log("Setting wifi connect explicit for netid " + netId);
   2844                     /* Expect a disconnection from the old connection */
   2845                     transitionTo(mDisconnectingState);
   2846                     break;
   2847                 case CMD_START_WPS:
   2848                     mWpsStateMachine.sendMessage(Message.obtain(message));
   2849                     transitionTo(mWaitForWpsCompletionState);
   2850                     break;
   2851                 case WifiMonitor.SCAN_RESULTS_EVENT:
   2852                     /* Set the scan setting back to "connect" mode */
   2853                     WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
   2854                     /* Handle scan results */
   2855                     return NOT_HANDLED;
   2856                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   2857                     if (DBG) log("Network connection established");
   2858                     mLastNetworkId = message.arg1;
   2859                     mLastBssid = (String) message.obj;
   2860 
   2861                     //TODO: make supplicant modification to push this in events
   2862                     mWifiInfo.setSSID(fetchSSID());
   2863                     mWifiInfo.setBSSID(mLastBssid);
   2864                     mWifiInfo.setNetworkId(mLastNetworkId);
   2865                     if (mNextWifiActionExplicit &&
   2866                         mWifiInfo.getNetworkId() == mLastExplicitNetworkId &&
   2867                         SystemClock.elapsedRealtime() < mLastNetworkChoiceTime +
   2868                                                             EXPLICIT_CONNECT_ALLOWED_DELAY_MS) {
   2869                         mWifiInfo.setExplicitConnect(true);
   2870                     }
   2871                     mNextWifiActionExplicit = false;
   2872                     /* send event to CM & network change broadcast */
   2873                     setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
   2874                     sendNetworkStateChangeBroadcast(mLastBssid);
   2875                     transitionTo(mConnectingState);
   2876                     break;
   2877                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   2878                     if (DBG) log("Network connection lost");
   2879                     handleNetworkDisconnect();
   2880                     transitionTo(mDisconnectedState);
   2881                     break;
   2882                 default:
   2883                     return NOT_HANDLED;
   2884             }
   2885             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2886             return HANDLED;
   2887         }
   2888     }
   2889 
   2890     class ConnectingState extends State {
   2891 
   2892         @Override
   2893         public void enter() {
   2894             if (DBG) log(getName() + "\n");
   2895             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   2896 
   2897             try {
   2898                 mNwService.enableIpv6(mInterfaceName);
   2899             } catch (RemoteException re) {
   2900                 loge("Failed to enable IPv6: " + re);
   2901             } catch (IllegalStateException e) {
   2902                 loge("Failed to enable IPv6: " + e);
   2903             }
   2904 
   2905             if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
   2906                 //start DHCP
   2907                 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
   2908                         mContext, WifiStateMachine.this, mInterfaceName);
   2909                 mDhcpStateMachine.registerForPreDhcpNotification();
   2910                 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
   2911             } else {
   2912                 DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
   2913                         mLastNetworkId);
   2914                 InterfaceConfiguration ifcg = new InterfaceConfiguration();
   2915                 ifcg.addr = dhcpInfoInternal.makeLinkAddress();
   2916                 ifcg.interfaceFlags = "[up]";
   2917                 try {
   2918                     mNwService.setInterfaceConfig(mInterfaceName, ifcg);
   2919                     if (DBG) log("Static IP configuration succeeded");
   2920                     sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
   2921                 } catch (RemoteException re) {
   2922                     loge("Static IP configuration failed: " + re);
   2923                     sendMessage(CMD_STATIC_IP_FAILURE);
   2924                 } catch (IllegalStateException e) {
   2925                     loge("Static IP configuration failed: " + e);
   2926                     sendMessage(CMD_STATIC_IP_FAILURE);
   2927                 }
   2928             }
   2929         }
   2930       @Override
   2931       public boolean processMessage(Message message) {
   2932           if (DBG) log(getName() + message.toString() + "\n");
   2933 
   2934           switch(message.what) {
   2935               case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   2936                   handlePreDhcpSetup();
   2937                   mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
   2938                   break;
   2939               case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   2940                   handlePostDhcpSetup();
   2941                   if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
   2942                       handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
   2943                       transitionTo(mConnectedState);
   2944                   } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
   2945                       handleFailedIpConfiguration();
   2946                       transitionTo(mDisconnectingState);
   2947                   }
   2948                   break;
   2949               case CMD_STATIC_IP_SUCCESS:
   2950                   handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
   2951                   transitionTo(mConnectedState);
   2952                   break;
   2953               case CMD_STATIC_IP_FAILURE:
   2954                   handleFailedIpConfiguration();
   2955                   transitionTo(mDisconnectingState);
   2956                   break;
   2957               case CMD_DISCONNECT:
   2958                   WifiNative.disconnectCommand();
   2959                   transitionTo(mDisconnectingState);
   2960                   break;
   2961                   /* Ignore connection to same network */
   2962               case CMD_CONNECT_NETWORK:
   2963                   int netId = message.arg1;
   2964                   if (mWifiInfo.getNetworkId() == netId) {
   2965                       break;
   2966                   }
   2967                   return NOT_HANDLED;
   2968               case CMD_SAVE_NETWORK:
   2969                   deferMessage(message);
   2970                   break;
   2971                   /* Ignore */
   2972               case WifiMonitor.NETWORK_CONNECTION_EVENT:
   2973                   break;
   2974               case CMD_SET_SCAN_MODE:
   2975                   if (message.arg1 == SCAN_ONLY_MODE) {
   2976                       sendMessage(CMD_DISCONNECT);
   2977                       deferMessage(message);
   2978                   }
   2979                   break;
   2980                   /* Defer scan when IP is being fetched */
   2981               case CMD_START_SCAN:
   2982                   deferMessage(message);
   2983                   break;
   2984                   /* Defer any power mode changes since we must keep active power mode at DHCP */
   2985               case CMD_SET_HIGH_PERF_MODE:
   2986                   deferMessage(message);
   2987                   break;
   2988               default:
   2989                 return NOT_HANDLED;
   2990           }
   2991           EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   2992           return HANDLED;
   2993       }
   2994     }
   2995 
   2996     class ConnectedState extends State {
   2997         @Override
   2998         public void enter() {
   2999             if (DBG) log(getName() + "\n");
   3000             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   3001             mRssiPollToken++;
   3002             if (mEnableRssiPolling) {
   3003                 sendMessage(obtainMessage(WifiStateMachine.CMD_RSSI_POLL, mRssiPollToken, 0));
   3004             }
   3005         }
   3006         @Override
   3007         public boolean processMessage(Message message) {
   3008             if (DBG) log(getName() + message.toString() + "\n");
   3009             boolean eventLoggingEnabled = true;
   3010             switch (message.what) {
   3011               case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   3012                   handlePreDhcpSetup();
   3013                   mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
   3014                   break;
   3015               case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   3016                   handlePostDhcpSetup();
   3017                   if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
   3018                       handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
   3019                   } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
   3020                       handleFailedIpConfiguration();
   3021                       transitionTo(mDisconnectingState);
   3022                   }
   3023                   break;
   3024                 case CMD_DISCONNECT:
   3025                     WifiNative.disconnectCommand();
   3026                     transitionTo(mDisconnectingState);
   3027                     break;
   3028                 case CMD_SET_SCAN_MODE:
   3029                     if (message.arg1 == SCAN_ONLY_MODE) {
   3030                         sendMessage(CMD_DISCONNECT);
   3031                         deferMessage(message);
   3032                     }
   3033                     break;
   3034                 case CMD_START_SCAN:
   3035                     eventLoggingEnabled = false;
   3036                     /* When the network is connected, re-scanning can trigger
   3037                      * a reconnection. Put it in scan-only mode during scan.
   3038                      * When scan results are received, the mode is switched
   3039                      * back to CONNECT_MODE.
   3040                      */
   3041                     WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
   3042                     /* Have the parent state handle the rest */
   3043                     return NOT_HANDLED;
   3044                     /* Ignore connection to same network */
   3045                 case CMD_CONNECT_NETWORK:
   3046                     int netId = message.arg1;
   3047                     if (mWifiInfo.getNetworkId() == netId) {
   3048                         break;
   3049                     }
   3050                     return NOT_HANDLED;
   3051                 case CMD_SAVE_NETWORK:
   3052                     WifiConfiguration config = (WifiConfiguration) message.obj;
   3053                     NetworkUpdateResult result = WifiConfigStore.saveNetwork(config);
   3054                     if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
   3055                         if (result.hasIpChanged()) {
   3056                             log("Reconfiguring IP on connection");
   3057                             transitionTo(mConnectingState);
   3058                         }
   3059                         if (result.hasProxyChanged()) {
   3060                             log("Reconfiguring proxy on connection");
   3061                             configureLinkProperties();
   3062                             sendLinkConfigurationChangedBroadcast();
   3063                         }
   3064                     }
   3065                     break;
   3066                     /* Ignore */
   3067                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   3068                     break;
   3069                 case CMD_RSSI_POLL:
   3070                     eventLoggingEnabled = false;
   3071                     if (message.arg1 == mRssiPollToken) {
   3072                         // Get Info and continue polling
   3073                         fetchRssiAndLinkSpeedNative();
   3074                         sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL,
   3075                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
   3076                     } else {
   3077                         // Polling has completed
   3078                     }
   3079                     break;
   3080                 case CMD_ENABLE_RSSI_POLL:
   3081                     mEnableRssiPolling = (message.arg1 == 1);
   3082                     mRssiPollToken++;
   3083                     if (mEnableRssiPolling) {
   3084                         // first poll
   3085                         fetchRssiAndLinkSpeedNative();
   3086                         sendMessageDelayed(obtainMessage(WifiStateMachine.CMD_RSSI_POLL,
   3087                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
   3088                     }
   3089                     break;
   3090                 default:
   3091                     return NOT_HANDLED;
   3092             }
   3093             if (eventLoggingEnabled) {
   3094                 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   3095             }
   3096             return HANDLED;
   3097         }
   3098         @Override
   3099         public void exit() {
   3100 
   3101             /* Request a CS wakelock during transition to mobile */
   3102             checkAndSetConnectivityInstance();
   3103             mCm.requestNetworkTransitionWakelock(TAG);
   3104 
   3105             /* If a scan result is pending in connected state, the supplicant
   3106              * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
   3107              */
   3108             if (mScanResultIsPending) {
   3109                 WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
   3110             }
   3111         }
   3112     }
   3113 
   3114     class DisconnectingState extends State {
   3115         @Override
   3116         public void enter() {
   3117             if (DBG) log(getName() + "\n");
   3118             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   3119         }
   3120         @Override
   3121         public boolean processMessage(Message message) {
   3122             if (DBG) log(getName() + message.toString() + "\n");
   3123             switch (message.what) {
   3124                 case CMD_SET_SCAN_MODE:
   3125                     if (message.arg1 == SCAN_ONLY_MODE) {
   3126                         deferMessage(message);
   3127                     }
   3128                     break;
   3129                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   3130                     /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
   3131                      * we have missed the network disconnection, transition to mDisconnectedState
   3132                      * and handle the rest of the events there
   3133                      */
   3134                     deferMessage(message);
   3135                     handleNetworkDisconnect();
   3136                     transitionTo(mDisconnectedState);
   3137                     break;
   3138                 default:
   3139                     return NOT_HANDLED;
   3140             }
   3141             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   3142             return HANDLED;
   3143         }
   3144     }
   3145 
   3146     class DisconnectedState extends State {
   3147         private boolean mAlarmEnabled = false;
   3148         /* This is set from the overlay config file or from a secure setting.
   3149          * A value of 0 disables scanning in the framework.
   3150          */
   3151         private long mFrameworkScanIntervalMs;
   3152 
   3153         private void setScanAlarm(boolean enabled) {
   3154             if (enabled == mAlarmEnabled) return;
   3155             if (enabled) {
   3156                 if (mFrameworkScanIntervalMs > 0) {
   3157                     mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
   3158                             System.currentTimeMillis() + mFrameworkScanIntervalMs,
   3159                             mFrameworkScanIntervalMs,
   3160                             mScanIntent);
   3161                     mAlarmEnabled = true;
   3162                 }
   3163             } else {
   3164                 mAlarmManager.cancel(mScanIntent);
   3165                 mAlarmEnabled = false;
   3166             }
   3167         }
   3168 
   3169         @Override
   3170         public void enter() {
   3171             if (DBG) log(getName() + "\n");
   3172             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   3173 
   3174             mFrameworkScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),
   3175                     Settings.Secure.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
   3176                     mDefaultFrameworkScanIntervalMs);
   3177             /*
   3178              * We initiate background scanning if it is enabled, otherwise we
   3179              * initiate an infrequent scan that wakes up the device to ensure
   3180              * a user connects to an access point on the move
   3181              */
   3182             if (mEnableBackgroundScan) {
   3183                 /* If a regular scan result is pending, do not initiate background
   3184                  * scan until the scan results are returned. This is needed because
   3185                  * initiating a background scan will cancel the regular scan and
   3186                  * scan results will not be returned until background scanning is
   3187                  * cleared
   3188                  */
   3189                 if (!mScanResultIsPending) {
   3190                     WifiNative.enableBackgroundScanCommand(true);
   3191                 }
   3192             } else {
   3193                 setScanAlarm(true);
   3194             }
   3195         }
   3196         @Override
   3197         public boolean processMessage(Message message) {
   3198             if (DBG) log(getName() + message.toString() + "\n");
   3199             switch (message.what) {
   3200                 case CMD_SET_SCAN_MODE:
   3201                     if (message.arg1 == SCAN_ONLY_MODE) {
   3202                         WifiNative.setScanResultHandlingCommand(message.arg1);
   3203                         //Supplicant disconnect to prevent further connects
   3204                         WifiNative.disconnectCommand();
   3205                         mIsScanMode = true;
   3206                         transitionTo(mScanModeState);
   3207                     }
   3208                     break;
   3209                 case CMD_ENABLE_BACKGROUND_SCAN:
   3210                     mEnableBackgroundScan = (message.arg1 == 1);
   3211                     if (mEnableBackgroundScan) {
   3212                         WifiNative.enableBackgroundScanCommand(true);
   3213                         setScanAlarm(false);
   3214                     } else {
   3215                         WifiNative.enableBackgroundScanCommand(false);
   3216                         setScanAlarm(true);
   3217                     }
   3218                     break;
   3219                     /* Ignore network disconnect */
   3220                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   3221                     break;
   3222                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   3223                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   3224                     setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
   3225                     /* ConnectModeState does the rest of the handling */
   3226                     return NOT_HANDLED;
   3227                 case CMD_START_SCAN:
   3228                     /* Disable background scan temporarily during a regular scan */
   3229                     if (mEnableBackgroundScan) {
   3230                         WifiNative.enableBackgroundScanCommand(false);
   3231                     }
   3232                     /* Handled in parent state */
   3233                     return NOT_HANDLED;
   3234                 case WifiMonitor.SCAN_RESULTS_EVENT:
   3235                     /* Re-enable background scan when a pending scan result is received */
   3236                     if (mEnableBackgroundScan && mScanResultIsPending) {
   3237                         WifiNative.enableBackgroundScanCommand(true);
   3238                     }
   3239                     /* Handled in parent state */
   3240                     return NOT_HANDLED;
   3241                 default:
   3242                     return NOT_HANDLED;
   3243             }
   3244             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   3245             return HANDLED;
   3246         }
   3247 
   3248         @Override
   3249         public void exit() {
   3250             /* No need for a background scan upon exit from a disconnected state */
   3251             if (mEnableBackgroundScan) {
   3252                 WifiNative.enableBackgroundScanCommand(false);
   3253             }
   3254             setScanAlarm(false);
   3255         }
   3256     }
   3257 
   3258     class WaitForWpsCompletionState extends State {
   3259         @Override
   3260         public void enter() {
   3261             if (DBG) log(getName() + "\n");
   3262             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   3263         }
   3264         @Override
   3265         public boolean processMessage(Message message) {
   3266             if (DBG) log(getName() + message.toString() + "\n");
   3267             switch (message.what) {
   3268                 /* Defer all commands that can cause connections to a different network
   3269                  * or put the state machine out of connect mode
   3270                  */
   3271                 case CMD_STOP_DRIVER:
   3272                 case CMD_SET_SCAN_MODE:
   3273                 case CMD_CONNECT_NETWORK:
   3274                 case CMD_ENABLE_NETWORK:
   3275                 case CMD_RECONNECT:
   3276                 case CMD_REASSOCIATE:
   3277                 case WifiMonitor.NETWORK_CONNECTION_EVENT: /* Handled after IP & proxy update */
   3278                     deferMessage(message);
   3279                     break;
   3280                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   3281                     if (DBG) log("Network connection lost");
   3282                     handleNetworkDisconnect();
   3283                     break;
   3284                 case WPS_COMPLETED_EVENT:
   3285                     /* we are still disconnected until we see a network connection
   3286                      * notification */
   3287                     transitionTo(mDisconnectedState);
   3288                     break;
   3289                 default:
   3290                     return NOT_HANDLED;
   3291             }
   3292             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   3293             return HANDLED;
   3294         }
   3295     }
   3296 
   3297     class SoftApStartingState extends State {
   3298         @Override
   3299         public void enter() {
   3300             if (DBG) log(getName() + "\n");
   3301             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   3302 
   3303             final Message message = getCurrentMessage();
   3304             if (message.what == CMD_START_AP) {
   3305                 final WifiConfiguration config = (WifiConfiguration) message.obj;
   3306 
   3307                 if (config == null) {
   3308                     mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
   3309                 } else {
   3310                     mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
   3311                     startSoftApWithConfig(config);
   3312                 }
   3313             } else {
   3314                 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
   3315             }
   3316         }
   3317         @Override
   3318         public boolean processMessage(Message message) {
   3319             if (DBG) log(getName() + message.toString() + "\n");
   3320             switch(message.what) {
   3321                 case CMD_LOAD_DRIVER:
   3322                 case CMD_UNLOAD_DRIVER:
   3323                 case CMD_START_SUPPLICANT:
   3324                 case CMD_STOP_SUPPLICANT:
   3325                 case CMD_START_AP:
   3326                 case CMD_STOP_AP:
   3327                 case CMD_START_DRIVER:
   3328                 case CMD_STOP_DRIVER:
   3329                 case CMD_SET_SCAN_MODE:
   3330                 case CMD_SET_SCAN_TYPE:
   3331                 case CMD_SET_HIGH_PERF_MODE:
   3332                 case CMD_SET_COUNTRY_CODE:
   3333                 case CMD_SET_FREQUENCY_BAND:
   3334                 case CMD_START_PACKET_FILTERING:
   3335                 case CMD_STOP_PACKET_FILTERING:
   3336                 case CMD_TETHER_STATE_CHANGE:
   3337                 case WifiP2pService.P2P_ENABLE_PENDING:
   3338                     deferMessage(message);
   3339                     break;
   3340                 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
   3341                     WifiConfiguration config = (WifiConfiguration) message.obj;
   3342                     if (config != null) {
   3343                         startSoftApWithConfig(config);
   3344                     } else {
   3345                         loge("Softap config is null!");
   3346                         sendMessage(CMD_START_AP_FAILURE);
   3347                     }
   3348                     break;
   3349                 case CMD_START_AP_SUCCESS:
   3350                     setWifiApState(WIFI_AP_STATE_ENABLED);
   3351                     transitionTo(mSoftApStartedState);
   3352                     break;
   3353                 case CMD_START_AP_FAILURE:
   3354                     // initiate driver unload
   3355                     sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
   3356                     break;
   3357                 default:
   3358                     return NOT_HANDLED;
   3359             }
   3360             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   3361             return HANDLED;
   3362         }
   3363     }
   3364 
   3365     class SoftApStartedState extends State {
   3366         @Override
   3367         public void enter() {
   3368             if (DBG) log(getName() + "\n");
   3369             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   3370         }
   3371         @Override
   3372         public boolean processMessage(Message message) {
   3373             if (DBG) log(getName() + message.toString() + "\n");
   3374             switch(message.what) {
   3375                 case CMD_STOP_AP:
   3376                     if (DBG) log("Stopping Soft AP");
   3377                     setWifiApState(WIFI_AP_STATE_DISABLING);
   3378 
   3379                     /* We have not tethered at this point, so we just shutdown soft Ap */
   3380                     try {
   3381                         mNwService.stopAccessPoint(mInterfaceName);
   3382                     } catch(Exception e) {
   3383                         loge("Exception in stopAccessPoint()");
   3384                     }
   3385                     transitionTo(mDriverLoadedState);
   3386                     break;
   3387                 case CMD_START_AP:
   3388                     // Ignore a start on a running access point
   3389                     break;
   3390                     /* Fail client mode operation when soft AP is enabled */
   3391                 case CMD_START_SUPPLICANT:
   3392                    loge("Cannot start supplicant with a running soft AP");
   3393                     setWifiState(WIFI_STATE_UNKNOWN);
   3394                     break;
   3395                 case CMD_TETHER_STATE_CHANGE:
   3396                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   3397                     if (startTethering(stateChange.available)) {
   3398                         transitionTo(mTetheringState);
   3399                     }
   3400                     break;
   3401                 case WifiP2pService.P2P_ENABLE_PENDING:
   3402                     // turn of soft Ap and defer to be handled in DriverUnloadedState
   3403                     setWifiApEnabled(null, false);
   3404                     deferMessage(message);
   3405                     break;
   3406                 default:
   3407                     return NOT_HANDLED;
   3408             }
   3409             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   3410             return HANDLED;
   3411         }
   3412     }
   3413 
   3414     class WaitForP2pDisableState extends State {
   3415         private int mSavedArg;
   3416         @Override
   3417         public void enter() {
   3418             if (DBG) log(getName() + "\n");
   3419             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   3420 
   3421             //Preserve the argument arg1 that has information used in DriverLoadingState
   3422             mSavedArg = getCurrentMessage().arg1;
   3423         }
   3424         @Override
   3425         public boolean processMessage(Message message) {
   3426             if (DBG) log(getName() + message.toString() + "\n");
   3427             switch(message.what) {
   3428                 case WifiP2pService.WIFI_ENABLE_PROCEED:
   3429                     //restore argument from original message (CMD_LOAD_DRIVER)
   3430                     message.arg1 = mSavedArg;
   3431                     transitionTo(mDriverLoadingState);
   3432                     break;
   3433                 case CMD_LOAD_DRIVER:
   3434                 case CMD_UNLOAD_DRIVER:
   3435                 case CMD_START_SUPPLICANT:
   3436                 case CMD_STOP_SUPPLICANT:
   3437                 case CMD_START_AP:
   3438                 case CMD_STOP_AP:
   3439                 case CMD_START_DRIVER:
   3440                 case CMD_STOP_DRIVER:
   3441                 case CMD_SET_SCAN_MODE:
   3442                 case CMD_SET_SCAN_TYPE:
   3443                 case CMD_SET_HIGH_PERF_MODE:
   3444                 case CMD_SET_COUNTRY_CODE:
   3445                 case CMD_SET_FREQUENCY_BAND:
   3446                 case CMD_START_PACKET_FILTERING:
   3447                 case CMD_STOP_PACKET_FILTERING:
   3448                     deferMessage(message);
   3449                     break;
   3450                 default:
   3451                     return NOT_HANDLED;
   3452             }
   3453             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   3454             return HANDLED;
   3455         }
   3456     }
   3457 
   3458     class TetheringState extends State {
   3459         @Override
   3460         public void enter() {
   3461             if (DBG) log(getName() + "\n");
   3462             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   3463 
   3464             /* Send ourselves a delayed message to shut down if tethering fails to notify */
   3465             sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
   3466                     ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
   3467         }
   3468         @Override
   3469         public boolean processMessage(Message message) {
   3470             if (DBG) log(getName() + message.toString() + "\n");
   3471             switch(message.what) {
   3472                 case CMD_TETHER_STATE_CHANGE:
   3473                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   3474                     if (isWifiTethered(stateChange.active)) {
   3475                         transitionTo(mTetheredState);
   3476                     }
   3477                     return HANDLED;
   3478                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   3479                     if (message.arg1 == mTetherToken) {
   3480                         loge("Failed to get tether update, shutdown soft access point");
   3481                         setWifiApEnabled(null, false);
   3482                     }
   3483                     break;
   3484                 case CMD_LOAD_DRIVER:
   3485                 case CMD_UNLOAD_DRIVER:
   3486                 case CMD_START_SUPPLICANT:
   3487                 case CMD_STOP_SUPPLICANT:
   3488                 case CMD_START_AP:
   3489                 case CMD_STOP_AP:
   3490                 case CMD_START_DRIVER:
   3491                 case CMD_STOP_DRIVER:
   3492                 case CMD_SET_SCAN_MODE:
   3493                 case CMD_SET_SCAN_TYPE:
   3494                 case CMD_SET_HIGH_PERF_MODE:
   3495                 case CMD_SET_COUNTRY_CODE:
   3496                 case CMD_SET_FREQUENCY_BAND:
   3497                 case CMD_START_PACKET_FILTERING:
   3498                 case CMD_STOP_PACKET_FILTERING:
   3499                 case WifiP2pService.P2P_ENABLE_PENDING:
   3500                     deferMessage(message);
   3501                     break;
   3502                 default:
   3503                     return NOT_HANDLED;
   3504             }
   3505             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   3506             return HANDLED;
   3507         }
   3508     }
   3509 
   3510     class TetheredState extends State {
   3511         @Override
   3512         public void enter() {
   3513             if (DBG) log(getName() + "\n");
   3514             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   3515         }
   3516         @Override
   3517         public boolean processMessage(Message message) {
   3518             if (DBG) log(getName() + message.toString() + "\n");
   3519             switch(message.what) {
   3520                 case CMD_TETHER_STATE_CHANGE:
   3521                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   3522                     if (!isWifiTethered(stateChange.active)) {
   3523                         loge("Tethering reports wifi as untethered!, shut down soft Ap");
   3524                         setWifiApEnabled(null, false);
   3525                     }
   3526                     return HANDLED;
   3527                 case CMD_STOP_AP:
   3528                     if (DBG) log("Untethering before stopping AP");
   3529                     setWifiApState(WIFI_AP_STATE_DISABLING);
   3530                     stopTethering();
   3531                     transitionTo(mSoftApStoppingState);
   3532                     break;
   3533                 default:
   3534                     return NOT_HANDLED;
   3535             }
   3536             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   3537             return HANDLED;
   3538         }
   3539     }
   3540 
   3541     class SoftApStoppingState extends State {
   3542         @Override
   3543         public void enter() {
   3544             if (DBG) log(getName() + "\n");
   3545             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
   3546 
   3547             /* Send ourselves a delayed message to shut down if tethering fails to notify */
   3548             sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
   3549                     ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
   3550 
   3551         }
   3552         @Override
   3553         public boolean processMessage(Message message) {
   3554             if (DBG) log(getName() + message.toString() + "\n");
   3555             switch(message.what) {
   3556                 case CMD_TETHER_STATE_CHANGE:
   3557                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   3558 
   3559                     /* Wait till wifi is untethered */
   3560                     if (isWifiTethered(stateChange.active)) break;
   3561 
   3562                     try {
   3563                         mNwService.stopAccessPoint(mInterfaceName);
   3564                     } catch(Exception e) {
   3565                         loge("Exception in stopAccessPoint()");
   3566                     }
   3567                     transitionTo(mDriverLoadedState);
   3568                     break;
   3569                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   3570                     if (message.arg1 == mTetherToken) {
   3571                         loge("Failed to get tether update, force stop access point");
   3572                         try {
   3573                             mNwService.stopAccessPoint(mInterfaceName);
   3574                         } catch(Exception e) {
   3575                             loge("Exception in stopAccessPoint()");
   3576                         }
   3577                         transitionTo(mDriverLoadedState);
   3578                     }
   3579                     break;
   3580                 case CMD_LOAD_DRIVER:
   3581                 case CMD_UNLOAD_DRIVER:
   3582                 case CMD_START_SUPPLICANT:
   3583                 case CMD_STOP_SUPPLICANT:
   3584                 case CMD_START_AP:
   3585                 case CMD_STOP_AP:
   3586                 case CMD_START_DRIVER:
   3587                 case CMD_STOP_DRIVER:
   3588                 case CMD_SET_SCAN_MODE:
   3589                 case CMD_SET_SCAN_TYPE:
   3590                 case CMD_SET_HIGH_PERF_MODE:
   3591                 case CMD_SET_COUNTRY_CODE:
   3592                 case CMD_SET_FREQUENCY_BAND:
   3593                 case CMD_START_PACKET_FILTERING:
   3594                 case CMD_STOP_PACKET_FILTERING:
   3595                 case WifiP2pService.P2P_ENABLE_PENDING:
   3596                     deferMessage(message);
   3597                     break;
   3598                 default:
   3599                     return NOT_HANDLED;
   3600             }
   3601             EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
   3602             return HANDLED;
   3603         }
   3604     }
   3605 
   3606     private void log(String s) {
   3607         Log.d(TAG, s);
   3608     }
   3609 
   3610     private void loge(String s) {
   3611         Log.e(TAG, s);
   3612     }
   3613 }
   3614