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