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