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