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