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