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 com.android.server.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.NetworkAgent;
     52 import android.net.NetworkCapabilities;
     53 import android.net.NetworkFactory;
     54 import android.net.NetworkInfo;
     55 import android.net.NetworkInfo.DetailedState;
     56 import android.net.NetworkUtils;
     57 import android.net.RouteInfo;
     58 import android.net.StaticIpConfiguration;
     59 import android.net.TrafficStats;
     60 import android.net.wifi.*;
     61 import android.net.wifi.SupplicantState;
     62 import android.net.wifi.WpsResult.Status;
     63 import android.net.wifi.p2p.IWifiP2pManager;
     64 import android.os.BatteryStats;
     65 import android.os.Bundle;
     66 import android.os.IBinder;
     67 import android.os.INetworkManagementService;
     68 import android.os.Looper;
     69 import android.os.Message;
     70 import android.os.Messenger;
     71 import android.os.PowerManager;
     72 import android.os.Process;
     73 import android.os.RemoteException;
     74 import android.os.ServiceManager;
     75 import android.os.SystemClock;
     76 import android.os.SystemProperties;
     77 import android.os.UserHandle;
     78 import android.os.WorkSource;
     79 import android.provider.Settings;
     80 import android.telephony.TelephonyManager;
     81 import android.util.LruCache;
     82 import android.text.TextUtils;
     83 import android.util.Log;
     84 
     85 import com.android.internal.R;
     86 import com.android.internal.app.IBatteryStats;
     87 import com.android.internal.util.AsyncChannel;
     88 import com.android.internal.util.Protocol;
     89 import com.android.internal.util.State;
     90 import com.android.internal.util.StateMachine;
     91 import com.android.server.net.BaseNetworkObserver;
     92 import com.android.server.net.NetlinkTracker;
     93 
     94 import com.android.server.wifi.p2p.WifiP2pServiceImpl;
     95 
     96 import java.io.FileDescriptor;
     97 import java.io.PrintWriter;
     98 import java.net.InetAddress;
     99 import java.util.*;
    100 import java.util.concurrent.atomic.AtomicInteger;
    101 import java.util.concurrent.atomic.AtomicBoolean;
    102 import java.util.regex.Pattern;
    103 import java.io.FileReader;
    104 import java.io.BufferedReader;
    105 import java.io.FileNotFoundException;
    106 import java.io.IOException;
    107 import java.net.Inet4Address;
    108 
    109 /**
    110  * Track the state of Wifi connectivity. All event handling is done here,
    111  * and all changes in connectivity state are initiated here.
    112  *
    113  * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p
    114  * In the current implementation, we support concurrent wifi p2p and wifi operation.
    115  * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService
    116  * handles p2p operation.
    117  *
    118  * @hide
    119  */
    120 public class WifiStateMachine extends StateMachine {
    121 
    122     private static final String NETWORKTYPE = "WIFI";
    123     private static boolean DBG = false;
    124     private static boolean VDBG = false;
    125     private static boolean VVDBG = false;
    126     private static boolean mLogMessages = false;
    127 
    128     private static final int ONE_HOUR_MILLI = 1000 * 60 * 60;
    129 
    130     private static final String GOOGLE_OUI = "DA-A1-19";
    131 
    132     /* temporary debug flag - best network selection development */
    133     private static boolean PDBG = false;
    134 
    135     /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting
    136      * the corresponding BSSID.
    137      */
    138     private boolean didBlackListBSSID = false;
    139 
    140     /**
    141      * Log with error attribute
    142      *
    143      * @param s is string log
    144      */
    145     protected void loge(String s) {
    146         Log.e(getName(), s);
    147     }
    148     protected void log(String s) {;
    149         Log.e(getName(), s);
    150     }
    151 
    152     private WifiMonitor mWifiMonitor;
    153     private WifiNative mWifiNative;
    154     private WifiConfigStore mWifiConfigStore;
    155     private WifiAutoJoinController mWifiAutoJoinController;
    156     private INetworkManagementService mNwService;
    157     private ConnectivityManager mCm;
    158 
    159     private final boolean mP2pSupported;
    160     private final AtomicBoolean mP2pConnected = new AtomicBoolean(false);
    161     private boolean mTemporarilyDisconnectWifi = false;
    162     private final String mPrimaryDeviceType;
    163 
    164     /* Scan results handling */
    165     private List<ScanResult> mScanResults = new ArrayList<ScanResult>();
    166     private static final Pattern scanResultPattern = Pattern.compile("\t+");
    167     private static final int SCAN_RESULT_CACHE_SIZE = 160;
    168     private final LruCache<String, ScanResult> mScanResultCache;
    169     // For debug, number of known scan results that were found as part of last scan result event,
    170     // as well the number of scans results returned by the supplicant with that message
    171     private int mNumScanResultsKnown;
    172     private int mNumScanResultsReturned;
    173 
    174     /* Batch scan results */
    175     private final List<BatchedScanResult> mBatchedScanResults =
    176             new ArrayList<BatchedScanResult>();
    177     private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE;
    178     private int mExpectedBatchedScans = 0;
    179     private long mBatchedScanMinPollTime = 0;
    180 
    181     private boolean mScreenOn = false;
    182 
    183     /* Chipset supports background scan */
    184     private final boolean mBackgroundScanSupported;
    185 
    186     private String mInterfaceName;
    187     /* Tethering interface could be separate from wlan interface */
    188     private String mTetherInterfaceName;
    189 
    190     private int mLastSignalLevel = -1;
    191     private String mLastBssid;
    192     private int mLastNetworkId; // The network Id we successfully joined
    193     private boolean linkDebouncing = false;
    194 
    195     // Testing various network disconnect cases by sending lots of spurious
    196     // disconnect to supplicant
    197     private boolean testNetworkDisconnect = false;
    198 
    199     private boolean mEnableRssiPolling = false;
    200     private boolean mEnableBackgroundScan = false;
    201     private int mRssiPollToken = 0;
    202     /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
    203     * In CONNECT_MODE, the STA can scan and connect to an access point
    204     * In SCAN_ONLY_MODE, the STA can only scan for access points
    205     * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off
    206     */
    207     private int mOperationalMode = CONNECT_MODE;
    208     private boolean mIsScanOngoing = false;
    209     private boolean mIsFullScanOngoing = false;
    210     private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>();
    211     private WorkSource mScanWorkSource = null;
    212     private static final int UNKNOWN_SCAN_SOURCE = -1;
    213     private static final int SCAN_ALARM_SOURCE = -2;
    214     private static final int ADD_OR_UPDATE_SOURCE = -3;
    215 
    216     private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10;
    217     private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings";
    218     private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource";
    219     private static final String SCAN_REQUEST_TIME = "scan_request_time";
    220 
    221     private static final String BATCHED_SETTING = "batched_settings";
    222     private static final String BATCHED_WORKSOURCE = "batched_worksource";
    223 
    224     /* Tracks if state machine has received any screen state change broadcast yet.
    225      * We can miss one of these at boot.
    226      */
    227     private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false);
    228 
    229     private boolean mBluetoothConnectionActive = false;
    230 
    231     private PowerManager.WakeLock mSuspendWakeLock;
    232 
    233     /**
    234      * Interval in milliseconds between polling for RSSI
    235      * and linkspeed information
    236      */
    237     private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
    238 
    239     /**
    240      * Interval in milliseconds between receiving a disconnect event
    241      * while connected to a good AP, and handling the disconnect proper
    242      */
    243     private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 7000;
    244 
    245     /**
    246      * Delay between supplicant restarts upon failure to establish connection
    247      */
    248     private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
    249 
    250     /**
    251      * Number of times we attempt to restart supplicant
    252      */
    253     private static final int SUPPLICANT_RESTART_TRIES = 5;
    254 
    255     private int mSupplicantRestartCount = 0;
    256     /* Tracks sequence number on stop failure message */
    257     private int mSupplicantStopFailureToken = 0;
    258 
    259     /**
    260      * Tether state change notification time out
    261      */
    262     private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000;
    263 
    264     /* Tracks sequence number on a tether notification time out */
    265     private int mTetherToken = 0;
    266 
    267     /**
    268      * Driver start time out.
    269      */
    270     private static final int DRIVER_START_TIME_OUT_MSECS = 10000;
    271 
    272     /* Tracks sequence number on a driver time out */
    273     private int mDriverStartToken = 0;
    274 
    275     /**
    276      * The link properties of the wifi interface.
    277      * Do not modify this directly; use updateLinkProperties instead.
    278      */
    279     private LinkProperties mLinkProperties;
    280 
    281     /* Tracks sequence number on a periodic scan message */
    282     private int mPeriodicScanToken = 0;
    283 
    284     // Wakelock held during wifi start/stop and driver load/unload
    285     private PowerManager.WakeLock mWakeLock;
    286 
    287     private Context mContext;
    288 
    289     private final Object mDhcpResultsLock = new Object();
    290     private DhcpResults mDhcpResults;
    291     private WifiInfo mWifiInfo;
    292     private NetworkInfo mNetworkInfo;
    293     private NetworkCapabilities mNetworkCapabilities;
    294     private SupplicantStateTracker mSupplicantStateTracker;
    295     private DhcpStateMachine mDhcpStateMachine;
    296     private boolean mDhcpActive = false;
    297 
    298     private int mWifiLinkLayerStatsSupported = 4; // Temporary disable
    299 
    300     private final AtomicInteger mCountryCodeSequence = new AtomicInteger();
    301 
    302     // Whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress
    303     private int mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
    304 
    305     // Roaming failure count
    306     private int mRoamFailCount = 0;
    307 
    308     // This is the BSSID we are trying to associate to, it can be set to "any"
    309     // if we havent selected a BSSID for joining.
    310     // The BSSID we are associated to is found in mWifiInfo
    311     private String mTargetRoamBSSID = "any";
    312 
    313     private long mLastDriverRoamAttempt = 0;
    314 
    315     private WifiConfiguration targetWificonfiguration = null;
    316 
    317     // Used as debug to indicate which configuration last was saved
    318     private WifiConfiguration lastSavedConfigurationAttempt = null;
    319 
    320     // Used as debug to indicate which configuration last was removed
    321     private WifiConfiguration lastForgetConfigurationAttempt = null;
    322 
    323     boolean isRoaming() {
    324         return mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_ROAMING
    325                 || mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_EXTENDED_ROAMING;
    326     }
    327 
    328     public void autoRoamSetBSSID(int netId, String bssid) {
    329         autoRoamSetBSSID(mWifiConfigStore.getWifiConfiguration(netId), bssid);
    330     }
    331 
    332     public boolean autoRoamSetBSSID(WifiConfiguration config, String bssid) {
    333         boolean ret = true;
    334         if (mTargetRoamBSSID == null) mTargetRoamBSSID = "any";
    335         if (bssid == null) bssid = "any";
    336         if (config == null) return false; // Nothing to do
    337 
    338         if (mTargetRoamBSSID != null && bssid == mTargetRoamBSSID && bssid == config.BSSID) {
    339             return false; // We didnt change anything
    340         }
    341         if (!mTargetRoamBSSID.equals("any") && bssid.equals("any")) {
    342             // Changing to ANY
    343             if (!mWifiConfigStore.roamOnAny) {
    344                 ret =  false; // Nothing to do
    345             }
    346         }
    347         if (VDBG) {
    348            loge("autoRoamSetBSSID " + bssid
    349                    + " key=" + config.configKey());
    350         }
    351         config.autoJoinBSSID = bssid;
    352         mTargetRoamBSSID = bssid;
    353         mWifiConfigStore.saveWifiConfigBSSID(config);
    354         return ret;
    355     }
    356 
    357     /**
    358      * Subset of link properties coming from netlink.
    359      * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers
    360      * and domains obtained from router advertisements (RFC 6106).
    361      */
    362     private NetlinkTracker mNetlinkTracker;
    363 
    364     private AlarmManager mAlarmManager;
    365     private PendingIntent mScanIntent;
    366     private PendingIntent mDriverStopIntent;
    367     private PendingIntent mBatchedScanIntervalIntent;
    368 
    369     /* Tracks current frequency mode */
    370     private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
    371 
    372     /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */
    373     private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true);
    374 
    375     // Channel for sending replies.
    376     private AsyncChannel mReplyChannel = new AsyncChannel();
    377 
    378     private WifiP2pServiceImpl mWifiP2pServiceImpl;
    379 
    380     // Used to initiate a connection with WifiP2pService
    381     private AsyncChannel mWifiP2pChannel;
    382     private AsyncChannel mWifiApConfigChannel;
    383 
    384     private WifiNetworkFactory mNetworkFactory;
    385     private WifiNetworkAgent mNetworkAgent;
    386 
    387     // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi
    388     // We should really persist that into the networkHistory.txt file, and read it back when
    389     // WifiStateMachine starts up
    390     private WifiConnectionStatistics mWifiConnectionStatistics = new WifiConnectionStatistics();
    391 
    392     // Used to filter out requests we couldn't possibly satisfy.
    393     private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities();
    394 
    395     /* The base for wifi message types */
    396     static final int BASE = Protocol.BASE_WIFI;
    397     /* Start the supplicant */
    398     static final int CMD_START_SUPPLICANT                 = BASE + 11;
    399     /* Stop the supplicant */
    400     static final int CMD_STOP_SUPPLICANT                  = BASE + 12;
    401     /* Start the driver */
    402     static final int CMD_START_DRIVER                     = BASE + 13;
    403     /* Stop the driver */
    404     static final int CMD_STOP_DRIVER                      = BASE + 14;
    405     /* Indicates Static IP succeeded */
    406     static final int CMD_STATIC_IP_SUCCESS                = BASE + 15;
    407     /* Indicates Static IP failed */
    408     static final int CMD_STATIC_IP_FAILURE                = BASE + 16;
    409     /* Indicates supplicant stop failed */
    410     static final int CMD_STOP_SUPPLICANT_FAILED           = BASE + 17;
    411     /* Delayed stop to avoid shutting down driver too quick*/
    412     static final int CMD_DELAYED_STOP_DRIVER              = BASE + 18;
    413     /* A delayed message sent to start driver when it fail to come up */
    414     static final int CMD_DRIVER_START_TIMED_OUT           = BASE + 19;
    415 
    416     /* Start the soft access point */
    417     static final int CMD_START_AP                         = BASE + 21;
    418     /* Indicates soft ap start succeeded */
    419     static final int CMD_START_AP_SUCCESS                 = BASE + 22;
    420     /* Indicates soft ap start failed */
    421     static final int CMD_START_AP_FAILURE                 = BASE + 23;
    422     /* Stop the soft access point */
    423     static final int CMD_STOP_AP                          = BASE + 24;
    424     /* Set the soft access point configuration */
    425     static final int CMD_SET_AP_CONFIG                    = BASE + 25;
    426     /* Soft access point configuration set completed */
    427     static final int CMD_SET_AP_CONFIG_COMPLETED          = BASE + 26;
    428     /* Request the soft access point configuration */
    429     static final int CMD_REQUEST_AP_CONFIG                = BASE + 27;
    430     /* Response to access point configuration request */
    431     static final int CMD_RESPONSE_AP_CONFIG               = BASE + 28;
    432     /* Invoked when getting a tether state change notification */
    433     static final int CMD_TETHER_STATE_CHANGE              = BASE + 29;
    434     /* A delayed message sent to indicate tether state change failed to arrive */
    435     static final int CMD_TETHER_NOTIFICATION_TIMED_OUT    = BASE + 30;
    436 
    437     static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 31;
    438 
    439     /* Supplicant commands */
    440     /* Is supplicant alive ? */
    441     static final int CMD_PING_SUPPLICANT                  = BASE + 51;
    442     /* Add/update a network configuration */
    443     static final int CMD_ADD_OR_UPDATE_NETWORK            = BASE + 52;
    444     /* Delete a network */
    445     static final int CMD_REMOVE_NETWORK                   = BASE + 53;
    446     /* Enable a network. The device will attempt a connection to the given network. */
    447     static final int CMD_ENABLE_NETWORK                   = BASE + 54;
    448     /* Enable all networks */
    449     static final int CMD_ENABLE_ALL_NETWORKS              = BASE + 55;
    450     /* Blacklist network. De-prioritizes the given BSSID for connection. */
    451     static final int CMD_BLACKLIST_NETWORK                = BASE + 56;
    452     /* Clear the blacklist network list */
    453     static final int CMD_CLEAR_BLACKLIST                  = BASE + 57;
    454     /* Save configuration */
    455     static final int CMD_SAVE_CONFIG                      = BASE + 58;
    456     /* Get configured networks */
    457     static final int CMD_GET_CONFIGURED_NETWORKS          = BASE + 59;
    458     /* Get available frequencies */
    459     static final int CMD_GET_CAPABILITY_FREQ              = BASE + 60;
    460     /* Get adaptors */
    461     static final int CMD_GET_SUPPORTED_FEATURES           = BASE + 61;
    462     /* Get configured networks with real preSharedKey */
    463     static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS = BASE + 62;
    464     /* Get Link Layer Stats thru HAL */
    465     static final int CMD_GET_LINK_LAYER_STATS             = BASE + 63;
    466     /* Supplicant commands after driver start*/
    467     /* Initiate a scan */
    468     static final int CMD_START_SCAN                       = BASE + 71;
    469     /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */
    470     static final int CMD_SET_OPERATIONAL_MODE             = BASE + 72;
    471     /* Disconnect from a network */
    472     static final int CMD_DISCONNECT                       = BASE + 73;
    473     /* Reconnect to a network */
    474     static final int CMD_RECONNECT                        = BASE + 74;
    475     /* Reassociate to a network */
    476     static final int CMD_REASSOCIATE                      = BASE + 75;
    477     /* Get Connection Statistis */
    478     static final int CMD_GET_CONNECTION_STATISTICS        = BASE + 76;
    479 
    480     /* Controls suspend mode optimizations
    481      *
    482      * When high perf mode is enabled, suspend mode optimizations are disabled
    483      *
    484      * When high perf mode is disabled, suspend mode optimizations are enabled
    485      *
    486      * Suspend mode optimizations include:
    487      * - packet filtering
    488      * - turn off roaming
    489      * - DTIM wake up settings
    490      */
    491     static final int CMD_SET_HIGH_PERF_MODE               = BASE + 77;
    492     /* Set the country code */
    493     static final int CMD_SET_COUNTRY_CODE                 = BASE + 80;
    494     /* Enables RSSI poll */
    495     static final int CMD_ENABLE_RSSI_POLL                 = BASE + 82;
    496     /* RSSI poll */
    497     static final int CMD_RSSI_POLL                        = BASE + 83;
    498     /* Set up packet filtering */
    499     static final int CMD_START_PACKET_FILTERING           = BASE + 84;
    500     /* Clear packet filter */
    501     static final int CMD_STOP_PACKET_FILTERING            = BASE + 85;
    502     /* Enable suspend mode optimizations in the driver */
    503     static final int CMD_SET_SUSPEND_OPT_ENABLED          = BASE + 86;
    504     /* Delayed NETWORK_DISCONNECT */
    505     static final int CMD_DELAYED_NETWORK_DISCONNECT       = BASE + 87;
    506     /* When there are no saved networks, we do a periodic scan to notify user of
    507      * an open network */
    508     static final int CMD_NO_NETWORKS_PERIODIC_SCAN        = BASE + 88;
    509     /* Test network Disconnection NETWORK_DISCONNECT */
    510     static final int CMD_TEST_NETWORK_DISCONNECT          = BASE + 89;
    511     private int testNetworkDisconnectCounter = 0;
    512 
    513     /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */
    514     static final int MULTICAST_V6  = 1;
    515     static final int MULTICAST_V4  = 0;
    516 
    517    /* Set the frequency band */
    518     static final int CMD_SET_FREQUENCY_BAND               = BASE + 90;
    519     /* Enable TDLS on a specific MAC address */
    520     static final int CMD_ENABLE_TDLS                      = BASE + 92;
    521     /* DHCP/IP configuration watchdog */
    522     static final int CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER    = BASE + 93;
    523 
    524     /**
    525      * Make this timer 40 seconds, which is about the normal DHCP timeout.
    526      * In no valid case, the WiFiStateMachine should remain stuck in ObtainingIpAddress
    527      * for more than 30 seconds.
    528      */
    529     static final int OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC = 40000;
    530 
    531     int obtainingIpWatchdogCount = 0;
    532 
    533     /* Commands from/to the SupplicantStateTracker */
    534     /* Reset the supplicant state tracker */
    535     static final int CMD_RESET_SUPPLICANT_STATE           = BASE + 111;
    536 
    537 
    538     /**
    539      * Watchdog for protecting against b/16823537
    540      * Leave time for 4-ways handshake to succeed
    541      */
    542     static final int ROAM_GUARD_TIMER_MSEC = 15000;
    543 
    544     int roamWatchdogCount = 0;
    545     /* Roam state watchdog */
    546     static final int CMD_ROAM_WATCHDOG_TIMER    = BASE + 94;
    547     /* Screen change intent handling */
    548     static final int CMD_SCREEN_STATE_CHANGED              = BASE + 95;
    549 
    550     int disconnectingWatchdogCount = 0;
    551     static final int DISCONNECTING_GUARD_TIMER_MSEC = 5000;
    552 
    553     /* Disconnecting state watchdog */
    554     static final int CMD_DISCONNECTING_WATCHDOG_TIMER     = BASE + 96;
    555 
    556     /* P2p commands */
    557     /* We are ok with no response here since we wont do much with it anyway */
    558     public static final int CMD_ENABLE_P2P                = BASE + 131;
    559     /* In order to shut down supplicant cleanly, we wait till p2p has
    560      * been disabled */
    561     public static final int CMD_DISABLE_P2P_REQ           = BASE + 132;
    562     public static final int CMD_DISABLE_P2P_RSP           = BASE + 133;
    563 
    564     public static final int CMD_BOOT_COMPLETED            = BASE + 134;
    565 
    566     /* change the batch scan settings.
    567      * arg1 = responsible UID
    568      * arg2 = csph (channel scans per hour)
    569      * obj = bundle with the new settings and the optional worksource
    570      */
    571     public static final int CMD_SET_BATCHED_SCAN          = BASE + 135;
    572     public static final int CMD_START_NEXT_BATCHED_SCAN   = BASE + 136;
    573     public static final int CMD_POLL_BATCHED_SCAN         = BASE + 137;
    574 
    575     /* We now have a valid IP configuration. */
    576     static final int CMD_IP_CONFIGURATION_SUCCESSFUL      = BASE + 138;
    577     /* We no longer have a valid IP configuration. */
    578     static final int CMD_IP_CONFIGURATION_LOST            = BASE + 139;
    579     /* Link configuration (IP address, DNS, ...) changes notified via netlink */
    580     static final int CMD_UPDATE_LINKPROPERTIES            = BASE + 140;
    581 
    582     /* Supplicant is trying to associate to a given BSSID */
    583     static final int CMD_TARGET_BSSID                     = BASE + 141;
    584 
    585     /* Reload all networks and reconnect */
    586     static final int CMD_RELOAD_TLS_AND_RECONNECT         = BASE + 142;
    587 
    588     static final int CMD_AUTO_CONNECT                     = BASE + 143;
    589 
    590     static final int network_status_unwanted_disconnect = 0;
    591     static final int network_status_unwanted_disable_autojoin = 1;
    592 
    593     static final int CMD_UNWANTED_NETWORK                 = BASE + 144;
    594 
    595     static final int CMD_AUTO_ROAM                        = BASE + 145;
    596 
    597     static final int CMD_AUTO_SAVE_NETWORK                = BASE + 146;
    598 
    599     static final int CMD_ASSOCIATED_BSSID                = BASE + 147;
    600 
    601     /* Wifi state machine modes of operation */
    602     /* CONNECT_MODE - connect to any 'known' AP when it becomes available */
    603     public static final int CONNECT_MODE                   = 1;
    604     /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */
    605     public static final int SCAN_ONLY_MODE                 = 2;
    606     /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */
    607     public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE   = 3;
    608 
    609     private static final int SUCCESS = 1;
    610     private static final int FAILURE = -1;
    611 
    612     /* Tracks if suspend optimizations need to be disabled by DHCP,
    613      * screen or due to high perf mode.
    614      * When any of them needs to disable it, we keep the suspend optimizations
    615      * disabled
    616      */
    617     private int mSuspendOptNeedsDisabled = 0;
    618 
    619     private static final int SUSPEND_DUE_TO_DHCP       = 1;
    620     private static final int SUSPEND_DUE_TO_HIGH_PERF  = 1<<1;
    621     private static final int SUSPEND_DUE_TO_SCREEN     = 1<<2;
    622 
    623     /* Tracks if user has enabled suspend optimizations through settings */
    624     private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true);
    625 
    626     /**
    627      * Default framework scan interval in milliseconds. This is used in the scenario in which
    628      * wifi chipset does not support background scanning to set up a
    629      * periodic wake up scan so that the device can connect to a new access
    630      * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can
    631      * override this.
    632      */
    633     private final int mDefaultFrameworkScanIntervalMs;
    634 
    635     private int mDisconnectedScanPeriodMs = 10000;
    636 
    637     /**
    638      * Supplicant scan interval in milliseconds.
    639      * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or
    640      * from the default config if the setting is not set
    641      */
    642     private long mSupplicantScanIntervalMs;
    643 
    644     /**
    645      * timeStamp of last full band scan we perfoemed for autojoin while connected with screen lit
    646      */
    647     private long lastFullBandConnectedTimeMilli;
    648 
    649     /**
    650      * time interval to the next full band scan we will perform for
    651      * autojoin while connected with screen lit
    652      */
    653     private long fullBandConnectedTimeIntervalMilli;
    654 
    655     /**
    656      * max time interval to the next full band scan we will perform for
    657      * autojoin while connected with screen lit
    658      * Max time is 5 minutes
    659      */
    660     private static final long  maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5;
    661 
    662     /**
    663      * Minimum time interval between enabling all networks.
    664      * A device can end up repeatedly connecting to a bad network on screen on/off toggle
    665      * due to enabling every time. We add a threshold to avoid this.
    666      */
    667     private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */
    668     private long mLastEnableAllNetworksTime;
    669 
    670     int mRunningBeaconCount = 0;
    671 
    672     /**
    673      * Starting and shutting down driver too quick causes problems leading to driver
    674      * being in a bad state. Delay driver stop.
    675      */
    676     private final int mDriverStopDelayMs;
    677     private int mDelayedStopCounter;
    678     private boolean mInDelayedStop = false;
    679 
    680     // sometimes telephony gives us this data before boot is complete and we can't store it
    681     // until after, so the write is deferred
    682     private volatile String mPersistedCountryCode;
    683 
    684     // Supplicant doesn't like setting the same country code multiple times (it may drop
    685     // currently connected network), so we save the country code here to avoid redundency
    686     private String mLastSetCountryCode;
    687 
    688     /* Default parent state */
    689     private State mDefaultState = new DefaultState();
    690     /* Temporary initial state */
    691     private State mInitialState = new InitialState();
    692     /* Driver loaded, waiting for supplicant to start */
    693     private State mSupplicantStartingState = new SupplicantStartingState();
    694     /* Driver loaded and supplicant ready */
    695     private State mSupplicantStartedState = new SupplicantStartedState();
    696     /* Waiting for supplicant to stop and monitor to exit */
    697     private State mSupplicantStoppingState = new SupplicantStoppingState();
    698     /* Driver start issued, waiting for completed event */
    699     private State mDriverStartingState = new DriverStartingState();
    700     /* Driver started */
    701     private State mDriverStartedState = new DriverStartedState();
    702     /* Wait until p2p is disabled
    703      * This is a special state which is entered right after we exit out of DriverStartedState
    704      * before transitioning to another state.
    705      */
    706     private State mWaitForP2pDisableState = new WaitForP2pDisableState();
    707     /* Driver stopping */
    708     private State mDriverStoppingState = new DriverStoppingState();
    709     /* Driver stopped */
    710     private State mDriverStoppedState = new DriverStoppedState();
    711     /* Scan for networks, no connection will be established */
    712     private State mScanModeState = new ScanModeState();
    713     /* Connecting to an access point */
    714     private State mConnectModeState = new ConnectModeState();
    715     /* Connected at 802.11 (L2) level */
    716     private State mL2ConnectedState = new L2ConnectedState();
    717     /* fetching IP after connection to access point (assoc+auth complete) */
    718     private State mObtainingIpState = new ObtainingIpState();
    719     /* Waiting for link quality verification to be complete */
    720     private State mVerifyingLinkState = new VerifyingLinkState();
    721     /* Connected with IP addr */
    722     private State mConnectedState = new ConnectedState();
    723     /* Roaming */
    724     private State mRoamingState = new RoamingState();
    725     /* disconnect issued, waiting for network disconnect confirmation */
    726     private State mDisconnectingState = new DisconnectingState();
    727     /* Network is not connected, supplicant assoc+auth is not complete */
    728     private State mDisconnectedState = new DisconnectedState();
    729     /* Waiting for WPS to be completed*/
    730     private State mWpsRunningState = new WpsRunningState();
    731 
    732     /* Soft ap is starting up */
    733     private State mSoftApStartingState = new SoftApStartingState();
    734     /* Soft ap is running */
    735     private State mSoftApStartedState = new SoftApStartedState();
    736     /* Soft ap is running and we are waiting for tether notification */
    737     private State mTetheringState = new TetheringState();
    738     /* Soft ap is running and we are tethered through connectivity service */
    739     private State mTetheredState = new TetheredState();
    740     /* Waiting for untether confirmation before stopping soft Ap */
    741     private State mUntetheringState = new UntetheringState();
    742 
    743     private class TetherStateChange {
    744         ArrayList<String> available;
    745         ArrayList<String> active;
    746         TetherStateChange(ArrayList<String> av, ArrayList<String> ac) {
    747             available = av;
    748             active = ac;
    749         }
    750     }
    751 
    752     public static class SimAuthRequestData {
    753         int networkId;
    754         int protocol;
    755         String ssid;
    756         String[] challenges;
    757     }
    758 
    759     public static class SimAuthResponseData {
    760         int id;
    761         String Kc1;
    762         String SRES1;
    763         String Kc2;
    764         String SRES2;
    765         String Kc3;
    766         String SRES3;
    767     }
    768 
    769     /**
    770      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
    771      *         {@link WifiManager#WIFI_STATE_DISABLING},
    772      *         {@link WifiManager#WIFI_STATE_ENABLED},
    773      *         {@link WifiManager#WIFI_STATE_ENABLING},
    774      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
    775      *
    776      */
    777     private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
    778 
    779     /**
    780      * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
    781      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
    782      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
    783      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
    784      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
    785      *
    786      */
    787     private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
    788 
    789     private static final int SCAN_REQUEST = 0;
    790     private static final String ACTION_START_SCAN =
    791         "com.android.server.WifiManager.action.START_SCAN";
    792 
    793     private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter";
    794     private static final int DRIVER_STOP_REQUEST = 0;
    795     private static final String ACTION_DELAYED_DRIVER_STOP =
    796         "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
    797 
    798     private static final String ACTION_REFRESH_BATCHED_SCAN =
    799             "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN";
    800     /**
    801      * Keep track of whether WIFI is running.
    802      */
    803     private boolean mIsRunning = false;
    804 
    805     /**
    806      * Keep track of whether we last told the battery stats we had started.
    807      */
    808     private boolean mReportedRunning = false;
    809 
    810     /**
    811      * Most recently set source of starting WIFI.
    812      */
    813     private final WorkSource mRunningWifiUids = new WorkSource();
    814 
    815     /**
    816      * The last reported UIDs that were responsible for starting WIFI.
    817      */
    818     private final WorkSource mLastRunningWifiUids = new WorkSource();
    819 
    820     private final IBatteryStats mBatteryStats;
    821 
    822     private BatchedScanSettings mBatchedScanSettings = null;
    823 
    824     /**
    825      * Track the worksource/cost of the current settings and track what's been noted
    826      * to the battery stats, so we can mark the end of the previous when changing.
    827      */
    828     private WorkSource mBatchedScanWorkSource = null;
    829     private int mBatchedScanCsph = 0;
    830     private WorkSource mNotedBatchedScanWorkSource = null;
    831     private int mNotedBatchedScanCsph = 0;
    832 
    833     private String mTcpBufferSizes = null;
    834 
    835     // Used for debug and stats gathering
    836     private static int sScanAlarmIntentCount = 0;
    837 
    838     public WifiStateMachine(Context context, String wlanInterface,
    839             WifiTrafficPoller trafficPoller){
    840         super("WifiStateMachine");
    841         mContext = context;
    842         mInterfaceName = wlanInterface;
    843         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
    844         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
    845                 BatteryStats.SERVICE_NAME));
    846 
    847         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
    848         mNwService = INetworkManagementService.Stub.asInterface(b);
    849 
    850         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
    851                 PackageManager.FEATURE_WIFI_DIRECT);
    852 
    853         mWifiNative = new WifiNative(mInterfaceName);
    854         mWifiConfigStore = new WifiConfigStore(context, mWifiNative);
    855         mWifiAutoJoinController = new WifiAutoJoinController(context, this,
    856                 mWifiConfigStore, mWifiConnectionStatistics, mWifiNative);
    857         mWifiMonitor = new WifiMonitor(this, mWifiNative);
    858         mWifiInfo = new WifiInfo();
    859         mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore,
    860                 getHandler());
    861         mLinkProperties = new LinkProperties();
    862 
    863         IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE);
    864         mWifiP2pServiceImpl = (WifiP2pServiceImpl)IWifiP2pManager.Stub.asInterface(s1);
    865 
    866         mNetworkInfo.setIsAvailable(false);
    867         mLastBssid = null;
    868         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
    869         mLastSignalLevel = -1;
    870 
    871         mNetlinkTracker = new NetlinkTracker(mInterfaceName, new NetlinkTracker.Callback() {
    872             public void update() {
    873                 sendMessage(CMD_UPDATE_LINKPROPERTIES);
    874             }
    875         });
    876         try {
    877             mNwService.registerObserver(mNetlinkTracker);
    878         } catch (RemoteException e) {
    879             loge("Couldn't register netlink tracker: " + e.toString());
    880         }
    881 
    882         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
    883         Intent scanIntent = new Intent(ACTION_START_SCAN, null);
    884         mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
    885 
    886         Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null);
    887         mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0);
    888 
    889         mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger(
    890                 R.integer.config_wifi_framework_scan_interval);
    891 
    892         mDriverStopDelayMs = mContext.getResources().getInteger(
    893                 R.integer.config_wifi_driver_stop_delay);
    894 
    895         mBackgroundScanSupported = mContext.getResources().getBoolean(
    896                 R.bool.config_wifi_background_scan_support);
    897 
    898         mPrimaryDeviceType = mContext.getResources().getString(
    899                 R.string.config_wifi_p2p_device_type);
    900 
    901         mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
    902                     Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
    903 
    904         mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
    905         mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
    906         mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
    907         mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024);
    908         mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024);
    909         // TODO - needs to be a bit more dynamic
    910         mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter);
    911 
    912         mContext.registerReceiver(
    913             new BroadcastReceiver() {
    914                 @Override
    915                 public void onReceive(Context context, Intent intent) {
    916                     ArrayList<String> available = intent.getStringArrayListExtra(
    917                             ConnectivityManager.EXTRA_AVAILABLE_TETHER);
    918                     ArrayList<String> active = intent.getStringArrayListExtra(
    919                             ConnectivityManager.EXTRA_ACTIVE_TETHER);
    920                     sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active));
    921                 }
    922             },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
    923 
    924         mContext.registerReceiver(
    925                 new BroadcastReceiver() {
    926                     @Override
    927                     public void onReceive(Context context, Intent intent) {
    928                         sScanAlarmIntentCount++;
    929                         startScan(SCAN_ALARM_SOURCE, -2, null, null);
    930                         if (VDBG)
    931                             loge("WiFiStateMachine SCAN ALARM");
    932                     }
    933                 },
    934                 new IntentFilter(ACTION_START_SCAN));
    935 
    936         IntentFilter filter = new IntentFilter();
    937         filter.addAction(Intent.ACTION_SCREEN_ON);
    938         filter.addAction(Intent.ACTION_SCREEN_OFF);
    939         filter.addAction(ACTION_REFRESH_BATCHED_SCAN);
    940         mContext.registerReceiver(
    941                 new BroadcastReceiver() {
    942                     @Override
    943                     public void onReceive(Context context, Intent intent) {
    944                         String action = intent.getAction();
    945 
    946                         if (action.equals(Intent.ACTION_SCREEN_ON)) {
    947                             sendMessage(CMD_SCREEN_STATE_CHANGED, 1);
    948                         } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
    949                             sendMessage(CMD_SCREEN_STATE_CHANGED, 0);
    950                         } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) {
    951                             startNextBatchedScanAsync();
    952                         }
    953                     }
    954                 }, filter);
    955 
    956         mContext.registerReceiver(
    957                 new BroadcastReceiver() {
    958                     @Override
    959                     public void onReceive(Context context, Intent intent) {
    960                        int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0);
    961                        sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0);
    962                     }
    963                 },
    964                 new IntentFilter(ACTION_DELAYED_DRIVER_STOP));
    965 
    966         mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
    967                 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false,
    968                 new ContentObserver(getHandler()) {
    969                     @Override
    970                     public void onChange(boolean selfChange) {
    971                         mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
    972                                 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
    973                     }
    974                 });
    975 
    976         mContext.registerReceiver(
    977                 new BroadcastReceiver() {
    978                     @Override
    979                     public void onReceive(Context context, Intent intent) {
    980                         sendMessage(CMD_BOOT_COMPLETED);
    981                     }
    982                 },
    983                 new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
    984 
    985         mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
    986 
    987         PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
    988         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName());
    989 
    990         mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
    991         mSuspendWakeLock.setReferenceCounted(false);
    992 
    993         mTcpBufferSizes = mContext.getResources().getString(
    994                 com.android.internal.R.string.config_wifi_tcp_buffers);
    995 
    996         addState(mDefaultState);
    997             addState(mInitialState, mDefaultState);
    998             addState(mSupplicantStartingState, mDefaultState);
    999             addState(mSupplicantStartedState, mDefaultState);
   1000                 addState(mDriverStartingState, mSupplicantStartedState);
   1001                 addState(mDriverStartedState, mSupplicantStartedState);
   1002                     addState(mScanModeState, mDriverStartedState);
   1003                     addState(mConnectModeState, mDriverStartedState);
   1004                         addState(mL2ConnectedState, mConnectModeState);
   1005                             addState(mObtainingIpState, mL2ConnectedState);
   1006                             addState(mVerifyingLinkState, mL2ConnectedState);
   1007                             addState(mConnectedState, mL2ConnectedState);
   1008                             addState(mRoamingState, mL2ConnectedState);
   1009                         addState(mDisconnectingState, mConnectModeState);
   1010                         addState(mDisconnectedState, mConnectModeState);
   1011                         addState(mWpsRunningState, mConnectModeState);
   1012                 addState(mWaitForP2pDisableState, mSupplicantStartedState);
   1013                 addState(mDriverStoppingState, mSupplicantStartedState);
   1014                 addState(mDriverStoppedState, mSupplicantStartedState);
   1015             addState(mSupplicantStoppingState, mDefaultState);
   1016             addState(mSoftApStartingState, mDefaultState);
   1017             addState(mSoftApStartedState, mDefaultState);
   1018                 addState(mTetheringState, mSoftApStartedState);
   1019                 addState(mTetheredState, mSoftApStartedState);
   1020                 addState(mUntetheringState, mSoftApStartedState);
   1021 
   1022         setInitialState(mInitialState);
   1023 
   1024         setLogRecSize(3000);
   1025         setLogOnlyTransitions(false);
   1026         if (VDBG) setDbg(true);
   1027 
   1028         //start the state machine
   1029         start();
   1030 
   1031         final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
   1032         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1033         intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
   1034         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1035     }
   1036 
   1037     private int mVerboseLoggingLevel = 0;
   1038 
   1039     int getVerboseLoggingLevel() {
   1040         return mVerboseLoggingLevel;
   1041     }
   1042 
   1043     void enableVerboseLogging(int verbose) {
   1044         mVerboseLoggingLevel = verbose;
   1045         if (verbose > 0) {
   1046             DBG = true;
   1047             VDBG = true;
   1048             PDBG = true;
   1049             mLogMessages = true;
   1050             mWifiNative.setSupplicantLogLevel("DEBUG");
   1051         } else {
   1052             DBG = false;
   1053             VDBG = false;
   1054             PDBG = false;
   1055             mLogMessages = false;
   1056             mWifiNative.setSupplicantLogLevel("INFO");
   1057         }
   1058         mWifiAutoJoinController.enableVerboseLogging(verbose);
   1059         mWifiMonitor.enableVerboseLogging(verbose);
   1060         mWifiNative.enableVerboseLogging(verbose);
   1061         mWifiConfigStore.enableVerboseLogging(verbose);
   1062         mSupplicantStateTracker.enableVerboseLogging(verbose);
   1063     }
   1064 
   1065     private int mAggressiveHandover = 0;
   1066 
   1067     int getAggressiveHandover() {
   1068         return mAggressiveHandover;
   1069     }
   1070 
   1071     void enableAggressiveHandover(int enabled) {
   1072         mAggressiveHandover = enabled;
   1073     }
   1074 
   1075     public void setAllowScansWithTraffic(int enabled) {
   1076         mWifiConfigStore.alwaysEnableScansWhileAssociated = enabled;
   1077     }
   1078 
   1079     public int getAllowScansWithTraffic() {
   1080         return mWifiConfigStore.alwaysEnableScansWhileAssociated;
   1081     }
   1082 
   1083     /*
   1084      *
   1085      * Framework scan control
   1086      */
   1087 
   1088     private boolean mAlarmEnabled = false;
   1089     /* This is set from the overlay config file or from a secure setting.
   1090      * A value of 0 disables scanning in the framework.
   1091      */
   1092     private long mFrameworkScanIntervalMs = 10000;
   1093 
   1094     private long mCurrentScanAlarmMs = 10000;
   1095     private void setScanAlarm(boolean enabled, int delayMilli) {
   1096         if (PDBG) {
   1097             loge("setScanAlarm " + enabled
   1098                     + " period " + mCurrentScanAlarmMs
   1099                     + " initial delay " + delayMilli);
   1100         }
   1101         if (mCurrentScanAlarmMs <= 0) enabled = false;
   1102         if (enabled == mAlarmEnabled) return;
   1103         if (enabled) {
   1104             long initialDelayMilli;
   1105             if (delayMilli <= 0) {
   1106                 // scan now
   1107                 startScan(SCAN_ALARM_SOURCE, 0, null, null);
   1108                 initialDelayMilli = mCurrentScanAlarmMs;
   1109             } else {
   1110                 initialDelayMilli = delayMilli;
   1111             }
   1112 
   1113             int type = AlarmManager.RTC;
   1114 
   1115             /* Set RTC_WAKEUP alarms if PNO is not supported - because no one is */
   1116             /* going to wake up the host processor to look for access points */
   1117             if (mBackgroundScanSupported == false)
   1118                 type = AlarmManager.RTC_WAKEUP;
   1119 
   1120             mAlarmManager.setRepeating(type,
   1121                     System.currentTimeMillis() + initialDelayMilli,
   1122                     mCurrentScanAlarmMs,
   1123                     mScanIntent);
   1124             mAlarmEnabled = true;
   1125         } else {
   1126             mAlarmManager.cancel(mScanIntent);
   1127             mAlarmEnabled = false;
   1128         }
   1129     }
   1130 
   1131     private boolean setRandomMacOui() {
   1132         String oui = mContext.getResources().getString(
   1133                 R.string.config_wifi_random_mac_oui, GOOGLE_OUI);
   1134         String[] ouiParts = oui.split("-");
   1135         byte[] ouiBytes = new byte[3];
   1136         ouiBytes[0] = (byte) (Integer.parseInt(ouiParts[0], 16) & 0xFF);
   1137         ouiBytes[1] = (byte) (Integer.parseInt(ouiParts[1], 16) & 0xFF);
   1138         ouiBytes[2] = (byte) (Integer.parseInt(ouiParts[2], 16) & 0xFF);
   1139 
   1140         logd("Setting OUI to " + oui);
   1141         return mWifiNative.setScanningMacOui(ouiBytes);
   1142     }
   1143 
   1144     /*********************************************************
   1145      * Methods exposed for public use
   1146      ********************************************************/
   1147 
   1148     public Messenger getMessenger() {
   1149         return new Messenger(getHandler());
   1150     }
   1151 
   1152     public WifiMonitor getWifiMonitor() {
   1153         return mWifiMonitor;
   1154     }
   1155 
   1156     /**
   1157      * TODO: doc
   1158      */
   1159     public boolean syncPingSupplicant(AsyncChannel channel) {
   1160         Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
   1161         boolean result = (resultMsg.arg1 != FAILURE);
   1162         resultMsg.recycle();
   1163         return result;
   1164     }
   1165 
   1166     public List<WifiChannel> syncGetChannelList(AsyncChannel channel) {
   1167         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ);
   1168         List<WifiChannel> list = null;
   1169         if (resultMsg.obj != null) {
   1170             list = new ArrayList<WifiChannel>();
   1171             String freqs = (String) resultMsg.obj;
   1172             String[] lines = freqs.split("\n");
   1173             for (String line : lines)
   1174                 if (line.contains("MHz")) {
   1175                     // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)"
   1176                     WifiChannel c = new WifiChannel();
   1177                     String[] prop = line.split(" ");
   1178                     if (prop.length < 5) continue;
   1179                     try {
   1180                         c.channelNum = Integer.parseInt(prop[1]);
   1181                         c.freqMHz = Integer.parseInt(prop[3]);
   1182                     } catch (NumberFormatException e) { }
   1183                     c.isDFS = line.contains("(DFS)");
   1184                     list.add(c);
   1185                 } else if (line.contains("Mode[B] Channels:")) {
   1186                     // B channels are the same as G channels, skipped
   1187                     break;
   1188                 }
   1189         }
   1190         resultMsg.recycle();
   1191         return (list != null && list.size() > 0) ? list : null;
   1192     }
   1193 
   1194 
   1195     /**
   1196      * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is
   1197      * given to callingUid.
   1198      *
   1199      * @param callingUid The uid initiating the wifi scan. Blame will be given here unless
   1200      *                   workSource is specified.
   1201      * @param workSource If not null, blame is given to workSource.
   1202      * @param settings Scan settings, see {@link ScanSettings}.
   1203      */
   1204     public void startScan(int callingUid, int scanCounter,
   1205                           ScanSettings settings, WorkSource workSource) {
   1206         Bundle bundle = new Bundle();
   1207         bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
   1208         bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
   1209         bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis());
   1210         sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);
   1211     }
   1212 
   1213     /**
   1214      * start or stop batched scanning using the given settings
   1215      */
   1216     public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph,
   1217             WorkSource workSource) {
   1218         Bundle bundle = new Bundle();
   1219         bundle.putParcelable(BATCHED_SETTING, settings);
   1220         bundle.putParcelable(BATCHED_WORKSOURCE, workSource);
   1221         sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle);
   1222     }
   1223 
   1224     public List<BatchedScanResult> syncGetBatchedScanResultsList() {
   1225         synchronized (mBatchedScanResults) {
   1226             List<BatchedScanResult> batchedScanList =
   1227                     new ArrayList<BatchedScanResult>(mBatchedScanResults.size());
   1228             for(BatchedScanResult result: mBatchedScanResults) {
   1229                 batchedScanList.add(new BatchedScanResult(result));
   1230             }
   1231             return batchedScanList;
   1232         }
   1233     }
   1234 
   1235     public void requestBatchedScanPoll() {
   1236         sendMessage(CMD_POLL_BATCHED_SCAN);
   1237     }
   1238 
   1239     private void startBatchedScan() {
   1240         if (mBatchedScanSettings == null) return;
   1241 
   1242         if (mDhcpActive) {
   1243             if (DBG) log("not starting Batched Scans due to DHCP");
   1244             return;
   1245         }
   1246 
   1247         // first grab any existing data
   1248         retrieveBatchedScanData();
   1249 
   1250         if (PDBG) loge("try  starting Batched Scans due to DHCP");
   1251 
   1252 
   1253         mAlarmManager.cancel(mBatchedScanIntervalIntent);
   1254 
   1255         String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings);
   1256         try {
   1257             mExpectedBatchedScans = Integer.parseInt(scansExpected);
   1258             setNextBatchedAlarm(mExpectedBatchedScans);
   1259             if (mExpectedBatchedScans > 0) noteBatchedScanStart();
   1260         } catch (NumberFormatException e) {
   1261             stopBatchedScan();
   1262             loge("Exception parsing WifiNative.setBatchedScanSettings response " + e);
   1263         }
   1264     }
   1265 
   1266     // called from BroadcastListener
   1267     private void startNextBatchedScanAsync() {
   1268         sendMessage(CMD_START_NEXT_BATCHED_SCAN);
   1269     }
   1270 
   1271     private void startNextBatchedScan() {
   1272         // first grab any existing data
   1273         retrieveBatchedScanData();
   1274 
   1275         setNextBatchedAlarm(mExpectedBatchedScans);
   1276     }
   1277 
   1278     private void handleBatchedScanPollRequest() {
   1279         if (DBG) {
   1280             log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" +
   1281                     mBatchedScanMinPollTime + " , mBatchedScanSettings=" +
   1282                     mBatchedScanSettings);
   1283         }
   1284         // if there is no appropriate PollTime that's because we either aren't
   1285         // batching or we've already set a time for a poll request
   1286         if (mBatchedScanMinPollTime == 0) return;
   1287         if (mBatchedScanSettings == null) return;
   1288 
   1289         long now = System.currentTimeMillis();
   1290 
   1291         if (now > mBatchedScanMinPollTime) {
   1292             // do the poll and reset our timers
   1293             startNextBatchedScan();
   1294         } else {
   1295             mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime,
   1296                     mBatchedScanIntervalIntent);
   1297             mBatchedScanMinPollTime = 0;
   1298         }
   1299     }
   1300 
   1301     // return true if new/different
   1302     private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) {
   1303         BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING);
   1304         WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE);
   1305 
   1306         if (DBG) {
   1307             log("set batched scan to " + settings + " for uid=" + responsibleUid +
   1308                     ", worksource=" + responsibleWorkSource);
   1309         }
   1310         if (settings != null) {
   1311             if (settings.equals(mBatchedScanSettings)) return false;
   1312         } else {
   1313             if (mBatchedScanSettings == null) return false;
   1314         }
   1315         mBatchedScanSettings = settings;
   1316         if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid);
   1317         mBatchedScanWorkSource = responsibleWorkSource;
   1318         mBatchedScanCsph = csph;
   1319         return true;
   1320     }
   1321 
   1322     private void stopBatchedScan() {
   1323         mAlarmManager.cancel(mBatchedScanIntervalIntent);
   1324         retrieveBatchedScanData();
   1325         mWifiNative.setBatchedScanSettings(null);
   1326         noteBatchedScanStop();
   1327     }
   1328 
   1329     private void setNextBatchedAlarm(int scansExpected) {
   1330 
   1331         if (mBatchedScanSettings == null || scansExpected < 1) return;
   1332 
   1333         mBatchedScanMinPollTime = System.currentTimeMillis() +
   1334                 mBatchedScanSettings.scanIntervalSec * 1000;
   1335 
   1336         if (mBatchedScanSettings.maxScansPerBatch < scansExpected) {
   1337             scansExpected = mBatchedScanSettings.maxScansPerBatch;
   1338         }
   1339 
   1340         int secToFull = mBatchedScanSettings.scanIntervalSec;
   1341         secToFull *= scansExpected;
   1342 
   1343         int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0);
   1344         if (debugPeriod > 0) secToFull = debugPeriod;
   1345 
   1346         // set the alarm to do the next poll.  We set it a little short as we'd rather
   1347         // wake up wearly than miss a scan due to buffer overflow
   1348         mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
   1349                 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000),
   1350                 mBatchedScanIntervalIntent);
   1351     }
   1352 
   1353     /**
   1354      * Start reading new scan data
   1355      * Data comes in as:
   1356      * "scancount=5\n"
   1357      * "nextcount=5\n"
   1358      *   "apcount=3\n"
   1359      *   "trunc\n" (optional)
   1360      *     "bssid=...\n"
   1361      *     "ssid=...\n"
   1362      *     "freq=...\n" (in Mhz)
   1363      *     "level=...\n"
   1364      *     "dist=...\n" (in cm)
   1365      *     "distsd=...\n" (standard deviation, in cm)
   1366      *     "===="
   1367      *     "bssid=...\n"
   1368      *     etc
   1369      *     "===="
   1370      *     "bssid=...\n"
   1371      *     etc
   1372      *     "%%%%"
   1373      *   "apcount=2\n"
   1374      *     "bssid=...\n"
   1375      *     etc
   1376      *     "%%%%
   1377      *   etc
   1378      *   "----"
   1379      */
   1380     private final static boolean DEBUG_PARSE = false;
   1381     private void retrieveBatchedScanData() {
   1382         String rawData = mWifiNative.getBatchedScanResults();
   1383         if (DEBUG_PARSE) log("rawData = " + rawData);
   1384         mBatchedScanMinPollTime = 0;
   1385         if (rawData == null || rawData.equalsIgnoreCase("OK")) {
   1386             loge("Unexpected BatchedScanResults :" + rawData);
   1387             return;
   1388         }
   1389 
   1390         int scanCount = 0;
   1391         final String END_OF_BATCHES = "----";
   1392         final String SCANCOUNT = "scancount=";
   1393         final String TRUNCATED = "trunc";
   1394         final String AGE = "age=";
   1395         final String DIST = "dist=";
   1396         final String DISTSD = "distSd=";
   1397 
   1398         String splitData[] = rawData.split("\n");
   1399         int n = 0;
   1400         if (splitData[n].startsWith(SCANCOUNT)) {
   1401             try {
   1402                 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length()));
   1403             } catch (NumberFormatException e) {
   1404                 loge("scancount parseInt Exception from " + splitData[n]);
   1405             }
   1406         } else log("scancount not found");
   1407         if (scanCount == 0) {
   1408             loge("scanCount==0 - aborting");
   1409             return;
   1410         }
   1411 
   1412         final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION);
   1413         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1414 
   1415         synchronized (mBatchedScanResults) {
   1416             mBatchedScanResults.clear();
   1417             BatchedScanResult batchedScanResult = new BatchedScanResult();
   1418 
   1419             String bssid = null;
   1420             WifiSsid wifiSsid = null;
   1421             int level = 0;
   1422             int freq = 0;
   1423             int dist, distSd;
   1424             long tsf = 0;
   1425             dist = distSd = ScanResult.UNSPECIFIED;
   1426             final long now = SystemClock.elapsedRealtime();
   1427             final int bssidStrLen = BSSID_STR.length();
   1428 
   1429             while (true) {
   1430                 while (n < splitData.length) {
   1431                     if (DEBUG_PARSE) logd("parsing " + splitData[n]);
   1432                     if (splitData[n].equals(END_OF_BATCHES)) {
   1433                         if (n+1 != splitData.length) {
   1434                             loge("didn't consume " + (splitData.length-n));
   1435                         }
   1436                         if (mBatchedScanResults.size() > 0) {
   1437                             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   1438                         }
   1439                         logd("retrieveBatchedScanResults X");
   1440                         return;
   1441                     }
   1442                     if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) {
   1443                         if (bssid != null) {
   1444                             batchedScanResult.scanResults.add(new ScanResult(
   1445                                     wifiSsid, bssid, "", level, freq, tsf, dist, distSd));
   1446                             wifiSsid = null;
   1447                             bssid = null;
   1448                             level = 0;
   1449                             freq = 0;
   1450                             tsf = 0;
   1451                             dist = distSd = ScanResult.UNSPECIFIED;
   1452                         }
   1453                         if (splitData[n].equals(END_STR)) {
   1454                             if (batchedScanResult.scanResults.size() != 0) {
   1455                                 mBatchedScanResults.add(batchedScanResult);
   1456                                 batchedScanResult = new BatchedScanResult();
   1457                             } else {
   1458                                 logd("Found empty batch");
   1459                             }
   1460                         }
   1461                     } else if (splitData[n].equals(TRUNCATED)) {
   1462                         batchedScanResult.truncated = true;
   1463                     } else if (splitData[n].startsWith(BSSID_STR)) {
   1464                         bssid = new String(splitData[n].getBytes(), bssidStrLen,
   1465                                 splitData[n].length() - bssidStrLen);
   1466                     } else if (splitData[n].startsWith(FREQ_STR)) {
   1467                         try {
   1468                             freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length()));
   1469                         } catch (NumberFormatException e) {
   1470                             loge("Invalid freqency: " + splitData[n]);
   1471                             freq = 0;
   1472                         }
   1473                     } else if (splitData[n].startsWith(AGE)) {
   1474                         try {
   1475                             tsf = now - Long.parseLong(splitData[n].substring(AGE.length()));
   1476                             tsf *= 1000; // convert mS -> uS
   1477                         } catch (NumberFormatException e) {
   1478                             loge("Invalid timestamp: " + splitData[n]);
   1479                             tsf = 0;
   1480                         }
   1481                     } else if (splitData[n].startsWith(SSID_STR)) {
   1482                         wifiSsid = WifiSsid.createFromAsciiEncoded(
   1483                                 splitData[n].substring(SSID_STR.length()));
   1484                     } else if (splitData[n].startsWith(LEVEL_STR)) {
   1485                         try {
   1486                             level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length()));
   1487                             if (level > 0) level -= 256;
   1488                         } catch (NumberFormatException e) {
   1489                             loge("Invalid level: " + splitData[n]);
   1490                             level = 0;
   1491                         }
   1492                     } else if (splitData[n].startsWith(DIST)) {
   1493                         try {
   1494                             dist = Integer.parseInt(splitData[n].substring(DIST.length()));
   1495                         } catch (NumberFormatException e) {
   1496                             loge("Invalid distance: " + splitData[n]);
   1497                             dist = ScanResult.UNSPECIFIED;
   1498                         }
   1499                     } else if (splitData[n].startsWith(DISTSD)) {
   1500                         try {
   1501                             distSd = Integer.parseInt(splitData[n].substring(DISTSD.length()));
   1502                         } catch (NumberFormatException e) {
   1503                             loge("Invalid distanceSd: " + splitData[n]);
   1504                             distSd = ScanResult.UNSPECIFIED;
   1505                         }
   1506                     } else {
   1507                         loge("Unable to parse batched scan result line: " + splitData[n]);
   1508                     }
   1509                     n++;
   1510                 }
   1511                 rawData = mWifiNative.getBatchedScanResults();
   1512                 if (DEBUG_PARSE) log("reading more data:\n" + rawData);
   1513                 if (rawData == null) {
   1514                     loge("Unexpected null BatchedScanResults");
   1515                     return;
   1516                 }
   1517                 splitData = rawData.split("\n");
   1518                 if (splitData.length == 0 || splitData[0].equals("ok")) {
   1519                     loge("batch scan results just ended!");
   1520                     if (mBatchedScanResults.size() > 0) {
   1521                         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1522                     }
   1523                     return;
   1524                 }
   1525                 n = 0;
   1526             }
   1527         }
   1528     }
   1529 
   1530     private long mDisconnectedTimeStamp = 0;
   1531 
   1532     public long getDisconnectedTimeMilli() {
   1533         if (getCurrentState() == mDisconnectedState
   1534                 && mDisconnectedTimeStamp != 0) {
   1535             long now_ms = System.currentTimeMillis();
   1536             return now_ms - mDisconnectedTimeStamp;
   1537         }
   1538         return 0;
   1539     }
   1540 
   1541     // Keeping track of scan requests
   1542     private long lastStartScanTimeStamp = 0;
   1543     private long lastScanDuration = 0;
   1544     // Last connect attempt is used to prevent scan requests:
   1545     //  - for a period of 10 seconds after attempting to connect
   1546     private long lastConnectAttempt = 0;
   1547     private String lastScanFreqs = null;
   1548 
   1549     // For debugging, keep track of last message status handling
   1550     // TODO, find an equivalent mechanism as part of parent class
   1551     private static int MESSAGE_HANDLING_STATUS_PROCESSED = 2;
   1552     private static int MESSAGE_HANDLING_STATUS_OK = 1;
   1553     private static int MESSAGE_HANDLING_STATUS_UNKNOWN = 0;
   1554     private static int MESSAGE_HANDLING_STATUS_REFUSED = -1;
   1555     private static int MESSAGE_HANDLING_STATUS_FAIL = -2;
   1556     private static int MESSAGE_HANDLING_STATUS_BUFFERED = -3;
   1557     private static int MESSAGE_HANDLING_STATUS_DEFERRED = -4;
   1558     private static int MESSAGE_HANDLING_STATUS_DISCARD = -5;
   1559     private static int MESSAGE_HANDLING_STATUS_LOOPED = -6;
   1560     private static int MESSAGE_HANDLING_STATUS_HANDLING_ERROR = -7;
   1561 
   1562     private int messageHandlingStatus = 0;
   1563 
   1564     //TODO: this is used only to track connection attempts, however the link state and packet per
   1565     //TODO: second logic should be folded into that
   1566     private boolean isScanAllowed() {
   1567         long now = System.currentTimeMillis();
   1568         if (lastConnectAttempt != 0 && (now - lastConnectAttempt) < 10000) {
   1569             return false;
   1570         }
   1571         return true;
   1572     }
   1573 
   1574     private int mOnTime = 0;
   1575     private int mTxTime = 0;
   1576     private int mRxTime = 0;
   1577     private int mOnTimeStartScan = 0;
   1578     private int mTxTimeStartScan = 0;
   1579     private int mRxTimeStartScan = 0;
   1580     private int mOnTimeScan = 0;
   1581     private int mTxTimeScan = 0;
   1582     private int mRxTimeScan = 0;
   1583     private int mOnTimeThisScan = 0;
   1584     private int mTxTimeThisScan = 0;
   1585     private int mRxTimeThisScan = 0;
   1586 
   1587     private int mOnTimeScreenStateChange = 0;
   1588     private int mOnTimeAtLastReport = 0;
   1589     private long lastOntimeReportTimeStamp = 0;
   1590     private long lastScreenStateChangeTimeStamp = 0;
   1591     private int mOnTimeLastReport = 0;
   1592     private int mTxTimeLastReport = 0;
   1593     private int mRxTimeLastReport = 0;
   1594 
   1595     private long lastLinkLayerStatsUpdate = 0;
   1596 
   1597     String reportOnTime() {
   1598         long now = System.currentTimeMillis();
   1599         StringBuilder sb = new StringBuilder();
   1600         // Report stats since last report
   1601         int on = mOnTime - mOnTimeLastReport;
   1602         mOnTimeLastReport = mOnTime;
   1603         int tx = mTxTime - mTxTimeLastReport;
   1604         mTxTimeLastReport = mTxTime;
   1605         int rx = mRxTime - mRxTimeLastReport;
   1606         mRxTimeLastReport = mRxTime;
   1607         int period = (int)(now - lastOntimeReportTimeStamp);
   1608         lastOntimeReportTimeStamp = now;
   1609         sb.append(String.format("[on:%d tx:%d rx:%d period:%d]", on, tx, rx, period));
   1610         // Report stats since Screen State Changed
   1611         on = mOnTime - mOnTimeScreenStateChange;
   1612         period = (int)(now - lastScreenStateChangeTimeStamp);
   1613         sb.append(String.format(" from screen [on:%d period:%d]", on, period));
   1614         return sb.toString();
   1615     }
   1616 
   1617     WifiLinkLayerStats getWifiLinkLayerStats(boolean dbg) {
   1618         WifiLinkLayerStats stats = null;
   1619         if (mWifiLinkLayerStatsSupported > 0) {
   1620             String name = "wlan0";
   1621             stats = mWifiNative.getWifiLinkLayerStats(name);
   1622             if (name != null && stats == null && mWifiLinkLayerStatsSupported > 0) {
   1623                 mWifiLinkLayerStatsSupported -= 1;
   1624             } else if (stats != null) {
   1625                 lastLinkLayerStatsUpdate = System.currentTimeMillis();
   1626                 mOnTime = stats.on_time;
   1627                 mTxTime = stats.tx_time;
   1628                 mRxTime = stats.rx_time;
   1629                 mRunningBeaconCount = stats.beacon_rx;
   1630                 if (dbg) {
   1631                     loge("WifiLinkLayerStats:");
   1632                     loge(stats.toString());
   1633                 }
   1634             }
   1635         }
   1636         return stats;
   1637     }
   1638 
   1639     void startRadioScanStats() {
   1640         WifiLinkLayerStats stats = getWifiLinkLayerStats(false);
   1641         if (stats != null) {
   1642             mOnTimeStartScan = stats.on_time;
   1643             mTxTimeStartScan = stats.tx_time;
   1644             mRxTimeStartScan = stats.rx_time;
   1645             mOnTime = stats.on_time;
   1646             mTxTime = stats.tx_time;
   1647             mRxTime = stats.rx_time;
   1648         }
   1649     }
   1650 
   1651     void closeRadioScanStats() {
   1652         WifiLinkLayerStats stats = getWifiLinkLayerStats(false);
   1653         if (stats != null) {
   1654             mOnTimeThisScan = stats.on_time - mOnTimeStartScan;
   1655             mTxTimeThisScan = stats.tx_time - mTxTimeStartScan;
   1656             mRxTimeThisScan = stats.rx_time - mRxTimeStartScan;
   1657             mOnTimeScan += mOnTimeThisScan;
   1658             mTxTimeScan += mTxTimeThisScan;
   1659             mRxTimeScan += mRxTimeThisScan;
   1660         }
   1661     }
   1662 
   1663     // If workSource is not null, blame is given to it, otherwise blame is given to callingUid.
   1664     private void noteScanStart(int callingUid, WorkSource workSource) {
   1665         long now = System.currentTimeMillis();
   1666         lastStartScanTimeStamp = now;
   1667         lastScanDuration = 0;
   1668         if (DBG) {
   1669             String ts = String.format("[%,d ms]", now);
   1670             if (workSource != null) {
   1671                 loge(ts + " noteScanStart" + workSource.toString()
   1672                         + " uid " + Integer.toString(callingUid));
   1673             } else {
   1674                 loge(ts + " noteScanstart no scan source");
   1675             }
   1676         }
   1677         startRadioScanStats();
   1678         if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE
   1679                 && callingUid != SCAN_ALARM_SOURCE)
   1680                 || workSource != null)) {
   1681             mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid);
   1682             try {
   1683                 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource);
   1684             } catch (RemoteException e) {
   1685                 log(e.toString());
   1686             }
   1687         }
   1688     }
   1689 
   1690     private void noteScanEnd() {
   1691         long now = System.currentTimeMillis();
   1692         if (lastStartScanTimeStamp != 0) {
   1693             lastScanDuration = now - lastStartScanTimeStamp;
   1694         }
   1695         lastStartScanTimeStamp = 0;
   1696         if (DBG) {
   1697             String ts = String.format("[%,d ms]", now);
   1698             if (mScanWorkSource != null)
   1699                 loge(ts + " noteScanEnd " + mScanWorkSource.toString());
   1700             else
   1701                 loge(ts + " noteScanEnd no scan source");
   1702         }
   1703         if (mScanWorkSource != null) {
   1704             try {
   1705                 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource);
   1706             } catch (RemoteException e) {
   1707                 log(e.toString());
   1708             } finally {
   1709                 mScanWorkSource = null;
   1710             }
   1711         }
   1712     }
   1713 
   1714     private void noteBatchedScanStart() {
   1715         if (PDBG) loge("noteBatchedScanstart()");
   1716         // note the end of a previous scan set
   1717         if (mNotedBatchedScanWorkSource != null &&
   1718                 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false ||
   1719                  mNotedBatchedScanCsph != mBatchedScanCsph)) {
   1720             try {
   1721                 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource);
   1722             } catch (RemoteException e) {
   1723                 log(e.toString());
   1724             } finally {
   1725                 mNotedBatchedScanWorkSource = null;
   1726                 mNotedBatchedScanCsph = 0;
   1727             }
   1728         }
   1729         // note the start of the new
   1730         try {
   1731             mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource,
   1732                     mBatchedScanCsph);
   1733             mNotedBatchedScanWorkSource = mBatchedScanWorkSource;
   1734             mNotedBatchedScanCsph = mBatchedScanCsph;
   1735         } catch (RemoteException e) {
   1736             log(e.toString());
   1737         }
   1738     }
   1739 
   1740     private void noteBatchedScanStop() {
   1741         if (PDBG) loge("noteBatchedScanstop()");
   1742 
   1743         if (mNotedBatchedScanWorkSource != null) {
   1744             try {
   1745                 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource);
   1746             } catch (RemoteException e) {
   1747                 log(e.toString());
   1748             } finally {
   1749                 mNotedBatchedScanWorkSource = null;
   1750                 mNotedBatchedScanCsph = 0;
   1751             }
   1752         }
   1753     }
   1754 
   1755     private void handleScanRequest(int type, Message message) {
   1756         // unbundle parameters
   1757         Bundle bundle = (Bundle) message.obj;
   1758         ScanSettings settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING);
   1759         WorkSource workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE);
   1760 
   1761         // parse scan settings
   1762         String freqs = null;
   1763         if (settings != null && settings.channelSet != null) {
   1764             StringBuilder sb = new StringBuilder();
   1765             boolean first = true;
   1766             for (WifiChannel channel : settings.channelSet) {
   1767                 if (!first) sb.append(','); else first = false;
   1768                 sb.append(channel.freqMHz);
   1769             }
   1770             freqs = sb.toString();
   1771         }
   1772 
   1773         // call wifi native to start the scan
   1774         if (startScanNative(type, freqs)) {
   1775             // only count battery consumption if scan request is accepted
   1776             noteScanStart(message.arg1, workSource);
   1777             // a full scan covers everything, clearing scan request buffer
   1778             if (freqs == null)
   1779                 mBufferedScanMsg.clear();
   1780             messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
   1781             return;
   1782         }
   1783 
   1784         // if reach here, scan request is rejected
   1785 
   1786         if (!mIsScanOngoing) {
   1787             // if rejection is NOT due to ongoing scan (e.g. bad scan parameters),
   1788 
   1789             // discard this request and pop up the next one
   1790             if (mBufferedScanMsg.size() > 0) {
   1791                 sendMessage(mBufferedScanMsg.remove());
   1792             }
   1793             messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   1794         } else if (!mIsFullScanOngoing) {
   1795             // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan,
   1796             // buffer the scan request to make sure specified channels will be scanned eventually
   1797             if (freqs == null)
   1798                 mBufferedScanMsg.clear();
   1799             if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) {
   1800                 Message msg = obtainMessage(CMD_START_SCAN,
   1801                         message.arg1, message.arg2, bundle);
   1802                 mBufferedScanMsg.add(msg);
   1803             } else {
   1804                 // if too many requests in buffer, combine them into a single full scan
   1805                 bundle = new Bundle();
   1806                 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null);
   1807                 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
   1808                 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle);
   1809                 mBufferedScanMsg.clear();
   1810                 mBufferedScanMsg.add(msg);
   1811             }
   1812             messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED;
   1813         } else {
   1814             // mIsScanOngoing and mIsFullScanOngoing
   1815             messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   1816         }
   1817     }
   1818 
   1819 
   1820     /** return true iff scan request is accepted */
   1821     private boolean startScanNative(int type, String freqs) {
   1822         if (mWifiNative.scan(type, freqs)) {
   1823             mIsScanOngoing = true;
   1824             mIsFullScanOngoing = (freqs == null);
   1825             lastScanFreqs = freqs;
   1826             return true;
   1827         }
   1828         return false;
   1829     }
   1830 
   1831     /**
   1832      * TODO: doc
   1833      */
   1834     public void setSupplicantRunning(boolean enable) {
   1835         if (enable) {
   1836             sendMessage(CMD_START_SUPPLICANT);
   1837         } else {
   1838             sendMessage(CMD_STOP_SUPPLICANT);
   1839         }
   1840     }
   1841 
   1842     /**
   1843      * TODO: doc
   1844      */
   1845     public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
   1846         if (enable) {
   1847             sendMessage(CMD_START_AP, wifiConfig);
   1848         } else {
   1849             sendMessage(CMD_STOP_AP);
   1850         }
   1851     }
   1852 
   1853     public void setWifiApConfiguration(WifiConfiguration config) {
   1854         mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
   1855     }
   1856 
   1857     public WifiConfiguration syncGetWifiApConfiguration() {
   1858         Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
   1859         WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
   1860         resultMsg.recycle();
   1861         return ret;
   1862     }
   1863 
   1864     /**
   1865      * TODO: doc
   1866      */
   1867     public int syncGetWifiState() {
   1868         return mWifiState.get();
   1869     }
   1870 
   1871     /**
   1872      * TODO: doc
   1873      */
   1874     public String syncGetWifiStateByName() {
   1875         switch (mWifiState.get()) {
   1876             case WIFI_STATE_DISABLING:
   1877                 return "disabling";
   1878             case WIFI_STATE_DISABLED:
   1879                 return "disabled";
   1880             case WIFI_STATE_ENABLING:
   1881                 return "enabling";
   1882             case WIFI_STATE_ENABLED:
   1883                 return "enabled";
   1884             case WIFI_STATE_UNKNOWN:
   1885                 return "unknown state";
   1886             default:
   1887                 return "[invalid state]";
   1888         }
   1889     }
   1890 
   1891     /**
   1892      * TODO: doc
   1893      */
   1894     public int syncGetWifiApState() {
   1895         return mWifiApState.get();
   1896     }
   1897 
   1898     /**
   1899      * TODO: doc
   1900      */
   1901     public String syncGetWifiApStateByName() {
   1902         switch (mWifiApState.get()) {
   1903             case WIFI_AP_STATE_DISABLING:
   1904                 return "disabling";
   1905             case WIFI_AP_STATE_DISABLED:
   1906                 return "disabled";
   1907             case WIFI_AP_STATE_ENABLING:
   1908                 return "enabling";
   1909             case WIFI_AP_STATE_ENABLED:
   1910                 return "enabled";
   1911             case WIFI_AP_STATE_FAILED:
   1912                 return "failed";
   1913             default:
   1914                 return "[invalid state]";
   1915         }
   1916     }
   1917 
   1918     /**
   1919      * Get status information for the current connection, if any.
   1920      * @return a {@link WifiInfo} object containing information about the current connection
   1921      *
   1922      */
   1923     public WifiInfo syncRequestConnectionInfo() {
   1924         return mWifiInfo;
   1925     }
   1926 
   1927     public DhcpResults syncGetDhcpResults() {
   1928         synchronized (mDhcpResultsLock) {
   1929             return new DhcpResults(mDhcpResults);
   1930         }
   1931     }
   1932 
   1933     /**
   1934      * TODO: doc
   1935      */
   1936     public void setDriverStart(boolean enable) {
   1937         if (enable) {
   1938             sendMessage(CMD_START_DRIVER);
   1939         } else {
   1940             sendMessage(CMD_STOP_DRIVER);
   1941         }
   1942     }
   1943 
   1944     /**
   1945      * TODO: doc
   1946      */
   1947     public void setOperationalMode(int mode) {
   1948         if (DBG) log("setting operational mode to " + String.valueOf(mode));
   1949         sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
   1950     }
   1951 
   1952     /**
   1953      * TODO: doc
   1954      */
   1955     public List<ScanResult> syncGetScanResultsList() {
   1956         synchronized (mScanResultCache) {
   1957             List<ScanResult> scanList = new ArrayList<ScanResult>();
   1958             for(ScanResult result: mScanResults) {
   1959                 scanList.add(new ScanResult(result));
   1960             }
   1961             return scanList;
   1962         }
   1963     }
   1964 
   1965     /**
   1966      * Get unsynchronized pointer to scan result list
   1967      * Can be called only from AutoJoinController which runs in the WifiStateMachine context
   1968      */
   1969     public List<ScanResult> getScanResultsListNoCopyUnsync() {
   1970         return mScanResults;
   1971     }
   1972 
   1973     /**
   1974      * Disconnect from Access Point
   1975      */
   1976     public void disconnectCommand() {
   1977         sendMessage(CMD_DISCONNECT);
   1978     }
   1979 
   1980     /**
   1981      * Initiate a reconnection to AP
   1982      */
   1983     public void reconnectCommand() {
   1984         sendMessage(CMD_RECONNECT);
   1985     }
   1986 
   1987     /**
   1988      * Initiate a re-association to AP
   1989      */
   1990     public void reassociateCommand() {
   1991         sendMessage(CMD_REASSOCIATE);
   1992     }
   1993 
   1994     /**
   1995      * Reload networks and then reconnect; helps load correct data for TLS networks
   1996      */
   1997 
   1998     public void reloadTlsNetworksAndReconnect() {
   1999         sendMessage(CMD_RELOAD_TLS_AND_RECONNECT);
   2000     }
   2001 
   2002     /**
   2003      * Add a network synchronously
   2004      *
   2005      * @return network id of the new network
   2006      */
   2007     public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
   2008         Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
   2009         int result = resultMsg.arg1;
   2010         resultMsg.recycle();
   2011         return result;
   2012     }
   2013 
   2014     /**
   2015      * Get configured networks synchronously
   2016      * @param channel
   2017      * @return
   2018      */
   2019 
   2020     public List<WifiConfiguration> syncGetConfiguredNetworks(int uuid, AsyncChannel channel) {
   2021         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS, uuid);
   2022         List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
   2023         resultMsg.recycle();
   2024         return result;
   2025     }
   2026 
   2027     public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) {
   2028         Message resultMsg = channel.sendMessageSynchronously(
   2029                 CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS);
   2030         List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
   2031         resultMsg.recycle();
   2032         return result;
   2033     }
   2034 
   2035 
   2036     /**
   2037      * Get connection statistics synchronously
   2038      * @param channel
   2039      * @return
   2040      */
   2041 
   2042     public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) {
   2043         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS);
   2044         WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj;
   2045         resultMsg.recycle();
   2046         return result;
   2047     }
   2048 
   2049     /**
   2050      * Get adaptors synchronously
   2051      */
   2052 
   2053     public int syncGetSupportedFeatures(AsyncChannel channel) {
   2054         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_SUPPORTED_FEATURES);
   2055         int supportedFeatureSet = resultMsg.arg1;
   2056         resultMsg.recycle();
   2057         return supportedFeatureSet;
   2058     }
   2059 
   2060     /**
   2061      * Get link layers stats for adapter synchronously
   2062      */
   2063     public WifiLinkLayerStats syncGetLinkLayerStats(AsyncChannel channel) {
   2064         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_LINK_LAYER_STATS);
   2065         WifiLinkLayerStats result = (WifiLinkLayerStats) resultMsg.obj;
   2066         resultMsg.recycle();
   2067         return result;
   2068     }
   2069 
   2070     /**
   2071      * Delete a network
   2072      *
   2073      * @param networkId id of the network to be removed
   2074      */
   2075     public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
   2076         Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
   2077         boolean result = (resultMsg.arg1 != FAILURE);
   2078         resultMsg.recycle();
   2079         return result;
   2080     }
   2081 
   2082     /**
   2083      * Enable a network
   2084      *
   2085      * @param netId network id of the network
   2086      * @param disableOthers true, if all other networks have to be disabled
   2087      * @return {@code true} if the operation succeeds, {@code false} otherwise
   2088      */
   2089     public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
   2090         Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
   2091                 disableOthers ? 1 : 0);
   2092         boolean result = (resultMsg.arg1 != FAILURE);
   2093         resultMsg.recycle();
   2094         return result;
   2095     }
   2096 
   2097     /**
   2098      * Disable a network
   2099      *
   2100      * @param netId network id of the network
   2101      * @return {@code true} if the operation succeeds, {@code false} otherwise
   2102      */
   2103     public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
   2104         Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId);
   2105         boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED);
   2106         resultMsg.recycle();
   2107         return result;
   2108     }
   2109 
   2110     /**
   2111      * Retrieves a WPS-NFC configuration token for the specified network
   2112      * @return a hex string representation of the WPS-NFC configuration token
   2113      */
   2114     public String syncGetWpsNfcConfigurationToken(int netId) {
   2115         return mWifiNative.getNfcWpsConfigurationToken(netId);
   2116     }
   2117 
   2118     /**
   2119      * Blacklist a BSSID. This will avoid the AP if there are
   2120      * alternate APs to connect
   2121      *
   2122      * @param bssid BSSID of the network
   2123      */
   2124     public void addToBlacklist(String bssid) {
   2125         sendMessage(CMD_BLACKLIST_NETWORK, bssid);
   2126     }
   2127 
   2128     /**
   2129      * Clear the blacklist list
   2130      *
   2131      */
   2132     public void clearBlacklist() {
   2133         sendMessage(CMD_CLEAR_BLACKLIST);
   2134     }
   2135 
   2136     public void enableRssiPolling(boolean enabled) {
   2137        sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
   2138     }
   2139 
   2140     public void enableAllNetworks() {
   2141         sendMessage(CMD_ENABLE_ALL_NETWORKS);
   2142     }
   2143 
   2144     /**
   2145      * Start filtering Multicast v4 packets
   2146      */
   2147     public void startFilteringMulticastV4Packets() {
   2148         mFilteringMulticastV4Packets.set(true);
   2149         sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0);
   2150     }
   2151 
   2152     /**
   2153      * Stop filtering Multicast v4 packets
   2154      */
   2155     public void stopFilteringMulticastV4Packets() {
   2156         mFilteringMulticastV4Packets.set(false);
   2157         sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0);
   2158     }
   2159 
   2160     /**
   2161      * Start filtering Multicast v4 packets
   2162      */
   2163     public void startFilteringMulticastV6Packets() {
   2164         sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0);
   2165     }
   2166 
   2167     /**
   2168      * Stop filtering Multicast v4 packets
   2169      */
   2170     public void stopFilteringMulticastV6Packets() {
   2171         sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0);
   2172     }
   2173 
   2174     /**
   2175      * Set high performance mode of operation.
   2176      * Enabling would set active power mode and disable suspend optimizations;
   2177      * disabling would set auto power mode and enable suspend optimizations
   2178      * @param enable true if enable, false otherwise
   2179      */
   2180     public void setHighPerfModeEnabled(boolean enable) {
   2181         sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);
   2182     }
   2183 
   2184     /**
   2185      * Set the country code
   2186      * @param countryCode following ISO 3166 format
   2187      * @param persist {@code true} if the setting should be remembered.
   2188      */
   2189     public void setCountryCode(String countryCode, boolean persist) {
   2190         // If it's a good country code, apply after the current
   2191         // wifi connection is terminated; ignore resetting of code
   2192         // for now (it is unclear what the chipset should do when
   2193         // country code is reset)
   2194         int countryCodeSequence = mCountryCodeSequence.incrementAndGet();
   2195         if (TextUtils.isEmpty(countryCode)) {
   2196             log("Ignoring resetting of country code");
   2197         } else {
   2198             sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode);
   2199         }
   2200     }
   2201 
   2202     /**
   2203      * Set the operational frequency band
   2204      * @param band
   2205      * @param persist {@code true} if the setting should be remembered.
   2206      */
   2207     public void setFrequencyBand(int band, boolean persist) {
   2208         if (persist) {
   2209             Settings.Global.putInt(mContext.getContentResolver(),
   2210                     Settings.Global.WIFI_FREQUENCY_BAND,
   2211                     band);
   2212         }
   2213         sendMessage(CMD_SET_FREQUENCY_BAND, band, 0);
   2214     }
   2215 
   2216     /**
   2217      * Enable TDLS for a specific MAC address
   2218      */
   2219     public void enableTdls(String remoteMacAddress, boolean enable) {
   2220         int enabler = enable ? 1 : 0;
   2221         sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress);
   2222     }
   2223 
   2224     /**
   2225      * Returns the operational frequency band
   2226      */
   2227     public int getFrequencyBand() {
   2228         return mFrequencyBand.get();
   2229     }
   2230 
   2231     /**
   2232      * Returns the wifi configuration file
   2233      */
   2234     public String getConfigFile() {
   2235         return mWifiConfigStore.getConfigFile();
   2236     }
   2237 
   2238     /**
   2239      * Send a message indicating bluetooth adapter connection state changed
   2240      */
   2241     public void sendBluetoothAdapterStateChange(int state) {
   2242         sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0);
   2243     }
   2244 
   2245     /**
   2246      * Save configuration on supplicant
   2247      *
   2248      * @return {@code true} if the operation succeeds, {@code false} otherwise
   2249      *
   2250      * TODO: deprecate this
   2251      */
   2252     public boolean syncSaveConfig(AsyncChannel channel) {
   2253         Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
   2254         boolean result = (resultMsg.arg1 != FAILURE);
   2255         resultMsg.recycle();
   2256         return result;
   2257     }
   2258 
   2259     public void updateBatteryWorkSource(WorkSource newSource) {
   2260         synchronized (mRunningWifiUids) {
   2261             try {
   2262                 if (newSource != null) {
   2263                     mRunningWifiUids.set(newSource);
   2264                 }
   2265                 if (mIsRunning) {
   2266                     if (mReportedRunning) {
   2267                         // If the work source has changed since last time, need
   2268                         // to remove old work from battery stats.
   2269                         if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
   2270                             mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
   2271                                     mRunningWifiUids);
   2272                             mLastRunningWifiUids.set(mRunningWifiUids);
   2273                         }
   2274                     } else {
   2275                         // Now being started, report it.
   2276                         mBatteryStats.noteWifiRunning(mRunningWifiUids);
   2277                         mLastRunningWifiUids.set(mRunningWifiUids);
   2278                         mReportedRunning = true;
   2279                     }
   2280                 } else {
   2281                     if (mReportedRunning) {
   2282                         // Last reported we were running, time to stop.
   2283                         mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
   2284                         mLastRunningWifiUids.clear();
   2285                         mReportedRunning = false;
   2286                     }
   2287                 }
   2288                 mWakeLock.setWorkSource(newSource);
   2289             } catch (RemoteException ignore) {
   2290             }
   2291         }
   2292     }
   2293 
   2294     @Override
   2295     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2296         super.dump(fd, pw, args);
   2297         mSupplicantStateTracker.dump(fd, pw, args);
   2298         pw.println("mLinkProperties " + mLinkProperties);
   2299         pw.println("mWifiInfo " + mWifiInfo);
   2300         pw.println("mDhcpResults " + mDhcpResults);
   2301         pw.println("mNetworkInfo " + mNetworkInfo);
   2302         pw.println("mLastSignalLevel " + mLastSignalLevel);
   2303         pw.println("mLastBssid " + mLastBssid);
   2304         pw.println("mLastNetworkId " + mLastNetworkId);
   2305         pw.println("mOperationalMode " + mOperationalMode);
   2306         pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
   2307         pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
   2308         pw.println("Supplicant status " + mWifiNative.status(true));
   2309         pw.println("mEnableBackgroundScan " + mEnableBackgroundScan);
   2310         pw.println("mLastSetCountryCode " + mLastSetCountryCode);
   2311         pw.println("mPersistedCountryCode " + mPersistedCountryCode);
   2312         pw.println();
   2313         mWifiConfigStore.dump(fd, pw, args);
   2314     }
   2315 
   2316     /*********************************************************
   2317      * Internal private functions
   2318      ********************************************************/
   2319 
   2320     private void logStateAndMessage(Message message, String state) {
   2321         messageHandlingStatus = 0;
   2322         if (mLogMessages) {
   2323             //long now = SystemClock.elapsedRealtimeNanos();
   2324             //String ts = String.format("[%,d us]", now/1000);
   2325 
   2326             loge( " " + state + " " + getLogRecString(message));
   2327         }
   2328     }
   2329 
   2330     /**
   2331      * Return the additional string to be logged by LogRec, default
   2332      *
   2333      * @param msg that was processed
   2334      * @return information to be logged as a String
   2335      */
   2336     protected String getLogRecString(Message msg) {
   2337         WifiConfiguration config;
   2338         Long now;
   2339         long milli;
   2340         String report;
   2341         StringBuilder sb = new StringBuilder();
   2342         if (mScreenOn) {
   2343             sb.append("!");
   2344         }
   2345         if (messageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) {
   2346             sb.append("(").append(messageHandlingStatus).append(")");
   2347         }
   2348         sb.append(smToString(msg));
   2349         if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) {
   2350             sb.append(" uid=" + msg.sendingUid);
   2351         }
   2352         switch (msg.what) {
   2353             case CMD_START_SCAN:
   2354                 now = System.currentTimeMillis();
   2355                 sb.append(" ");
   2356                 sb.append(Integer.toString(msg.arg1));
   2357                 sb.append(" ");
   2358                 sb.append(Integer.toString(msg.arg2));
   2359                 sb.append(" ic=");
   2360                 sb.append(Integer.toString(sScanAlarmIntentCount));
   2361                 if (msg.obj != null) {
   2362                     Bundle bundle = (Bundle)msg.obj;
   2363                     Long request = bundle.getLong(SCAN_REQUEST_TIME, 0);
   2364                     if (request != 0) {
   2365                         sb.append(" proc(ms):").append(now - request);
   2366                     }
   2367                 }
   2368                 if (mIsScanOngoing) sb.append(" onGoing");
   2369                 if (mIsFullScanOngoing) sb.append(" full");
   2370                 if (lastStartScanTimeStamp != 0) {
   2371                     sb.append(" started:").append(lastStartScanTimeStamp);
   2372                     sb.append(",").append(now - lastStartScanTimeStamp);
   2373                 }
   2374                 if (lastScanDuration != 0) {
   2375                     sb.append(" dur:").append(lastScanDuration);
   2376                 }
   2377                 sb.append(" rssi=").append(mWifiInfo.getRssi());
   2378                 sb.append(" f=").append(mWifiInfo.getFrequency());
   2379                 sb.append(" sc=").append(mWifiInfo.score);
   2380                 sb.append(" link=").append(mWifiInfo.getLinkSpeed());
   2381                 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
   2382                 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
   2383                 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
   2384                 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
   2385                 if (lastScanFreqs != null) {
   2386                     sb.append(" list=").append(lastScanFreqs);
   2387                 } else {
   2388                     sb.append(" fiv=").append(fullBandConnectedTimeIntervalMilli);
   2389                 }
   2390                 report = reportOnTime();
   2391                 if (report != null) {
   2392                     sb.append(" ").append(report);
   2393                 }
   2394                 break;
   2395             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   2396                 milli = SystemClock.elapsedRealtime();
   2397                 sb.append(" ");
   2398                 sb.append(Integer.toString(msg.arg1));
   2399                 sb.append(" ");
   2400                 sb.append(Integer.toString(msg.arg2));
   2401                 sb.append(" rt=").append(milli).append(" ");
   2402                 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
   2403                 if (stateChangeResult != null) {
   2404                     sb.append(stateChangeResult.toString());
   2405                 }
   2406                 break;
   2407             case WifiManager.SAVE_NETWORK:
   2408             case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
   2409                 sb.append(" ");
   2410                 sb.append(Integer.toString(msg.arg1));
   2411                 sb.append(" ");
   2412                 sb.append(Integer.toString(msg.arg2));
   2413                 if (lastSavedConfigurationAttempt != null) {
   2414                     sb.append(" ").append(lastSavedConfigurationAttempt.configKey());
   2415                     sb.append(" nid=").append(lastSavedConfigurationAttempt.networkId);
   2416                     if (lastSavedConfigurationAttempt.hiddenSSID) {
   2417                         sb.append(" hidden");
   2418                     }
   2419                     if (lastSavedConfigurationAttempt.preSharedKey != null
   2420                             && !lastSavedConfigurationAttempt.preSharedKey.equals("*")) {
   2421                         sb.append(" hasPSK");
   2422                     }
   2423                     if (lastSavedConfigurationAttempt.ephemeral) {
   2424                         sb.append(" ephemeral");
   2425                     }
   2426                     if (lastSavedConfigurationAttempt.selfAdded) {
   2427                         sb.append(" selfAdded");
   2428                     }
   2429                     sb.append(" cuid=").append(lastSavedConfigurationAttempt.creatorUid);
   2430                     sb.append(" suid=").append(lastSavedConfigurationAttempt.lastUpdateUid);
   2431                 }
   2432                 break;
   2433             case WifiManager.FORGET_NETWORK:
   2434                 sb.append(" ");
   2435                 sb.append(Integer.toString(msg.arg1));
   2436                 sb.append(" ");
   2437                 sb.append(Integer.toString(msg.arg2));
   2438                 if (lastForgetConfigurationAttempt != null) {
   2439                     sb.append(" ").append(lastForgetConfigurationAttempt.configKey());
   2440                     sb.append(" nid=").append(lastForgetConfigurationAttempt.networkId);
   2441                     if (lastForgetConfigurationAttempt.hiddenSSID) {
   2442                         sb.append(" hidden");
   2443                     }
   2444                     if (lastForgetConfigurationAttempt.preSharedKey != null) {
   2445                         sb.append(" hasPSK");
   2446                     }
   2447                     if (lastForgetConfigurationAttempt.ephemeral) {
   2448                         sb.append(" ephemeral");
   2449                     }
   2450                     if (lastForgetConfigurationAttempt.selfAdded) {
   2451                         sb.append(" selfAdded");
   2452                     }
   2453                     sb.append(" cuid=").append(lastForgetConfigurationAttempt.creatorUid);
   2454                     sb.append(" suid=").append(lastForgetConfigurationAttempt.lastUpdateUid);
   2455                     sb.append(" ajst=").append(lastForgetConfigurationAttempt.autoJoinStatus);
   2456                 }
   2457                 break;
   2458             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   2459                 sb.append(" ");
   2460                 sb.append(Integer.toString(msg.arg1));
   2461                 sb.append(" ");
   2462                 sb.append(Integer.toString(msg.arg2));
   2463                 String bssid = (String)msg.obj;
   2464                 if (bssid != null && bssid.length()>0) {
   2465                     sb.append(" ");
   2466                     sb.append(bssid);
   2467                 }
   2468                 sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID));
   2469                 milli = SystemClock.elapsedRealtime();
   2470                 sb.append(" rt=").append(milli);
   2471                 break;
   2472             case WifiMonitor.SCAN_RESULTS_EVENT:
   2473                 sb.append(" ");
   2474                 sb.append(Integer.toString(msg.arg1));
   2475                 sb.append(" ");
   2476                 sb.append(Integer.toString(msg.arg2));
   2477                 if (mScanResults != null) {
   2478                     sb.append(" found=");
   2479                     sb.append(mScanResults.size());
   2480                 }
   2481                 sb.append(" known=").append(mNumScanResultsKnown);
   2482                 sb.append(" got=").append(mNumScanResultsReturned);
   2483                 if (lastScanDuration != 0) {
   2484                     sb.append(" dur:").append(lastScanDuration);
   2485                 }
   2486                 if (mOnTime != 0) {
   2487                     sb.append(" on:").append(mOnTimeThisScan).append(",").append(mOnTimeScan);
   2488                     sb.append(",").append(mOnTime);
   2489                 }
   2490                 if (mTxTime != 0) {
   2491                     sb.append(" tx:").append(mTxTimeThisScan).append(",").append(mTxTimeScan);
   2492                     sb.append(",").append(mTxTime);
   2493                 }
   2494                 if (mRxTime != 0) {
   2495                     sb.append(" rx:").append(mRxTimeThisScan).append(",").append(mRxTimeScan);
   2496                     sb.append(",").append(mRxTime);
   2497                 }
   2498                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
   2499                 break;
   2500             case WifiMonitor.NETWORK_CONNECTION_EVENT:
   2501                 sb.append(" ");
   2502                 sb.append(Integer.toString(msg.arg1));
   2503                 sb.append(" ");
   2504                 sb.append(Integer.toString(msg.arg2));
   2505                 sb.append(" ").append(mLastBssid);
   2506                 sb.append(" nid=").append(mLastNetworkId);
   2507                 config = getCurrentWifiConfiguration();
   2508                 if (config != null) {
   2509                     sb.append(" ").append(config.configKey());
   2510                 }
   2511                 milli = SystemClock.elapsedRealtime();
   2512                 sb.append(" rt=").append(milli);
   2513                 break;
   2514             case CMD_TARGET_BSSID:
   2515             case CMD_ASSOCIATED_BSSID:
   2516                 sb.append(" ");
   2517                 sb.append(Integer.toString(msg.arg1));
   2518                 sb.append(" ");
   2519                 sb.append(Integer.toString(msg.arg2));
   2520                 if (msg.obj != null) {
   2521                     sb.append(" BSSID=").append((String)msg.obj);
   2522                 }
   2523                 if (mTargetRoamBSSID != null) {
   2524                     sb.append(" Target=").append(mTargetRoamBSSID);
   2525                 }
   2526                 sb.append(" roam=").append(Integer.toString(mAutoRoaming));
   2527                 milli = SystemClock.elapsedRealtime();
   2528                 sb.append(" rt=").append(milli);
   2529                 break;
   2530             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   2531                 if (msg.obj != null) {
   2532                     sb.append(" ").append((String)msg.obj);
   2533                 }
   2534                 sb.append(" nid=").append(msg.arg1);
   2535                 sb.append(" reason=").append(msg.arg2);
   2536                 if (mLastBssid != null) {
   2537                     sb.append(" lastbssid=").append(mLastBssid);
   2538                 }
   2539                 if (mWifiInfo.getFrequency() != -1) {
   2540                     sb.append(" freq=").append(mWifiInfo.getFrequency());
   2541                     sb.append(" rssi=").append(mWifiInfo.getRssi());
   2542                 }
   2543                 if (linkDebouncing) {
   2544                     sb.append(" debounce");
   2545                 }
   2546                 milli = SystemClock.elapsedRealtime();
   2547                 sb.append(" rt=").append(milli);
   2548                 break;
   2549             case WifiMonitor.SSID_TEMP_DISABLED:
   2550             case WifiMonitor.SSID_REENABLED:
   2551                 sb.append(" nid=").append(msg.arg1);
   2552                 if (msg.obj != null) {
   2553                     sb.append(" ").append((String)msg.obj);
   2554                 }
   2555                 config = getCurrentWifiConfiguration();
   2556                 if (config != null) {
   2557                     sb.append(" cur=").append(config.configKey());
   2558                     sb.append(" ajst=").append(config.autoJoinStatus);
   2559                     if (config.selfAdded) {
   2560                         sb.append(" selfAdded");
   2561                     }
   2562                     if (config.status != 0) {
   2563                         sb.append(" st=").append(config.status);
   2564                         sb.append(" rs=").append(config.disableReason);
   2565                     }
   2566                     if (config.lastConnected != 0) {
   2567                         now = System.currentTimeMillis();
   2568                         sb.append(" lastconn=").append(now - config.lastConnected).append("(ms)");
   2569                     }
   2570                     if (mLastBssid != null) {
   2571                         sb.append(" lastbssid=").append(mLastBssid);
   2572                     }
   2573                     if (mWifiInfo.getFrequency() != -1) {
   2574                         sb.append(" freq=").append(mWifiInfo.getFrequency());
   2575                         sb.append(" rssi=").append(mWifiInfo.getRssi());
   2576                         sb.append(" bssid=").append(mWifiInfo.getBSSID());
   2577                     }
   2578                 }
   2579                 milli = SystemClock.elapsedRealtime();
   2580                 sb.append(" rt=").append(milli);
   2581                 break;
   2582             case CMD_RSSI_POLL:
   2583             case CMD_UNWANTED_NETWORK:
   2584             case WifiManager.RSSI_PKTCNT_FETCH:
   2585                 sb.append(" ");
   2586                 sb.append(Integer.toString(msg.arg1));
   2587                 sb.append(" ");
   2588                 sb.append(Integer.toString(msg.arg2));
   2589                 if (mWifiInfo.getSSID() != null)
   2590                 if (mWifiInfo.getSSID() != null)
   2591                     sb.append(" ").append(mWifiInfo.getSSID());
   2592                 if (mWifiInfo.getBSSID() != null)
   2593                     sb.append(" ").append(mWifiInfo.getBSSID());
   2594                 sb.append(" rssi=").append(mWifiInfo.getRssi());
   2595                 sb.append(" f=").append(mWifiInfo.getFrequency());
   2596                 sb.append(" sc=").append(mWifiInfo.score);
   2597                 sb.append(" link=").append(mWifiInfo.getLinkSpeed());
   2598                 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
   2599                 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
   2600                 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
   2601                 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
   2602                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
   2603                 report = reportOnTime();
   2604                 if (report != null) {
   2605                     sb.append(" ").append(report);
   2606                 }
   2607                 if (wifiScoringReport != null) {
   2608                     sb.append(wifiScoringReport);
   2609                 }
   2610                 break;
   2611             case CMD_AUTO_CONNECT:
   2612             case WifiManager.CONNECT_NETWORK:
   2613                 sb.append(" ");
   2614                 sb.append(Integer.toString(msg.arg1));
   2615                 sb.append(" ");
   2616                 sb.append(Integer.toString(msg.arg2));
   2617                 config = (WifiConfiguration) msg.obj;
   2618                 if (config != null) {
   2619                     sb.append(" ").append(config.configKey());
   2620                     if (config.visibility != null) {
   2621                         sb.append(" [").append(config.visibility.num24);
   2622                         sb.append(" ,").append(config.visibility.rssi24);
   2623                         sb.append(" ;").append(config.visibility.num5);
   2624                         sb.append(" ,").append(config.visibility.rssi5).append("]");
   2625                     }
   2626                 }
   2627                 if (mTargetRoamBSSID != null) {
   2628                     sb.append(" ").append(mTargetRoamBSSID);
   2629                 }
   2630                 sb.append(" roam=").append(Integer.toString(mAutoRoaming));
   2631                 milli = SystemClock.elapsedRealtime();
   2632                 sb.append(" rt=").append(milli);
   2633                 config = getCurrentWifiConfiguration();
   2634                 if (config != null) {
   2635                     sb.append(" ").append(config.configKey());
   2636                     if (config.visibility != null) {
   2637                         sb.append(" [").append(config.visibility.num24);
   2638                         sb.append(" ,").append(config.visibility.rssi24);
   2639                         sb.append(" ;").append(config.visibility.num5);
   2640                         sb.append(" ,").append(config.visibility.rssi5).append("]");
   2641                     }
   2642                 }
   2643                 break;
   2644             case CMD_AUTO_ROAM:
   2645                 sb.append(" ");
   2646                 sb.append(Integer.toString(msg.arg1));
   2647                 sb.append(" ");
   2648                 sb.append(Integer.toString(msg.arg2));
   2649                 ScanResult result = (ScanResult)msg.obj;
   2650                 if (result != null) {
   2651                     now = System.currentTimeMillis();
   2652                     sb.append(" bssid=").append(result.BSSID);
   2653                     sb.append(" rssi=").append(result.level);
   2654                     sb.append(" freq=").append(result.frequency);
   2655                     if (result.seen > 0 && result.seen < now) {
   2656                         sb.append(" seen=").append(now - result.seen);
   2657                     } else {
   2658                         // Somehow the timestamp for this scan result is inconsistent
   2659                         sb.append(" !seen=").append(result.seen);
   2660                     }
   2661                 }
   2662                 if (mTargetRoamBSSID != null) {
   2663                     sb.append(" ").append(mTargetRoamBSSID);
   2664                 }
   2665                 sb.append(" roam=").append(Integer.toString(mAutoRoaming));
   2666                 sb.append(" fail count=").append(Integer.toString(mRoamFailCount));
   2667                 milli = SystemClock.elapsedRealtime();
   2668                 sb.append(" rt=").append(milli);
   2669                 break;
   2670             case CMD_ADD_OR_UPDATE_NETWORK:
   2671                 sb.append(" ");
   2672                 sb.append(Integer.toString(msg.arg1));
   2673                 sb.append(" ");
   2674                 sb.append(Integer.toString(msg.arg2));
   2675                 if (msg.obj != null) {
   2676                     config = (WifiConfiguration)msg.obj;
   2677                     sb.append(" ").append(config.configKey());
   2678                     sb.append(" prio=").append(config.priority);
   2679                     sb.append(" status=").append(config.status);
   2680                     if (config.BSSID != null) {
   2681                         sb.append(" ").append(config.BSSID);
   2682                     }
   2683                     WifiConfiguration curConfig = getCurrentWifiConfiguration();
   2684                     if (curConfig != null) {
   2685                         if (curConfig.configKey().equals(config.configKey())) {
   2686                             sb.append(" is current");
   2687                         } else {
   2688                             sb.append(" current=").append(curConfig.configKey());
   2689                             sb.append(" prio=").append(curConfig.priority);
   2690                             sb.append(" status=").append(curConfig.status);
   2691                         }
   2692                     }
   2693                 }
   2694                 break;
   2695             case WifiManager.DISABLE_NETWORK:
   2696             case CMD_ENABLE_NETWORK:
   2697                 sb.append(" ");
   2698                 sb.append(Integer.toString(msg.arg1));
   2699                 sb.append(" ");
   2700                 sb.append(Integer.toString(msg.arg2));
   2701                 String key = mWifiConfigStore.getLastSelectedConfiguration();
   2702                 if (key != null) {
   2703                     sb.append(" last=").append(key);
   2704                 }
   2705                 config = mWifiConfigStore.getWifiConfiguration(msg.arg1);
   2706                 if (config != null && (key == null || !config.configKey().equals(key))) {
   2707                     sb.append(" target=").append(key);
   2708                 }
   2709                 break;
   2710             case CMD_GET_CONFIGURED_NETWORKS:
   2711                 sb.append(" ");
   2712                 sb.append(Integer.toString(msg.arg1));
   2713                 sb.append(" ");
   2714                 sb.append(Integer.toString(msg.arg2));
   2715                 sb.append(" num=").append(mWifiConfigStore.getConfiguredNetworksSize());
   2716                 break;
   2717             case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   2718                 sb.append(" ");
   2719                 sb.append(Integer.toString(msg.arg1));
   2720                 sb.append(" ");
   2721                 sb.append(Integer.toString(msg.arg2));
   2722                 sb.append(" txpkts=").append(mWifiInfo.txSuccess);
   2723                 sb.append(",").append(mWifiInfo.txBad);
   2724                 sb.append(",").append(mWifiInfo.txRetries);
   2725                 break;
   2726             case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   2727                 sb.append(" ");
   2728                 sb.append(Integer.toString(msg.arg1));
   2729                 sb.append(" ");
   2730                 sb.append(Integer.toString(msg.arg2));
   2731                 if (msg.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
   2732                     sb.append(" OK ");
   2733                 } else if (msg.arg1 == DhcpStateMachine.DHCP_FAILURE) {
   2734                     sb.append(" FAIL ");
   2735                 }
   2736                 if (mLinkProperties != null) {
   2737                     if (mLinkProperties.hasIPv4Address()) {
   2738                         sb.append(" v4");
   2739                     }
   2740                     if (mLinkProperties.hasGlobalIPv6Address()) {
   2741                         sb.append(" v6");
   2742                     }
   2743                     if (mLinkProperties.hasIPv4DefaultRoute()) {
   2744                         sb.append(" v4r");
   2745                     }
   2746                     if (mLinkProperties.hasIPv6DefaultRoute()) {
   2747                         sb.append(" v6r");
   2748                     }
   2749                     if (mLinkProperties.hasIPv4DnsServer()) {
   2750                         sb.append(" v4dns");
   2751                     }
   2752                     if (mLinkProperties.hasIPv6DnsServer()) {
   2753                         sb.append(" v6dns");
   2754                     }
   2755                 }
   2756                 break;
   2757             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
   2758                 sb.append(" ");
   2759                 sb.append(Integer.toString(msg.arg1));
   2760                 sb.append(" ");
   2761                 sb.append(Integer.toString(msg.arg2));
   2762                 if (msg.obj != null) {
   2763                     NetworkInfo info = (NetworkInfo)msg.obj;
   2764                     NetworkInfo.State state = info.getState();
   2765                     NetworkInfo.DetailedState detailedState = info.getDetailedState();
   2766                     if (state != null) {
   2767                         sb.append(" st=").append(state);
   2768                     }
   2769                     if (detailedState != null) {
   2770                         sb.append("/").append(detailedState);
   2771                     }
   2772                 }
   2773                 break;
   2774             case CMD_IP_CONFIGURATION_LOST:
   2775                 int count = -1;
   2776                 WifiConfiguration c = getCurrentWifiConfiguration();
   2777                 if (c != null) count = c.numIpConfigFailures;
   2778                 sb.append(" ");
   2779                 sb.append(Integer.toString(msg.arg1));
   2780                 sb.append(" ");
   2781                 sb.append(Integer.toString(msg.arg2));
   2782                 sb.append(" failures: ");
   2783                 sb.append(Integer.toString(count));
   2784                 sb.append("/");
   2785                 sb.append(Integer.toString(mWifiConfigStore.getMaxDhcpRetries()));
   2786                 if (mWifiInfo.getBSSID() != null) {
   2787                     sb.append(" ").append(mWifiInfo.getBSSID());
   2788                 }
   2789                 if (c != null) {
   2790                     if (c.scanResultCache != null) {
   2791                         for (ScanResult r : c.scanResultCache.values()) {
   2792                             if (r.BSSID.equals(mWifiInfo.getBSSID())) {
   2793                                 sb.append(" ipfail=").append(r.numIpConfigFailures);
   2794                                 sb.append(",st=").append(r.autoJoinStatus);
   2795                             }
   2796                         }
   2797                     }
   2798                     sb.append(" -> ajst=").append(c.autoJoinStatus);
   2799                     sb.append(" ").append(c.disableReason);
   2800                     sb.append(" txpkts=").append(mWifiInfo.txSuccess);
   2801                     sb.append(",").append(mWifiInfo.txBad);
   2802                     sb.append(",").append(mWifiInfo.txRetries);
   2803                 }
   2804                 milli = SystemClock.elapsedRealtime();
   2805                 sb.append(" rt=").append(milli);
   2806                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
   2807                 break;
   2808             case CMD_UPDATE_LINKPROPERTIES:
   2809                 sb.append(" ");
   2810                 sb.append(Integer.toString(msg.arg1));
   2811                 sb.append(" ");
   2812                 sb.append(Integer.toString(msg.arg2));
   2813                 if (mLinkProperties != null) {
   2814                     if (mLinkProperties.hasIPv4Address()) {
   2815                         sb.append(" v4");
   2816                     }
   2817                     if (mLinkProperties.hasGlobalIPv6Address()) {
   2818                         sb.append(" v6");
   2819                     }
   2820                     if (mLinkProperties.hasIPv4DefaultRoute()) {
   2821                         sb.append(" v4r");
   2822                     }
   2823                     if (mLinkProperties.hasIPv6DefaultRoute()) {
   2824                         sb.append(" v6r");
   2825                     }
   2826                     if (mLinkProperties.hasIPv4DnsServer()) {
   2827                         sb.append(" v4dns");
   2828                     }
   2829                     if (mLinkProperties.hasIPv6DnsServer()) {
   2830                         sb.append(" v6dns");
   2831                     }
   2832                 }
   2833                 break;
   2834             case CMD_SET_COUNTRY_CODE:
   2835                 sb.append(" ");
   2836                 sb.append(Integer.toString(msg.arg1));
   2837                 sb.append(" ");
   2838                 sb.append(Integer.toString(msg.arg2));
   2839                 if (msg.obj != null) {
   2840                     sb.append(" ").append((String)msg.obj);
   2841                 }
   2842                 break;
   2843             case CMD_ROAM_WATCHDOG_TIMER:
   2844                 sb.append(" ");
   2845                 sb.append(Integer.toString(msg.arg1));
   2846                 sb.append(" ");
   2847                 sb.append(Integer.toString(msg.arg2));
   2848                 sb.append(" cur=").append(roamWatchdogCount);
   2849                 break;
   2850             case CMD_DISCONNECTING_WATCHDOG_TIMER:
   2851                 sb.append(" ");
   2852                 sb.append(Integer.toString(msg.arg1));
   2853                 sb.append(" ");
   2854                 sb.append(Integer.toString(msg.arg2));
   2855                 sb.append(" cur=").append(disconnectingWatchdogCount);
   2856                 break;
   2857             default:
   2858                 sb.append(" ");
   2859                 sb.append(Integer.toString(msg.arg1));
   2860                 sb.append(" ");
   2861                 sb.append(Integer.toString(msg.arg2));
   2862                 break;
   2863         }
   2864 
   2865         return sb.toString();
   2866     }
   2867 
   2868     private void handleScreenStateChanged(boolean screenOn, boolean startBackgroundScanIfNeeded) {
   2869         mScreenOn = screenOn;
   2870         if (PDBG) {
   2871             loge(" handleScreenStateChanged Enter: screenOn=" + screenOn
   2872                     + " mCurrentScanAlarmMs = " + Long.toString(mCurrentScanAlarmMs)
   2873                     + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt
   2874                     + " state " + getCurrentState().getName()
   2875                     + " suppState:" + mSupplicantStateTracker.getSupplicantStateName());
   2876         }
   2877         enableRssiPolling(screenOn);
   2878         if (screenOn) enableAllNetworks();
   2879         if (mUserWantsSuspendOpt.get()) {
   2880             if (screenOn) {
   2881                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0);
   2882             } else {
   2883                 // Allow 2s for suspend optimizations to be set
   2884                 mSuspendWakeLock.acquire(2000);
   2885                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0);
   2886             }
   2887         }
   2888         mScreenBroadcastReceived.set(true);
   2889 
   2890         getWifiLinkLayerStats(false);
   2891         mOnTimeScreenStateChange = mOnTime;
   2892         lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate;
   2893 
   2894         if (screenOn) {
   2895             clearBlacklist();
   2896 
   2897             fullBandConnectedTimeIntervalMilli = mWifiConfigStore.associatedPartialScanPeriodMilli;
   2898             // Start the scan alarm so as to enable autojoin
   2899             if (getCurrentState() == mConnectedState
   2900                     && mWifiConfigStore.enableAutoJoinScanWhenAssociated) {
   2901                 mCurrentScanAlarmMs = mWifiConfigStore.associatedPartialScanPeriodMilli;
   2902                 // Scan after 200ms
   2903                 setScanAlarm(true, 200);
   2904             } else if (getCurrentState() == mDisconnectedState) {
   2905                 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs;
   2906                 // Scan after 200ms
   2907                 setScanAlarm(true, 200);
   2908             }
   2909         } else {
   2910             setScanAlarm(false, 0);
   2911         }
   2912 
   2913         if (mBackgroundScanSupported) {
   2914             mEnableBackgroundScan = (screenOn == false);
   2915         }
   2916 
   2917         if (DBG) logd("backgroundScan enabled=" + mEnableBackgroundScan
   2918                 + " startBackgroundScanIfNeeded:" + startBackgroundScanIfNeeded);
   2919 
   2920         if (startBackgroundScanIfNeeded) {
   2921             mWifiNative.enableBackgroundScan(mEnableBackgroundScan);
   2922         }
   2923 
   2924         if (DBG) log("handleScreenStateChanged Exit: " + screenOn);
   2925     }
   2926 
   2927     private void checkAndSetConnectivityInstance() {
   2928         if (mCm == null) {
   2929             mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
   2930         }
   2931     }
   2932 
   2933     private boolean startTethering(ArrayList<String> available) {
   2934 
   2935         boolean wifiAvailable = false;
   2936 
   2937         checkAndSetConnectivityInstance();
   2938 
   2939         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
   2940 
   2941         for (String intf : available) {
   2942             for (String regex : wifiRegexs) {
   2943                 if (intf.matches(regex)) {
   2944 
   2945                     InterfaceConfiguration ifcg = null;
   2946                     try {
   2947                         ifcg = mNwService.getInterfaceConfig(intf);
   2948                         if (ifcg != null) {
   2949                             /* IP/netmask: 192.168.43.1/255.255.255.0 */
   2950                             ifcg.setLinkAddress(new LinkAddress(
   2951                                     NetworkUtils.numericToInetAddress("192.168.43.1"), 24));
   2952                             ifcg.setInterfaceUp();
   2953 
   2954                             mNwService.setInterfaceConfig(intf, ifcg);
   2955                         }
   2956                     } catch (Exception e) {
   2957                         loge("Error configuring interface " + intf + ", :" + e);
   2958                         return false;
   2959                     }
   2960 
   2961                     if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
   2962                         loge("Error tethering on " + intf);
   2963                         return false;
   2964                     }
   2965                     mTetherInterfaceName = intf;
   2966                     return true;
   2967                 }
   2968             }
   2969         }
   2970         // We found no interfaces to tether
   2971         return false;
   2972     }
   2973 
   2974     private void stopTethering() {
   2975 
   2976         checkAndSetConnectivityInstance();
   2977 
   2978         /* Clear the interface config to allow dhcp correctly configure new
   2979            ip settings */
   2980         InterfaceConfiguration ifcg = null;
   2981         try {
   2982             ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName);
   2983             if (ifcg != null) {
   2984                 ifcg.setLinkAddress(
   2985                         new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0));
   2986                 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg);
   2987             }
   2988         } catch (Exception e) {
   2989             loge("Error resetting interface " + mTetherInterfaceName + ", :" + e);
   2990         }
   2991 
   2992         if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
   2993             loge("Untether initiate failed!");
   2994         }
   2995     }
   2996 
   2997     private boolean isWifiTethered(ArrayList<String> active) {
   2998 
   2999         checkAndSetConnectivityInstance();
   3000 
   3001         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
   3002         for (String intf : active) {
   3003             for (String regex : wifiRegexs) {
   3004                 if (intf.matches(regex)) {
   3005                     return true;
   3006                 }
   3007             }
   3008         }
   3009         // We found no interfaces that are tethered
   3010         return false;
   3011     }
   3012 
   3013     /**
   3014      * Set the country code from the system setting value, if any.
   3015      */
   3016     private void setCountryCode() {
   3017         String countryCode = Settings.Global.getString(mContext.getContentResolver(),
   3018                 Settings.Global.WIFI_COUNTRY_CODE);
   3019         if (countryCode != null && !countryCode.isEmpty()) {
   3020             setCountryCode(countryCode, false);
   3021         } else {
   3022             //use driver default
   3023         }
   3024     }
   3025 
   3026     /**
   3027      * Set the frequency band from the system setting value, if any.
   3028      */
   3029     private void setFrequencyBand() {
   3030         int band = Settings.Global.getInt(mContext.getContentResolver(),
   3031                 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
   3032         setFrequencyBand(band, false);
   3033     }
   3034 
   3035     private void setSuspendOptimizationsNative(int reason, boolean enabled) {
   3036         if (DBG) {
   3037             log("setSuspendOptimizationsNative: " + reason + " " + enabled
   3038                     + " -want " + mUserWantsSuspendOpt.get()
   3039                     + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
   3040                     +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName()
   3041                     +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName()
   3042                     +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName());
   3043         }
   3044         //mWifiNative.setSuspendOptimizations(enabled);
   3045 
   3046         if (enabled) {
   3047             mSuspendOptNeedsDisabled &= ~reason;
   3048             /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
   3049             if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) {
   3050                 if (DBG) {
   3051                     log("setSuspendOptimizationsNative do it " + reason + " " + enabled
   3052                             + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
   3053                             +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName()
   3054                             +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName()
   3055                             +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName());
   3056                 }
   3057                 mWifiNative.setSuspendOptimizations(true);
   3058             }
   3059         } else {
   3060             mSuspendOptNeedsDisabled |= reason;
   3061             mWifiNative.setSuspendOptimizations(false);
   3062         }
   3063     }
   3064 
   3065     private void setSuspendOptimizations(int reason, boolean enabled) {
   3066         if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled);
   3067         if (enabled) {
   3068             mSuspendOptNeedsDisabled &= ~reason;
   3069         } else {
   3070             mSuspendOptNeedsDisabled |= reason;
   3071         }
   3072         if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
   3073     }
   3074 
   3075     private void setWifiState(int wifiState) {
   3076         final int previousWifiState = mWifiState.get();
   3077 
   3078         try {
   3079             if (wifiState == WIFI_STATE_ENABLED) {
   3080                 mBatteryStats.noteWifiOn();
   3081             } else if (wifiState == WIFI_STATE_DISABLED) {
   3082                 mBatteryStats.noteWifiOff();
   3083             }
   3084         } catch (RemoteException e) {
   3085             loge("Failed to note battery stats in wifi");
   3086         }
   3087 
   3088         mWifiState.set(wifiState);
   3089 
   3090         if (DBG) log("setWifiState: " + syncGetWifiStateByName());
   3091 
   3092         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
   3093         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   3094         intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
   3095         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
   3096         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   3097     }
   3098 
   3099     private void setWifiApState(int wifiApState) {
   3100         final int previousWifiApState = mWifiApState.get();
   3101 
   3102         try {
   3103             if (wifiApState == WIFI_AP_STATE_ENABLED) {
   3104                 mBatteryStats.noteWifiOn();
   3105             } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
   3106                 mBatteryStats.noteWifiOff();
   3107             }
   3108         } catch (RemoteException e) {
   3109             loge("Failed to note battery stats in wifi");
   3110         }
   3111 
   3112         // Update state
   3113         mWifiApState.set(wifiApState);
   3114 
   3115         if (DBG) log("setWifiApState: " + syncGetWifiApStateByName());
   3116 
   3117         final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
   3118         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   3119         intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
   3120         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
   3121         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   3122     }
   3123 
   3124     /*
   3125     void ageOutScanResults(int age) {
   3126         synchronized(mScanResultCache) {
   3127             // Trim mScanResults, which prevent WifiStateMachine to return
   3128             // obsolete scan results to queriers
   3129             long now = System.CurrentTimeMillis();
   3130             for (int i = 0; i < mScanResults.size(); i++) {
   3131                 ScanResult result = mScanResults.get(i);
   3132                 if ((result.seen > now || (now - result.seen) > age)) {
   3133                     mScanResults.remove(i);
   3134                 }
   3135             }
   3136         }
   3137     }*/
   3138 
   3139     private static final String ID_STR = "id=";
   3140     private static final String BSSID_STR = "bssid=";
   3141     private static final String FREQ_STR = "freq=";
   3142     private static final String LEVEL_STR = "level=";
   3143     private static final String TSF_STR = "tsf=";
   3144     private static final String FLAGS_STR = "flags=";
   3145     private static final String SSID_STR = "ssid=";
   3146     private static final String DELIMITER_STR = "====";
   3147     private static final String END_STR = "####";
   3148 
   3149     int emptyScanResultCount = 0;
   3150 
   3151     /**
   3152      * Format:
   3153      *
   3154      * id=1
   3155      * bssid=68:7f:76:d7:1a:6e
   3156      * freq=2412
   3157      * level=-44
   3158      * tsf=1344626243700342
   3159      * flags=[WPA2-PSK-CCMP][WPS][ESS]
   3160      * ssid=zfdy
   3161      * ====
   3162      * id=2
   3163      * bssid=68:5f:74:d7:1a:6f
   3164      * freq=5180
   3165      * level=-73
   3166      * tsf=1344626243700373
   3167      * flags=[WPA2-PSK-CCMP][WPS][ESS]
   3168      * ssid=zuby
   3169      * ====
   3170      */
   3171     private void setScanResults() {
   3172         mNumScanResultsKnown = 0;
   3173         mNumScanResultsReturned = 0;
   3174         String bssid = "";
   3175         int level = 0;
   3176         int freq = 0;
   3177         long tsf = 0;
   3178         String flags = "";
   3179         WifiSsid wifiSsid = null;
   3180         String scanResults;
   3181         String tmpResults;
   3182         StringBuffer scanResultsBuf = new StringBuffer();
   3183         int sid = 0;
   3184 
   3185         while (true) {
   3186             tmpResults = mWifiNative.scanResults(sid);
   3187             if (TextUtils.isEmpty(tmpResults)) break;
   3188             scanResultsBuf.append(tmpResults);
   3189             scanResultsBuf.append("\n");
   3190             String[] lines = tmpResults.split("\n");
   3191             sid = -1;
   3192             for (int i=lines.length - 1; i >= 0; i--) {
   3193                 if (lines[i].startsWith(END_STR)) {
   3194                     break;
   3195                 } else if (lines[i].startsWith(ID_STR)) {
   3196                     try {
   3197                         sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1;
   3198                     } catch (NumberFormatException e) {
   3199                         // Nothing to do
   3200                     }
   3201                     break;
   3202                 }
   3203             }
   3204             if (sid == -1) break;
   3205         }
   3206 
   3207         // Age out scan results, we return all scan results found in the last 12 seconds,
   3208         // and NOT all scan results since last scan.
   3209         // ageOutScanResults(12000);
   3210 
   3211         scanResults = scanResultsBuf.toString();
   3212         if (TextUtils.isEmpty(scanResults)) {
   3213             emptyScanResultCount++;
   3214             if (emptyScanResultCount > 10) {
   3215                 // If we got too many empty scan results, the current scan cache is stale,
   3216                 // hence clear it.
   3217                 mScanResults = new ArrayList<ScanResult>();
   3218             }
   3219            return;
   3220         }
   3221 
   3222         emptyScanResultCount = 0;
   3223 
   3224         // note that all these splits and substrings keep references to the original
   3225         // huge string buffer while the amount we really want is generally pretty small
   3226         // so make copies instead (one example b/11087956 wasted 400k of heap here).
   3227         synchronized(mScanResultCache) {
   3228             mScanResults = new ArrayList<ScanResult>();
   3229             String[] lines = scanResults.split("\n");
   3230             final int bssidStrLen = BSSID_STR.length();
   3231             final int flagLen = FLAGS_STR.length();
   3232 
   3233             for (String line : lines) {
   3234                 if (line.startsWith(BSSID_STR)) {
   3235                     bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen);
   3236                 } else if (line.startsWith(FREQ_STR)) {
   3237                     try {
   3238                         freq = Integer.parseInt(line.substring(FREQ_STR.length()));
   3239                     } catch (NumberFormatException e) {
   3240                         freq = 0;
   3241                     }
   3242                 } else if (line.startsWith(LEVEL_STR)) {
   3243                     try {
   3244                         level = Integer.parseInt(line.substring(LEVEL_STR.length()));
   3245                         /* some implementations avoid negative values by adding 256
   3246                          * so we need to adjust for that here.
   3247                          */
   3248                         if (level > 0) level -= 256;
   3249                     } catch(NumberFormatException e) {
   3250                         level = 0;
   3251                     }
   3252                 } else if (line.startsWith(TSF_STR)) {
   3253                     try {
   3254                         tsf = Long.parseLong(line.substring(TSF_STR.length()));
   3255                     } catch (NumberFormatException e) {
   3256                         tsf = 0;
   3257                     }
   3258                 } else if (line.startsWith(FLAGS_STR)) {
   3259                     flags = new String(line.getBytes(), flagLen, line.length() - flagLen);
   3260                 } else if (line.startsWith(SSID_STR)) {
   3261                     wifiSsid = WifiSsid.createFromAsciiEncoded(
   3262                             line.substring(SSID_STR.length()));
   3263                 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) {
   3264                     if (bssid != null) {
   3265                         String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
   3266                         String key = bssid + ssid;
   3267                         ScanResult scanResult = mScanResultCache.get(key);
   3268                         if (scanResult != null) {
   3269                             // TODO: average the RSSI, instead of overwriting it
   3270                             scanResult.level = level;
   3271                             scanResult.wifiSsid = wifiSsid;
   3272                             // Keep existing API
   3273                             scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() :
   3274                                     WifiSsid.NONE;
   3275                             scanResult.capabilities = flags;
   3276                             scanResult.frequency = freq;
   3277                             scanResult.timestamp = tsf;
   3278                             scanResult.seen = System.currentTimeMillis();
   3279                         } else {
   3280                             scanResult =
   3281                                 new ScanResult(
   3282                                         wifiSsid, bssid, flags, level, freq, tsf);
   3283                             scanResult.seen = System.currentTimeMillis();
   3284                             mScanResultCache.put(key, scanResult);
   3285                         }
   3286                         mNumScanResultsReturned ++; // Keep track of how many scan results we got
   3287                                                     // as part of this scan's processing
   3288                         mScanResults.add(scanResult);
   3289                     }
   3290                     bssid = null;
   3291                     level = 0;
   3292                     freq = 0;
   3293                     tsf = 0;
   3294                     flags = "";
   3295                     wifiSsid = null;
   3296                 }
   3297             }
   3298         }
   3299         boolean attemptAutoJoin = true;
   3300         SupplicantState state = mWifiInfo.getSupplicantState();
   3301         if (getCurrentState() == mRoamingState
   3302                 || getCurrentState() == mObtainingIpState
   3303                 || getCurrentState() == mScanModeState
   3304                 || getCurrentState() == mDisconnectingState
   3305                 || (getCurrentState() == mConnectedState
   3306                 && !mWifiConfigStore.enableAutoJoinWhenAssociated)
   3307                 || linkDebouncing
   3308                 || state == SupplicantState.ASSOCIATING
   3309                 || state == SupplicantState.AUTHENTICATING
   3310                 || state == SupplicantState.FOUR_WAY_HANDSHAKE
   3311                 || state == SupplicantState.GROUP_HANDSHAKE) {
   3312             // Dont attempt auto-joining again while we are already attempting to join
   3313             // and/or obtaining Ip address
   3314             attemptAutoJoin = false;
   3315         }
   3316         if (DBG) {
   3317             loge("wifi setScanResults state" + getCurrentState()
   3318                     + " sup_state=" + state
   3319                     + " debouncing=" + linkDebouncing);
   3320         }
   3321         if (attemptAutoJoin) {
   3322             messageHandlingStatus = MESSAGE_HANDLING_STATUS_PROCESSED;
   3323         }
   3324         // Loose last selected configuration if we have been disconnected for 30 minutes
   3325         if (getDisconnectedTimeMilli() > 1000 * 60 * 30) {
   3326             mWifiConfigStore.setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
   3327         }
   3328 
   3329         if (mWifiConfigStore.enableAutoJoinWhenAssociated) {
   3330             synchronized(mScanResultCache) {
   3331                 // AutoJoincontroller will directly acces the scan result list and update it with
   3332                 // ScanResult status
   3333                 mNumScanResultsKnown = mWifiAutoJoinController.newSupplicantResults(attemptAutoJoin);
   3334             }
   3335         }
   3336         if (linkDebouncing) {
   3337             // If debouncing, we dont re-select a SSID or BSSID hence
   3338             // there is no need to call the network selection code
   3339             // in WifiAutoJoinController, instead,
   3340             // just try to reconnect to the same SSID by triggering a roam
   3341             sendMessage(CMD_AUTO_ROAM, mLastNetworkId, 1, null);
   3342         }
   3343     }
   3344 
   3345     /*
   3346      * Fetch RSSI, linkspeed, and frequency on current connection
   3347      */
   3348     private void fetchRssiLinkSpeedAndFrequencyNative() {
   3349         int newRssi = -1;
   3350         int newLinkSpeed = -1;
   3351         int newFrequency = -1;
   3352 
   3353         String signalPoll = mWifiNative.signalPoll();
   3354 
   3355         if (signalPoll != null) {
   3356             String[] lines = signalPoll.split("\n");
   3357             for (String line : lines) {
   3358                 String[] prop = line.split("=");
   3359                 if (prop.length < 2) continue;
   3360                 try {
   3361                     if (prop[0].equals("RSSI")) {
   3362                         newRssi = Integer.parseInt(prop[1]);
   3363                     } else if (prop[0].equals("LINKSPEED")) {
   3364                         newLinkSpeed = Integer.parseInt(prop[1]);
   3365                     } else if (prop[0].equals("FREQUENCY")) {
   3366                         newFrequency = Integer.parseInt(prop[1]);
   3367                     }
   3368                 } catch (NumberFormatException e) {
   3369                     //Ignore, defaults on rssi and linkspeed are assigned
   3370                 }
   3371             }
   3372         }
   3373 
   3374         if (PDBG) {
   3375             loge("fetchRssiLinkSpeedAndFrequencyNative rssi="
   3376                     + Integer.toString(newRssi) + " linkspeed="
   3377                     + Integer.toString(newLinkSpeed));
   3378         }
   3379 
   3380         if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) {
   3381         // screen out invalid values
   3382             /* some implementations avoid negative values by adding 256
   3383              * so we need to adjust for that here.
   3384              */
   3385             if (newRssi > 0) newRssi -= 256;
   3386             mWifiInfo.setRssi(newRssi);
   3387             /*
   3388              * Rather then sending the raw RSSI out every time it
   3389              * changes, we precalculate the signal level that would
   3390              * be displayed in the status bar, and only send the
   3391              * broadcast if that much more coarse-grained number
   3392              * changes. This cuts down greatly on the number of
   3393              * broadcasts, at the cost of not informing others
   3394              * interested in RSSI of all the changes in signal
   3395              * level.
   3396              */
   3397             int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
   3398             if (newSignalLevel != mLastSignalLevel) {
   3399                 sendRssiChangeBroadcast(newRssi);
   3400             }
   3401             mLastSignalLevel = newSignalLevel;
   3402         } else {
   3403             mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
   3404         }
   3405 
   3406         if (newLinkSpeed != -1) {
   3407             mWifiInfo.setLinkSpeed(newLinkSpeed);
   3408         }
   3409         if (newFrequency > 0) {
   3410             if (ScanResult.is5GHz(newFrequency)) {
   3411                 mWifiConnectionStatistics.num5GhzConnected++;
   3412             }
   3413             if (ScanResult.is24GHz(newFrequency)) {
   3414                 mWifiConnectionStatistics.num24GhzConnected++;
   3415             }
   3416             mWifiInfo.setFrequency(newFrequency);
   3417         }
   3418         mWifiConfigStore.updateConfiguration(mWifiInfo);
   3419     }
   3420 
   3421     /**
   3422      *  Determine if we need to switch network:
   3423      * - the delta determine the urgency to switch and/or or the expected evilness of the disruption
   3424      * - match the uregncy of the switch versus the packet usage at the interface
   3425      */
   3426     boolean shouldSwitchNetwork(int networkDelta) {
   3427         int delta;
   3428         if (networkDelta <= 0) {
   3429             return false;
   3430         }
   3431         delta = networkDelta;
   3432         if (mWifiInfo != null) {
   3433             if (!mWifiConfigStore.enableAutoJoinWhenAssociated
   3434                     && mWifiInfo.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
   3435                 // If AutoJoin while associated is not enabled,
   3436                 // we should never switch network when already associated
   3437                 delta = -1000;
   3438             } else {
   3439                 // TODO: Look at per AC packet count, do not switch if VO/VI traffic is present
   3440                 // TODO: at the interface. We should also discriminate between ucast and mcast,
   3441                 // TODO: since the rxSuccessRate include all the bonjour and Ipv6
   3442                 // TODO: broadcasts
   3443                 if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) {
   3444                     delta -= 999;
   3445                 } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) {
   3446                     delta -= 6;
   3447                 }
   3448                 loge("WifiStateMachine shouldSwitchNetwork "
   3449                         + " txSuccessRate=" + String.format("%.2f", mWifiInfo.txSuccessRate)
   3450                         + " rxSuccessRate=" + String.format("%.2f", mWifiInfo.rxSuccessRate)
   3451                         + " delta " + networkDelta + " -> " + delta);
   3452             }
   3453         } else {
   3454             loge("WifiStateMachine shouldSwitchNetwork "
   3455                     + " delta " + networkDelta + " -> " + delta);
   3456         }
   3457         if (delta > 0) {
   3458             return true;
   3459         }
   3460         return false;
   3461     }
   3462 
   3463     // Polling has completed, hence we wont have a score anymore
   3464     private void cleanWifiScore() {
   3465         mWifiInfo.txBadRate = 0;
   3466         mWifiInfo.txSuccessRate = 0;
   3467         mWifiInfo.txRetriesRate = 0;
   3468         mWifiInfo.rxSuccessRate = 0;
   3469     }
   3470 
   3471     int mBadLinkspeedcount = 0;
   3472 
   3473     // For debug, provide information about the last scoring operation
   3474     String wifiScoringReport = null;
   3475     private void calculateWifiScore(WifiLinkLayerStats stats) {
   3476         StringBuilder sb = new StringBuilder();
   3477         if (stats == null || mWifiLinkLayerStatsSupported <= 0) {
   3478             long mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
   3479             long mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
   3480             mWifiInfo.updatePacketRates(mTxPkts, mRxPkts);
   3481         } else {
   3482             sb.append(" stats");
   3483             mWifiInfo.updatePacketRates(stats);
   3484         }
   3485         int score = 56; // Starting score, temporarily hardcoded in between 50 and 60
   3486         boolean isBadLinkspeed = (mWifiInfo.is24GHz()
   3487                 && mWifiInfo.getLinkSpeed() < mWifiConfigStore.badLinkSpeed24)
   3488                 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed()
   3489                 < mWifiConfigStore.badLinkSpeed5);
   3490         boolean isGoodLinkspeed = (mWifiInfo.is24GHz()
   3491                 && mWifiInfo.getLinkSpeed() >= mWifiConfigStore.goodLinkSpeed24)
   3492                 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed()
   3493                 >= mWifiConfigStore.goodLinkSpeed5);
   3494 
   3495         if (isBadLinkspeed) {
   3496             if (mBadLinkspeedcount < 6)
   3497                 mBadLinkspeedcount++;
   3498         } else {
   3499             if (mBadLinkspeedcount > 0)
   3500                 mBadLinkspeedcount--;
   3501         }
   3502 
   3503         if (isBadLinkspeed) sb.append(" bl(").append(mBadLinkspeedcount).append(")");
   3504         if (isGoodLinkspeed) sb.append(" gl");
   3505 
   3506         /**
   3507          * We want to make sure that we use the 24GHz RSSI thresholds if
   3508          * there are 2.4GHz scan results
   3509          * otherwise we end up lowering the score based on 5GHz values
   3510          * which may cause a switch to LTE before roaming has a chance to try 2.4GHz
   3511          * We also might unblacklist the configuation based on 2.4GHz
   3512          * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good
   3513          */
   3514         boolean use24Thresholds = false;
   3515         boolean homeNetworkBoost = false;
   3516         WifiConfiguration currentConfiguration = getCurrentWifiConfiguration();
   3517         if (currentConfiguration != null
   3518                 && currentConfiguration.scanResultCache != null) {
   3519             currentConfiguration.setVisibility(12000);
   3520             if (currentConfiguration.visibility != null) {
   3521                 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI
   3522                         && currentConfiguration.visibility.rssi24
   3523                         >= (currentConfiguration.visibility.rssi5-2)) {
   3524                     use24Thresholds = true;
   3525                 }
   3526             }
   3527             if (currentConfiguration.scanResultCache.size() <= 6
   3528                 && currentConfiguration.allowedKeyManagement.cardinality() == 1
   3529                 && currentConfiguration.allowedKeyManagement.
   3530                     get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) {
   3531                 // A PSK network with less than 6 known BSSIDs
   3532                 // This is most likely a home network and thus we want to stick to wifi more
   3533                 homeNetworkBoost = true;
   3534             }
   3535         }
   3536         if (homeNetworkBoost) sb.append(" hn");
   3537         if (use24Thresholds) sb.append(" u24");
   3538 
   3539         int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover
   3540                 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0);
   3541         sb.append(String.format(" rssi=%d ag=%d", rssi, mAggressiveHandover));
   3542 
   3543         boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz();
   3544 
   3545         boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24)
   3546                 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5);
   3547         boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24)
   3548                 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5);
   3549         boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24)
   3550                 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5);
   3551 
   3552         if (isBadRSSI) sb.append(" br");
   3553         if (isLowRSSI) sb.append(" lr");
   3554         if (isHighRSSI) sb.append(" hr");
   3555 
   3556         int penalizedDueToUserTriggeredDisconnect = 0;        // For debug information
   3557         if (currentConfiguration!= null &&
   3558                 (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 5)) {
   3559             if (isBadRSSI) {
   3560                 currentConfiguration.numTicksAtBadRSSI++;
   3561                 if (currentConfiguration.numTicksAtBadRSSI > 1000) {
   3562                     // We remained associated for a compound amount of time while passing
   3563                     // traffic, hence loose the corresponding user triggered disabled stats
   3564                     if (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0) {
   3565                         currentConfiguration.numUserTriggeredWifiDisableBadRSSI--;
   3566                     }
   3567                     if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) {
   3568                         currentConfiguration.numUserTriggeredWifiDisableLowRSSI--;
   3569                     }
   3570                     if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
   3571                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
   3572                     }
   3573                     currentConfiguration.numTicksAtBadRSSI = 0;
   3574                 }
   3575                 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment &&
   3576                         (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0
   3577                         || currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0
   3578                         || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) {
   3579                     score = score -5;
   3580                     penalizedDueToUserTriggeredDisconnect = 1;
   3581                     sb.append(" p1");
   3582                 }
   3583             } else if (isLowRSSI) {
   3584                 currentConfiguration.numTicksAtLowRSSI++;
   3585                 if (currentConfiguration.numTicksAtLowRSSI > 1000) {
   3586                     // We remained associated for a compound amount of time while passing
   3587                     // traffic, hence loose the corresponding user triggered disabled stats
   3588                     if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) {
   3589                         currentConfiguration.numUserTriggeredWifiDisableLowRSSI--;
   3590                     }
   3591                     if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
   3592                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
   3593                     }
   3594                     currentConfiguration.numTicksAtLowRSSI = 0;
   3595                 }
   3596                 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment &&
   3597                         (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0
   3598                         || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) {
   3599                     score = score -5;
   3600                     penalizedDueToUserTriggeredDisconnect = 2;
   3601                     sb.append(" p2");
   3602                 }
   3603             } else if (!isHighRSSI) {
   3604                 currentConfiguration.numTicksAtNotHighRSSI++;
   3605                 if (currentConfiguration.numTicksAtNotHighRSSI > 1000) {
   3606                     // We remained associated for a compound amount of time while passing
   3607                     // traffic, hence loose the corresponding user triggered disabled stats
   3608                     if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
   3609                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
   3610                     }
   3611                     currentConfiguration.numTicksAtNotHighRSSI = 0;
   3612                 }
   3613                 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment &&
   3614                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
   3615                     score = score -5;
   3616                     penalizedDueToUserTriggeredDisconnect = 3;
   3617                     sb.append(" p3");
   3618                 }
   3619             }
   3620             sb.append(String.format(" ticks %d,%d,%d", currentConfiguration.numTicksAtBadRSSI,
   3621                     currentConfiguration.numTicksAtLowRSSI,
   3622                     currentConfiguration.numTicksAtNotHighRSSI));
   3623         }
   3624 
   3625         if (PDBG) {
   3626             String rssiStatus = "";
   3627             if (isBadRSSI) rssiStatus += " badRSSI ";
   3628             else if (isHighRSSI) rssiStatus += " highRSSI ";
   3629             else if (isLowRSSI) rssiStatus += " lowRSSI ";
   3630             if (isBadLinkspeed) rssiStatus += " lowSpeed ";
   3631             loge("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency())
   3632                             + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed())
   3633                             + " score=" + Integer.toString(mWifiInfo.score)
   3634                             + rssiStatus
   3635                             + " -> txbadrate=" + String.format( "%.2f", mWifiInfo.txBadRate )
   3636                             + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate)
   3637                             + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate)
   3638                             + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate)
   3639                             + " userTriggerdPenalty" + penalizedDueToUserTriggeredDisconnect);
   3640         }
   3641 
   3642         if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3)
   3643                 && (isBadRSSI || isLowRSSI)) {
   3644             // Link is stuck
   3645             if (mWifiInfo.linkStuckCount < 5)
   3646                 mWifiInfo.linkStuckCount += 1;
   3647             sb.append(String.format(" ls+=%d", mWifiInfo.linkStuckCount));
   3648             if (PDBG) loge(" bad link -> stuck count ="
   3649                     + Integer.toString(mWifiInfo.linkStuckCount));
   3650         } else if (mWifiInfo.txSuccessRate > 2 || mWifiInfo.txBadRate < 0.1) {
   3651             if (mWifiInfo.linkStuckCount > 0)
   3652                 mWifiInfo.linkStuckCount -= 1;
   3653             sb.append(String.format(" ls-=%d", mWifiInfo.linkStuckCount));
   3654             if (PDBG) loge(" good link -> stuck count ="
   3655                     + Integer.toString(mWifiInfo.linkStuckCount));
   3656         }
   3657 
   3658         sb.append(String.format(" [%d", score));
   3659 
   3660         if (mWifiInfo.linkStuckCount > 1) {
   3661             // Once link gets stuck for more than 3 seconds, start reducing the score
   3662             score = score - 2 * (mWifiInfo.linkStuckCount - 1);
   3663         }
   3664         sb.append(String.format(",%d", score));
   3665 
   3666         if (isBadLinkspeed) {
   3667             score -= 4 ;
   3668             if (PDBG) {
   3669                 loge(" isBadLinkspeed   ---> count=" + mBadLinkspeedcount
   3670                         + " score=" + Integer.toString(score));
   3671             }
   3672         } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) {
   3673             score += 4; // So as bad rssi alone dont kill us
   3674         }
   3675         sb.append(String.format(",%d", score));
   3676 
   3677         if (isBadRSSI) {
   3678             if (mWifiInfo.badRssiCount < 7)
   3679                 mWifiInfo.badRssiCount += 1;
   3680         } else if (isLowRSSI) {
   3681             mWifiInfo.lowRssiCount = 1; // Dont increment the lowRssi count above 1
   3682             if (mWifiInfo.badRssiCount > 0) {
   3683                 // Decrement bad Rssi count
   3684                 mWifiInfo.badRssiCount -= 1;
   3685             }
   3686         } else {
   3687             mWifiInfo.badRssiCount = 0;
   3688             mWifiInfo.lowRssiCount = 0;
   3689         }
   3690 
   3691         score -= mWifiInfo.badRssiCount * 2 +  mWifiInfo.lowRssiCount ;
   3692         sb.append(String.format(",%d", score));
   3693 
   3694         if (PDBG) loge(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount)
   3695                      + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount)
   3696                         + " --> score " + Integer.toString(score));
   3697 
   3698 
   3699         if (isHighRSSI) {
   3700             score += 5;
   3701             if (PDBG) loge(" isHighRSSI       ---> score=" + Integer.toString(score));
   3702         }
   3703         sb.append(String.format(",%d]", score));
   3704 
   3705         sb.append(String.format(" brc=%d lrc=%d", mWifiInfo.badRssiCount, mWifiInfo.lowRssiCount));
   3706 
   3707         //sanitize boundaries
   3708         if (score > NetworkAgent.WIFI_BASE_SCORE)
   3709             score = NetworkAgent.WIFI_BASE_SCORE;
   3710         if (score < 0)
   3711             score = 0;
   3712 
   3713         //report score
   3714         if (score != mWifiInfo.score) {
   3715             if (DBG) {
   3716                 loge("calculateWifiScore() report new score " + Integer.toString(score));
   3717             }
   3718             mWifiInfo.score = score;
   3719             if (mNetworkAgent != null) {
   3720                 mNetworkAgent.sendNetworkScore(score);
   3721             }
   3722         }
   3723         wifiScoringReport = sb.toString();
   3724     }
   3725 
   3726     public double getTxPacketRate() {
   3727         if (mWifiInfo != null) {
   3728             return mWifiInfo.txSuccessRate;
   3729         }
   3730         return -1;
   3731     }
   3732 
   3733     public double getRxPacketRate() {
   3734         if (mWifiInfo != null) {
   3735             return mWifiInfo.rxSuccessRate;
   3736         }
   3737         return -1;
   3738     }
   3739 
   3740     /**
   3741      * Fetch TX packet counters on current connection
   3742      */
   3743     private void fetchPktcntNative(RssiPacketCountInfo info) {
   3744         String pktcntPoll = mWifiNative.pktcntPoll();
   3745 
   3746         if (pktcntPoll != null) {
   3747             String[] lines = pktcntPoll.split("\n");
   3748             for (String line : lines) {
   3749                 String[] prop = line.split("=");
   3750                 if (prop.length < 2) continue;
   3751                 try {
   3752                     if (prop[0].equals("TXGOOD")) {
   3753                         info.txgood = Integer.parseInt(prop[1]);
   3754                     } else if (prop[0].equals("TXBAD")) {
   3755                         info.txbad = Integer.parseInt(prop[1]);
   3756                     }
   3757                 } catch (NumberFormatException e) {
   3758                     // Ignore
   3759                 }
   3760             }
   3761         }
   3762     }
   3763 
   3764     private boolean clearIPv4Address(String iface) {
   3765         try {
   3766             InterfaceConfiguration ifcg = new InterfaceConfiguration();
   3767             ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
   3768             mNwService.setInterfaceConfig(iface, ifcg);
   3769             return true;
   3770         } catch (RemoteException e) {
   3771             return false;
   3772         }
   3773     }
   3774 
   3775     private boolean isProvisioned(LinkProperties lp) {
   3776         // LinkProperties#isProvisioned returns true even if all we have is an IPv4 address and no
   3777         // connectivity. This turns out not to be very useful, because we can't distinguish it from
   3778         // a state where we have an IPv4 address assigned to the interface but are still running
   3779         // DHCP.
   3780         // TODO: Fix LinkProperties and remove this function.
   3781         if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
   3782             return lp.hasIPv4Address();
   3783         } else {
   3784             return (lp.hasIPv4Address() && lp.hasIPv4DefaultRoute() && lp.hasIPv4DnsServer()) ||
   3785                    (lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute() && lp.hasIPv6DnsServer());
   3786         }
   3787     }
   3788 
   3789     /**
   3790      * Updates mLinkProperties by merging information from various sources.
   3791      *
   3792      * This is needed because the information in mLinkProperties comes from multiple sources (DHCP,
   3793      * netlink, static configuration, ...). When one of these sources of information has updated
   3794      * link properties, we can't just assign them to mLinkProperties or we'd lose track of the
   3795      * information that came from other sources. Instead, when one of those sources has new
   3796      * information, we update the object that tracks the information from that source and then
   3797      * call this method to apply the change to mLinkProperties.
   3798      *
   3799      * The information in mLinkProperties is currently obtained as follows:
   3800      * - Interface name: set in the constructor.
   3801      * - IPv4 and IPv6 addresses: netlink, passed in by mNetlinkTracker.
   3802      * - IPv4 routes, DNS servers, and domains: DHCP.
   3803      * - IPv6 routes and DNS servers: netlink, passed in by mNetlinkTracker.
   3804      * - HTTP proxy: the wifi config store.
   3805      */
   3806     private void updateLinkProperties(int reason) {
   3807         LinkProperties newLp = new LinkProperties();
   3808 
   3809         // Interface name and proxy are locally configured.
   3810         newLp.setInterfaceName(mInterfaceName);
   3811         newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
   3812 
   3813         // IPv4/v6 addresses, IPv6 routes and IPv6 DNS servers come from netlink.
   3814         LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
   3815         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
   3816         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
   3817             newLp.addRoute(route);
   3818         }
   3819         for (InetAddress dns : netlinkLinkProperties.getDnsServers()) {
   3820             newLp.addDnsServer(dns);
   3821         }
   3822 
   3823         // IPv4 routes, DNS servers and domains come from mDhcpResults.
   3824         synchronized (mDhcpResultsLock) {
   3825             // Even when we're using static configuration, we don't need to look at the config
   3826             // store, because static IP configuration also populates mDhcpResults.
   3827             if ((mDhcpResults != null)) {
   3828                 for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
   3829                     newLp.addRoute(route);
   3830                 }
   3831                 for (InetAddress dns : mDhcpResults.dnsServers) {
   3832                     newLp.addDnsServer(dns);
   3833                 }
   3834                 newLp.setDomains(mDhcpResults.domains);
   3835             }
   3836         }
   3837 
   3838         final boolean linkChanged = !newLp.equals(mLinkProperties);
   3839         final boolean wasProvisioned = isProvisioned(mLinkProperties);
   3840         final boolean isProvisioned = isProvisioned(newLp);
   3841         final DetailedState detailedState = getNetworkDetailedState();
   3842 
   3843         if (linkChanged) {
   3844             if (DBG) {
   3845                 log("Link configuration changed for netId: " + mLastNetworkId
   3846                         + " old: " + mLinkProperties + " new: " + newLp);
   3847             }
   3848             mLinkProperties = newLp;
   3849             if (TextUtils.isEmpty(mTcpBufferSizes) == false) {
   3850                 mLinkProperties.setTcpBufferSizes(mTcpBufferSizes);
   3851             }
   3852             if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
   3853         }
   3854 
   3855         if (DBG) {
   3856             StringBuilder sb = new StringBuilder();
   3857             sb.append("updateLinkProperties nid: " + mLastNetworkId);
   3858             sb.append(" state: " + detailedState);
   3859             sb.append(" reason: " + smToString(reason));
   3860 
   3861             if (mLinkProperties != null) {
   3862                 if (mLinkProperties.hasIPv4Address()) {
   3863                     sb.append(" v4");
   3864                 }
   3865                 if (mLinkProperties.hasGlobalIPv6Address()) {
   3866                     sb.append(" v6");
   3867                 }
   3868                 if (mLinkProperties.hasIPv4DefaultRoute()) {
   3869                     sb.append(" v4r");
   3870                 }
   3871                 if (mLinkProperties.hasIPv6DefaultRoute()) {
   3872                     sb.append(" v6r");
   3873                 }
   3874                 if (mLinkProperties.hasIPv4DnsServer()) {
   3875                     sb.append(" v4dns");
   3876                 }
   3877                 if (mLinkProperties.hasIPv6DnsServer()) {
   3878                     sb.append(" v6dns");
   3879                 }
   3880                 if (isProvisioned) {
   3881                     sb.append(" isprov");
   3882                 }
   3883             }
   3884             loge(sb.toString());
   3885         }
   3886 
   3887         // If we just configured or lost IP configuration, do the needful.
   3888         // We don't just call handleSuccessfulIpConfiguration() or handleIpConfigurationLost()
   3889         // here because those should only be called if we're attempting to connect or already
   3890         // connected, whereas updateLinkProperties can be called at any time.
   3891         switch (reason) {
   3892             case DhcpStateMachine.DHCP_SUCCESS:
   3893             case CMD_STATIC_IP_SUCCESS:
   3894                 // IPv4 provisioning succeded. Advance to connected state.
   3895                 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
   3896                 if (!isProvisioned) {
   3897                     // Can never happen unless DHCP reports success but isProvisioned thinks the
   3898                     // resulting configuration is invalid (e.g., no IPv4 address, or the state in
   3899                     // mLinkProperties is out of sync with reality, or there's a bug in this code).
   3900                     // TODO: disconnect here instead. If our configuration is not usable, there's no
   3901                     // point in staying connected, and if mLinkProperties is out of sync with
   3902                     // reality, that will cause problems in the future.
   3903                     loge("IPv4 config succeeded, but not provisioned");
   3904                 }
   3905                 break;
   3906 
   3907             case DhcpStateMachine.DHCP_FAILURE:
   3908                 // DHCP failed. If we're not already provisioned, give up and disconnect.
   3909                 // If we're already provisioned (e.g., IPv6-only network), stay connected.
   3910                 if (!isProvisioned) {
   3911                     sendMessage(CMD_IP_CONFIGURATION_LOST);
   3912                 } else {
   3913                     // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network).
   3914                     sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
   3915 
   3916                     // To be sure we don't get stuck with a non-working network if all we had is
   3917                     // IPv4, remove the IPv4 address from the interface (since we're using DHCP,
   3918                     // and DHCP failed). If we had an IPv4 address before, the deletion of the
   3919                     // address  will cause a CMD_UPDATE_LINKPROPERTIES. If the IPv4 address was
   3920                     // necessary for provisioning, its deletion will cause us to disconnect.
   3921                     //
   3922                     // This shouldn't be needed, because on an IPv4-only network a DHCP failure will
   3923                     // have empty DhcpResults and thus empty LinkProperties, and isProvisioned will
   3924                     // not return true if we're using DHCP and don't have an IPv4 default route. So
   3925                     // for now it's only here for extra redundancy. However, it will increase
   3926                     // robustness if we move to getting IPv4 routes from netlink as well.
   3927                     loge("DHCP failure: provisioned, clearing IPv4 address.");
   3928                     if (!clearIPv4Address(mInterfaceName)) {
   3929                         sendMessage(CMD_IP_CONFIGURATION_LOST);
   3930                     }
   3931                 }
   3932                 break;
   3933 
   3934             case CMD_STATIC_IP_FAILURE:
   3935                 // Static configuration was invalid, or an error occurred in applying it. Give up.
   3936                 sendMessage(CMD_IP_CONFIGURATION_LOST);
   3937                 break;
   3938 
   3939             case CMD_UPDATE_LINKPROPERTIES:
   3940                 // IP addresses, DNS servers, etc. changed. Act accordingly.
   3941                 if (wasProvisioned && !isProvisioned) {
   3942                     // We no longer have a usable network configuration. Disconnect.
   3943                     sendMessage(CMD_IP_CONFIGURATION_LOST);
   3944                 } else if (!wasProvisioned && isProvisioned) {
   3945                     // We have a usable IPv6-only config. Advance to connected state.
   3946                     sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
   3947                 }
   3948                 if (linkChanged && getNetworkDetailedState() == DetailedState.CONNECTED) {
   3949                     // If anything has changed and we're already connected, send out a notification.
   3950                     sendLinkConfigurationChangedBroadcast();
   3951                 }
   3952                 break;
   3953         }
   3954     }
   3955 
   3956     /**
   3957      * Clears all our link properties.
   3958      */
   3959      private void clearLinkProperties() {
   3960          // Clear the link properties obtained from DHCP and netlink.
   3961          synchronized (mDhcpResultsLock) {
   3962              if (mDhcpResults != null) {
   3963                  mDhcpResults.clear();
   3964              }
   3965          }
   3966          mNetlinkTracker.clearLinkProperties();
   3967 
   3968          // Now clear the merged link properties.
   3969          mLinkProperties.clear();
   3970          if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
   3971      }
   3972 
   3973      /**
   3974       * try to update default route MAC address.
   3975       */
   3976       private String updateDefaultRouteMacAddress(int timeout) {
   3977           String address = null;
   3978           for (RouteInfo route : mLinkProperties.getRoutes()) {
   3979               if (route.isDefaultRoute() && route.hasGateway()) {
   3980                   InetAddress gateway = route.getGateway();
   3981                   if (gateway instanceof Inet4Address) {
   3982                       if (PDBG) {
   3983                           loge("updateDefaultRouteMacAddress found Ipv4 default :"
   3984                                   + gateway.getHostAddress());
   3985                       }
   3986                       address = macAddressFromRoute(gateway.getHostAddress());
   3987                      /* The gateway's MAC address is known */
   3988                       if ((address == null) && (timeout > 0)) {
   3989                           boolean reachable = false;
   3990                           try {
   3991                               reachable = gateway.isReachable(timeout);
   3992                           } catch (Exception e) {
   3993                               loge("updateDefaultRouteMacAddress exception reaching :"
   3994                                       + gateway.getHostAddress());
   3995 
   3996                           } finally {
   3997                               if (reachable == true) {
   3998 
   3999                                   address = macAddressFromRoute(gateway.getHostAddress());
   4000                                   if (PDBG) {
   4001                                       loge("updateDefaultRouteMacAddress reachable (tried again) :"
   4002                                               + gateway.getHostAddress() + " found " + address);
   4003                                   }
   4004                               }
   4005                           }
   4006                       }
   4007                       if (address != null) {
   4008                           mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address);
   4009                       }
   4010                   }
   4011               }
   4012           }
   4013           return address;
   4014       }
   4015 
   4016     private void sendScanResultsAvailableBroadcast() {
   4017         Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
   4018         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   4019         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   4020     }
   4021 
   4022     private void sendRssiChangeBroadcast(final int newRssi) {
   4023         try {
   4024             mBatteryStats.noteWifiRssiChanged(newRssi);
   4025         } catch (RemoteException e) {
   4026             // Won't happen.
   4027         }
   4028         Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
   4029         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   4030         intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
   4031         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   4032     }
   4033 
   4034     private void sendNetworkStateChangeBroadcast(String bssid) {
   4035         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
   4036         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   4037         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
   4038         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
   4039         if (bssid != null)
   4040             intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
   4041         if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK ||
   4042                 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
   4043             intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo));
   4044         }
   4045         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   4046     }
   4047 
   4048     private void sendLinkConfigurationChangedBroadcast() {
   4049         Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
   4050         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   4051         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
   4052         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   4053     }
   4054 
   4055     private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
   4056         Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
   4057         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   4058         intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
   4059         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   4060     }
   4061 
   4062     /**
   4063      * Record the detailed state of a network.
   4064      * @param state the new {@code DetailedState}
   4065      */
   4066     private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {
   4067         boolean hidden = false;
   4068 
   4069         if (linkDebouncing || isRoaming()) {
   4070             // There is generally a confusion in the system about colluding
   4071             // WiFi Layer 2 state (as reported by supplicant) and the Network state
   4072             // which leads to multiple confusion.
   4073             //
   4074             // If link is de-bouncing or roaming, we already have an IP address
   4075             // as well we were connected and are doing L2 cycles of
   4076             // reconnecting or renewing IP address to check that we still have it
   4077             // This L2 link flapping should ne be reflected into the Network state
   4078             // which is the state of the WiFi Network visible to Layer 3 and applications
   4079             // Note that once debouncing and roaming are completed, we will
   4080             // set the Network state to where it should be, or leave it as unchanged
   4081             //
   4082             hidden = true;
   4083         }
   4084         if (DBG) {
   4085             log("setDetailed state, old ="
   4086                     + mNetworkInfo.getDetailedState() + " and new state=" + state
   4087                     + " hidden=" + hidden);
   4088         }
   4089         if (mNetworkInfo.getExtraInfo() != null && mWifiInfo.getSSID() != null) {
   4090             // Always indicate that SSID has changed
   4091             if (!mNetworkInfo.getExtraInfo().equals(mWifiInfo.getSSID())) {
   4092                 if (DBG) {
   4093                     log("setDetailed state send new extra info"  + mWifiInfo.getSSID());
   4094                 }
   4095                 mNetworkInfo.setExtraInfo(mWifiInfo.getSSID());
   4096                 sendNetworkStateChangeBroadcast(null);
   4097             }
   4098         }
   4099         if (hidden == true) {
   4100             return false;
   4101         }
   4102 
   4103         if (state != mNetworkInfo.getDetailedState()) {
   4104             mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());
   4105             if (mNetworkAgent != null) {
   4106                 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   4107             }
   4108             sendNetworkStateChangeBroadcast(null);
   4109             return true;
   4110         }
   4111         return false;
   4112     }
   4113 
   4114     private DetailedState getNetworkDetailedState() {
   4115         return mNetworkInfo.getDetailedState();
   4116     }
   4117 
   4118 
   4119     private SupplicantState handleSupplicantStateChange(Message message) {
   4120         StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   4121         SupplicantState state = stateChangeResult.state;
   4122         // Supplicant state change
   4123         // [31-13] Reserved for future use
   4124         // [8 - 0] Supplicant state (as defined in SupplicantState.java)
   4125         // 50023 supplicant_state_changed (custom|1|5)
   4126         mWifiInfo.setSupplicantState(state);
   4127         // Network id is only valid when we start connecting
   4128         if (SupplicantState.isConnecting(state)) {
   4129             mWifiInfo.setNetworkId(stateChangeResult.networkId);
   4130         } else {
   4131             mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
   4132         }
   4133 
   4134         mWifiInfo.setBSSID(stateChangeResult.BSSID);
   4135         mWifiInfo.setSSID(stateChangeResult.wifiSsid);
   4136 
   4137         mSupplicantStateTracker.sendMessage(Message.obtain(message));
   4138 
   4139         return state;
   4140     }
   4141 
   4142     /**
   4143      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
   4144      * using the interface, stopping DHCP & disabling interface
   4145      */
   4146     private void handleNetworkDisconnect() {
   4147         if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP"
   4148                 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
   4149                 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName()
   4150                 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName()
   4151                 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName());
   4152 
   4153 
   4154         clearCurrentConfigBSSID("handleNetworkDisconnect");
   4155 
   4156         stopDhcp();
   4157 
   4158         try {
   4159             mNwService.clearInterfaceAddresses(mInterfaceName);
   4160             mNwService.disableIpv6(mInterfaceName);
   4161         } catch (Exception e) {
   4162             loge("Failed to clear addresses or disable ipv6" + e);
   4163         }
   4164 
   4165         /* Reset data structures */
   4166         mBadLinkspeedcount = 0;
   4167         mWifiInfo.reset();
   4168         linkDebouncing = false;
   4169         /* Reset roaming parameters */
   4170         mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
   4171         fullBandConnectedTimeIntervalMilli = 20 * 1000; // Start scans at 20 seconds interval
   4172 
   4173         setNetworkDetailedState(DetailedState.DISCONNECTED);
   4174         if (mNetworkAgent != null) {
   4175             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   4176             mNetworkAgent = null;
   4177         }
   4178         mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
   4179 
   4180         /* Clear network properties */
   4181         clearLinkProperties();
   4182 
   4183         /* Cend event to CM & network change broadcast */
   4184         sendNetworkStateChangeBroadcast(mLastBssid);
   4185 
   4186         /* Cancel auto roam requests */
   4187         autoRoamSetBSSID(mLastNetworkId, "any");
   4188 
   4189         mLastBssid= null;
   4190         registerDisconnected();
   4191         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
   4192     }
   4193 
   4194     private void handleSupplicantConnectionLoss() {
   4195         /* Socket connection can be lost when we do a graceful shutdown
   4196         * or when the driver is hung. Ensure supplicant is stopped here.
   4197         */
   4198         mWifiMonitor.killSupplicant(mP2pSupported);
   4199         mWifiNative.closeSupplicantConnection();
   4200         sendSupplicantConnectionChangedBroadcast(false);
   4201         setWifiState(WIFI_STATE_DISABLED);
   4202     }
   4203 
   4204     void handlePreDhcpSetup() {
   4205         mDhcpActive = true;
   4206         if (!mBluetoothConnectionActive) {
   4207             /*
   4208              * There are problems setting the Wi-Fi driver's power
   4209              * mode to active when bluetooth coexistence mode is
   4210              * enabled or sense.
   4211              * <p>
   4212              * We set Wi-Fi to active mode when
   4213              * obtaining an IP address because we've found
   4214              * compatibility issues with some routers with low power
   4215              * mode.
   4216              * <p>
   4217              * In order for this active power mode to properly be set,
   4218              * we disable coexistence mode until we're done with
   4219              * obtaining an IP address.  One exception is if we
   4220              * are currently connected to a headset, since disabling
   4221              * coexistence would interrupt that connection.
   4222              */
   4223             // Disable the coexistence mode
   4224             mWifiNative.setBluetoothCoexistenceMode(
   4225                     mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
   4226         }
   4227 
   4228         // Disable power save and suspend optimizations during DHCP
   4229         // Note: The order here is important for now. Brcm driver changes
   4230         // power settings when we control suspend mode optimizations.
   4231         // TODO: Remove this comment when the driver is fixed.
   4232         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
   4233         mWifiNative.setPowerSave(false);
   4234 
   4235         stopBatchedScan();
   4236         WifiNative.pauseScan();
   4237 
   4238         /* P2p discovery breaks dhcp, shut it down in order to get through this */
   4239         Message msg = new Message();
   4240         msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY;
   4241         msg.arg1 = WifiP2pServiceImpl.ENABLED;
   4242         msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE;
   4243         msg.obj = mDhcpStateMachine;
   4244         mWifiP2pChannel.sendMessage(msg);
   4245     }
   4246 
   4247 
   4248     void startDhcp() {
   4249         if (mDhcpStateMachine == null) {
   4250             mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
   4251                     mContext, WifiStateMachine.this, mInterfaceName);
   4252 
   4253         }
   4254         mDhcpStateMachine.registerForPreDhcpNotification();
   4255         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
   4256     }
   4257 
   4258     void renewDhcp() {
   4259         if (mDhcpStateMachine == null) {
   4260             mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
   4261                     mContext, WifiStateMachine.this, mInterfaceName);
   4262 
   4263         }
   4264         mDhcpStateMachine.registerForPreDhcpNotification();
   4265         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP);
   4266     }
   4267 
   4268     void stopDhcp() {
   4269         if (mDhcpStateMachine != null) {
   4270             /* In case we were in middle of DHCP operation restore back powermode */
   4271             handlePostDhcpSetup();
   4272             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
   4273         }
   4274     }
   4275 
   4276     void handlePostDhcpSetup() {
   4277         /* Restore power save and suspend optimizations */
   4278         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
   4279         mWifiNative.setPowerSave(true);
   4280 
   4281         mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED);
   4282 
   4283         // Set the coexistence mode back to its default value
   4284         mWifiNative.setBluetoothCoexistenceMode(
   4285                 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
   4286 
   4287         mDhcpActive = false;
   4288 
   4289         startBatchedScan();
   4290         WifiNative.restartScan();
   4291     }
   4292 
   4293     private void handleIPv4Success(DhcpResults dhcpResults, int reason) {
   4294 
   4295         if (PDBG) {
   4296             loge("wifistatemachine handleIPv4Success <" + dhcpResults.toString() + ">");
   4297             loge("link address " + dhcpResults.ipAddress);
   4298         }
   4299 
   4300         synchronized (mDhcpResultsLock) {
   4301             mDhcpResults = dhcpResults;
   4302         }
   4303 
   4304         Inet4Address addr = (Inet4Address) dhcpResults.ipAddress.getAddress();
   4305         if (isRoaming()) {
   4306             if (addr instanceof Inet4Address) {
   4307                 int previousAddress = mWifiInfo.getIpAddress();
   4308                 int newAddress = NetworkUtils.inetAddressToInt(addr);
   4309                 if (previousAddress != newAddress) {
   4310                     loge("handleIPv4Success, roaming and address changed" +
   4311                             mWifiInfo + " got: " + addr);
   4312                 } else {
   4313 
   4314                 }
   4315             } else {
   4316                 loge("handleIPv4Success, roaming and didnt get an IPv4 address" +
   4317                         addr.toString());
   4318             }
   4319         }
   4320         mWifiInfo.setInetAddress(addr);
   4321         mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
   4322         updateLinkProperties(reason);
   4323     }
   4324 
   4325     private void handleSuccessfulIpConfiguration() {
   4326         mLastSignalLevel = -1; // Force update of signal strength
   4327         WifiConfiguration c = getCurrentWifiConfiguration();
   4328         // Reset IP failure tracking
   4329         if (c != null) {
   4330             c.numConnectionFailures = 0;
   4331         }
   4332         if (c != null) {
   4333             ScanResult result = getCurrentScanResult();
   4334             if (result == null) {
   4335                 loge("WifiStateMachine: handleSuccessfulIpConfiguration and no scan results" +
   4336                         c.configKey());
   4337             } else {
   4338                 // Clear the per BSSID failure count
   4339                 result.numIpConfigFailures = 0;
   4340                 // Clear the WHOLE BSSID blacklist, which means supplicant is free to retry
   4341                 // any BSSID, even though it may already have a non zero ip failure count,
   4342                 // this will typically happen if the user walks away and come back to his arrea
   4343                 // TODO: implement blacklisting based on a timer, i.e. keep BSSID blacklisted
   4344                 // in supplicant for a couple of hours or a day
   4345                 mWifiNative.clearBlacklist();
   4346             }
   4347         }
   4348     }
   4349 
   4350     private void handleIPv4Failure(int reason) {
   4351         synchronized(mDhcpResultsLock) {
   4352              if (mDhcpResults != null) {
   4353                  mDhcpResults.clear();
   4354              }
   4355         }
   4356         if (PDBG) {
   4357             loge("wifistatemachine handleIPv4Failure");
   4358         }
   4359         updateLinkProperties(reason);
   4360     }
   4361 
   4362     private void handleIpConfigurationLost() {
   4363         mWifiInfo.setInetAddress(null);
   4364         mWifiInfo.setMeteredHint(false);
   4365 
   4366         mWifiConfigStore.handleSSIDStateChange(mLastNetworkId, false,
   4367                 "DHCP FAILURE", mWifiInfo.getBSSID());
   4368 
   4369         /* DHCP times out after about 30 seconds, we do a
   4370          * disconnect thru supplicant, we will let autojoin retry connecting to the network
   4371          */
   4372         mWifiNative.disconnect();
   4373     }
   4374 
   4375     /* Current design is to not set the config on a running hostapd but instead
   4376      * stop and start tethering when user changes config on a running access point
   4377      *
   4378      * TODO: Add control channel setup through hostapd that allows changing config
   4379      * on a running daemon
   4380      */
   4381     private void startSoftApWithConfig(final WifiConfiguration config) {
   4382         // Start hostapd on a separate thread
   4383         new Thread(new Runnable() {
   4384             public void run() {
   4385                 try {
   4386                     mNwService.startAccessPoint(config, mInterfaceName);
   4387                 } catch (Exception e) {
   4388                     loge("Exception in softap start " + e);
   4389                     try {
   4390                         mNwService.stopAccessPoint(mInterfaceName);
   4391                         mNwService.startAccessPoint(config, mInterfaceName);
   4392                     } catch (Exception e1) {
   4393                         loge("Exception in softap re-start " + e1);
   4394                         sendMessage(CMD_START_AP_FAILURE);
   4395                         return;
   4396                     }
   4397                 }
   4398                 if (DBG) log("Soft AP start successful");
   4399                 sendMessage(CMD_START_AP_SUCCESS);
   4400             }
   4401         }).start();
   4402     }
   4403 
   4404     /*
   4405      * Read a MAC address in /proc/arp/table, used by WifistateMachine
   4406      * so as to record MAC address of default gateway.
   4407      **/
   4408     private String macAddressFromRoute(String ipAddress) {
   4409         String macAddress = null;
   4410         BufferedReader reader = null;
   4411         try {
   4412             reader = new BufferedReader(new FileReader("/proc/net/arp"));
   4413 
   4414             // Skip over the line bearing colum titles
   4415             String line = reader.readLine();
   4416 
   4417             while ((line = reader.readLine()) != null) {
   4418                 String[] tokens = line.split("[ ]+");
   4419                 if (tokens.length < 6) {
   4420                     continue;
   4421                 }
   4422 
   4423                 // ARP column format is
   4424                 // Address HWType HWAddress Flags Mask IFace
   4425                 String ip = tokens[0];
   4426                 String mac = tokens[3];
   4427 
   4428                 if (ipAddress.equals(ip)) {
   4429                     macAddress = mac;
   4430                     break;
   4431                 }
   4432             }
   4433 
   4434             if (macAddress == null) {
   4435                 loge("Did not find remoteAddress {" + ipAddress + "} in " +
   4436                         "/proc/net/arp");
   4437             }
   4438 
   4439         } catch (FileNotFoundException e) {
   4440             loge("Could not open /proc/net/arp to lookup mac address");
   4441         } catch (IOException e) {
   4442             loge("Could not read /proc/net/arp to lookup mac address");
   4443         } finally {
   4444             try {
   4445                 if (reader != null) {
   4446                     reader.close();
   4447                 }
   4448             } catch (IOException e) {
   4449                 // Do nothing
   4450             }
   4451         }
   4452         return macAddress;
   4453 
   4454     }
   4455 
   4456     private class WifiNetworkFactory extends NetworkFactory {
   4457         public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) {
   4458             super(l, c, TAG, f);
   4459         }
   4460         protected void startNetwork() {
   4461             // TODO
   4462             // Enter association mode.
   4463         }
   4464         protected void stopNetwork() {
   4465             // TODO
   4466             // Stop associating.
   4467         }
   4468     }
   4469     /********************************************************
   4470      * HSM states
   4471      *******************************************************/
   4472 
   4473     class DefaultState extends State {
   4474         @Override
   4475         public boolean processMessage(Message message) {
   4476             logStateAndMessage(message, getClass().getSimpleName());
   4477 
   4478             switch (message.what) {
   4479                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
   4480                     AsyncChannel ac = (AsyncChannel) message.obj;
   4481                     if (ac == mWifiP2pChannel) {
   4482                         if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
   4483                             mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
   4484                         } else {
   4485                             loge("WifiP2pService connection failure, error=" + message.arg1);
   4486                         }
   4487                     } else {
   4488                         loge("got HALF_CONNECTED for unknown channel");
   4489                     }
   4490                     break;
   4491                 }
   4492                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
   4493                     AsyncChannel ac = (AsyncChannel) message.obj;
   4494                     if (ac == mWifiP2pChannel) {
   4495                         loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
   4496                         //TODO: Re-establish connection to state machine after a delay
   4497                         // mWifiP2pChannel.connect(mContext, getHandler(),
   4498                         // mWifiP2pManager.getMessenger());
   4499                     }
   4500                     break;
   4501                 }
   4502                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
   4503                     mBluetoothConnectionActive = (message.arg1 !=
   4504                             BluetoothAdapter.STATE_DISCONNECTED);
   4505                     break;
   4506                     /* Synchronous call returns */
   4507                 case CMD_PING_SUPPLICANT:
   4508                 case CMD_ENABLE_NETWORK:
   4509                 case CMD_ADD_OR_UPDATE_NETWORK:
   4510                 case CMD_REMOVE_NETWORK:
   4511                 case CMD_SAVE_CONFIG:
   4512                     replyToMessage(message, message.what, FAILURE);
   4513                     break;
   4514                 case CMD_GET_CAPABILITY_FREQ:
   4515                     replyToMessage(message, message.what, null);
   4516                     break;
   4517                 case CMD_GET_CONFIGURED_NETWORKS:
   4518                     replyToMessage(message, message.what, (List<WifiConfiguration>) null);
   4519                     break;
   4520                 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
   4521                     replyToMessage(message, message.what, (List<WifiConfiguration>) null);
   4522                     break;
   4523                 case CMD_ENABLE_RSSI_POLL:
   4524                     mEnableRssiPolling = (message.arg1 == 1);
   4525                     break;
   4526                 case CMD_SET_HIGH_PERF_MODE:
   4527                     if (message.arg1 == 1) {
   4528                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);
   4529                     } else {
   4530                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);
   4531                     }
   4532                     break;
   4533                 case CMD_BOOT_COMPLETED:
   4534                     String countryCode = mPersistedCountryCode;
   4535                     if (TextUtils.isEmpty(countryCode) == false) {
   4536                         Settings.Global.putString(mContext.getContentResolver(),
   4537                                 Settings.Global.WIFI_COUNTRY_CODE,
   4538                                 countryCode);
   4539                         // It may be that the state transition that should send this info
   4540                         // to the driver happened between mPersistedCountryCode getting set
   4541                         // and now, so simply persisting it here would mean we have sent
   4542                         // nothing to the driver.  Send the cmd so it might be set now.
   4543                         int sequenceNum = mCountryCodeSequence.incrementAndGet();
   4544                         sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE,
   4545                                 sequenceNum, 0, countryCode);
   4546                     }
   4547 
   4548                     checkAndSetConnectivityInstance();
   4549                     mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext,
   4550                             NETWORKTYPE, mNetworkCapabilitiesFilter);
   4551                     mNetworkFactory.setScoreFilter(60);
   4552                     mCm.registerNetworkFactory(new Messenger(mNetworkFactory), NETWORKTYPE);
   4553                     break;
   4554                 case CMD_SET_BATCHED_SCAN:
   4555                     recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj);
   4556                     break;
   4557                 case CMD_POLL_BATCHED_SCAN:
   4558                     handleBatchedScanPollRequest();
   4559                     break;
   4560                 case CMD_START_NEXT_BATCHED_SCAN:
   4561                     startNextBatchedScan();
   4562                     break;
   4563                 case CMD_SCREEN_STATE_CHANGED:
   4564                     handleScreenStateChanged(message.arg1 != 0,
   4565                             /* startBackgroundScanIfNeeded = */ false);
   4566                     break;
   4567                     /* Discard */
   4568                 case CMD_START_SCAN:
   4569                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   4570                     break;
   4571                 case CMD_START_SUPPLICANT:
   4572                 case CMD_STOP_SUPPLICANT:
   4573                 case CMD_STOP_SUPPLICANT_FAILED:
   4574                 case CMD_START_DRIVER:
   4575                 case CMD_STOP_DRIVER:
   4576                 case CMD_DELAYED_STOP_DRIVER:
   4577                 case CMD_DRIVER_START_TIMED_OUT:
   4578                 case CMD_START_AP:
   4579                 case CMD_START_AP_SUCCESS:
   4580                 case CMD_START_AP_FAILURE:
   4581                 case CMD_STOP_AP:
   4582                 case CMD_TETHER_STATE_CHANGE:
   4583                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   4584                 case CMD_DISCONNECT:
   4585                 case CMD_RECONNECT:
   4586                 case CMD_REASSOCIATE:
   4587                 case CMD_RELOAD_TLS_AND_RECONNECT:
   4588                 case WifiMonitor.SUP_CONNECTION_EVENT:
   4589                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   4590                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   4591                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   4592                 case WifiMonitor.SCAN_RESULTS_EVENT:
   4593                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   4594                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   4595                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   4596                 case WifiMonitor.WPS_OVERLAP_EVENT:
   4597                 case CMD_BLACKLIST_NETWORK:
   4598                 case CMD_CLEAR_BLACKLIST:
   4599                 case CMD_SET_OPERATIONAL_MODE:
   4600                 case CMD_SET_COUNTRY_CODE:
   4601                 case CMD_SET_FREQUENCY_BAND:
   4602                 case CMD_RSSI_POLL:
   4603                 case CMD_ENABLE_ALL_NETWORKS:
   4604                 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   4605                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   4606                 /* Handled by WifiApConfigStore */
   4607                 case CMD_SET_AP_CONFIG:
   4608                 case CMD_SET_AP_CONFIG_COMPLETED:
   4609                 case CMD_REQUEST_AP_CONFIG:
   4610                 case CMD_RESPONSE_AP_CONFIG:
   4611                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
   4612                 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
   4613                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
   4614                 case CMD_DISABLE_P2P_RSP:
   4615                 case WifiMonitor.SUP_REQUEST_IDENTITY:
   4616                 case CMD_TEST_NETWORK_DISCONNECT:
   4617                 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
   4618                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
   4619                 case CMD_TARGET_BSSID:
   4620                 case CMD_AUTO_CONNECT:
   4621                 case CMD_AUTO_ROAM:
   4622                 case CMD_AUTO_SAVE_NETWORK:
   4623                 case CMD_ASSOCIATED_BSSID:
   4624                 case CMD_UNWANTED_NETWORK:
   4625                 case CMD_DISCONNECTING_WATCHDOG_TIMER:
   4626                 case CMD_ROAM_WATCHDOG_TIMER:
   4627                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   4628                     break;
   4629                 case DhcpStateMachine.CMD_ON_QUIT:
   4630                     mDhcpStateMachine = null;
   4631                     break;
   4632                 case CMD_SET_SUSPEND_OPT_ENABLED:
   4633                     if (message.arg1 == 1) {
   4634                         mSuspendWakeLock.release();
   4635                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true);
   4636                     } else {
   4637                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false);
   4638                     }
   4639                     break;
   4640                 case WifiMonitor.DRIVER_HUNG_EVENT:
   4641                     setSupplicantRunning(false);
   4642                     setSupplicantRunning(true);
   4643                     break;
   4644                 case WifiManager.CONNECT_NETWORK:
   4645                     replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   4646                             WifiManager.BUSY);
   4647                     break;
   4648                 case WifiManager.FORGET_NETWORK:
   4649                     replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
   4650                             WifiManager.BUSY);
   4651                     break;
   4652                 case WifiManager.SAVE_NETWORK:
   4653                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   4654                     replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
   4655                             WifiManager.BUSY);
   4656                     break;
   4657                 case WifiManager.START_WPS:
   4658                     replyToMessage(message, WifiManager.WPS_FAILED,
   4659                             WifiManager.BUSY);
   4660                     break;
   4661                 case WifiManager.CANCEL_WPS:
   4662                     replyToMessage(message, WifiManager.CANCEL_WPS_FAILED,
   4663                             WifiManager.BUSY);
   4664                     break;
   4665                 case WifiManager.DISABLE_NETWORK:
   4666                     replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
   4667                             WifiManager.BUSY);
   4668                     break;
   4669                 case WifiManager.RSSI_PKTCNT_FETCH:
   4670                     replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED,
   4671                             WifiManager.BUSY);
   4672                     break;
   4673                 case CMD_GET_SUPPORTED_FEATURES:
   4674                     if (WifiNative.startHal()) {
   4675                         int featureSet = WifiNative.getSupportedFeatureSet();
   4676                         replyToMessage(message, message.what, featureSet);
   4677                     } else {
   4678                         replyToMessage(message, message.what, 0);
   4679                     }
   4680                     break;
   4681                 case CMD_GET_LINK_LAYER_STATS:
   4682                     // Not supported hence reply with error message
   4683                     replyToMessage(message, message.what, null);
   4684                     break;
   4685                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
   4686                     NetworkInfo info = (NetworkInfo) message.obj;
   4687                     mP2pConnected.set(info.isConnected());
   4688                     break;
   4689                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
   4690                     mTemporarilyDisconnectWifi = (message.arg1 == 1);
   4691                     replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
   4692                     break;
   4693                 /* Link configuration (IP address, DNS, ...) changes notified via netlink */
   4694                 case CMD_UPDATE_LINKPROPERTIES:
   4695                     updateLinkProperties(CMD_UPDATE_LINKPROPERTIES);
   4696                     break;
   4697                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
   4698                 case CMD_IP_CONFIGURATION_LOST:
   4699                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   4700                     break;
   4701                 case CMD_GET_CONNECTION_STATISTICS:
   4702                     replyToMessage(message, message.what, mWifiConnectionStatistics);
   4703                     break;
   4704                 default:
   4705                     loge("Error! unhandled message" + message);
   4706                     break;
   4707             }
   4708             return HANDLED;
   4709         }
   4710     }
   4711 
   4712     class InitialState extends State {
   4713         @Override
   4714         public void enter() {
   4715             mWifiNative.unloadDriver();
   4716 
   4717             if (mWifiP2pChannel == null) {
   4718                 mWifiP2pChannel = new AsyncChannel();
   4719                 mWifiP2pChannel.connect(mContext, getHandler(),
   4720                     mWifiP2pServiceImpl.getP2pStateMachineMessenger());
   4721             }
   4722 
   4723             if (mWifiApConfigChannel == null) {
   4724                 mWifiApConfigChannel = new AsyncChannel();
   4725                 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
   4726                         mContext, getHandler());
   4727                 wifiApConfigStore.loadApConfiguration();
   4728                 mWifiApConfigChannel.connectSync(mContext, getHandler(),
   4729                         wifiApConfigStore.getMessenger());
   4730             }
   4731         }
   4732         @Override
   4733         public boolean processMessage(Message message) {
   4734             logStateAndMessage(message, getClass().getSimpleName());
   4735             switch (message.what) {
   4736                 case CMD_START_SUPPLICANT:
   4737                     if (mWifiNative.loadDriver()) {
   4738                         try {
   4739                             mNwService.wifiFirmwareReload(mInterfaceName, "STA");
   4740                         } catch (Exception e) {
   4741                             loge("Failed to reload STA firmware " + e);
   4742                             // Continue
   4743                         }
   4744 
   4745                         try {
   4746                             // A runtime crash can leave the interface up and
   4747                             // IP addresses configured, and this affects
   4748                             // connectivity when supplicant starts up.
   4749                             // Ensure interface is down and we have no IP
   4750                             // addresses before a supplicant start.
   4751                             mNwService.setInterfaceDown(mInterfaceName);
   4752                             mNwService.clearInterfaceAddresses(mInterfaceName);
   4753 
   4754                             // Set privacy extensions
   4755                             mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
   4756 
   4757                            // IPv6 is enabled only as long as access point is connected since:
   4758                            // - IPv6 addresses and routes stick around after disconnection
   4759                            // - kernel is unaware when connected and fails to start IPv6 negotiation
   4760                            // - kernel can start autoconfiguration when 802.1x is not complete
   4761                             mNwService.disableIpv6(mInterfaceName);
   4762                         } catch (RemoteException re) {
   4763                             loge("Unable to change interface settings: " + re);
   4764                         } catch (IllegalStateException ie) {
   4765                             loge("Unable to change interface settings: " + ie);
   4766                         }
   4767 
   4768                        /* Stop a running supplicant after a runtime restart
   4769                         * Avoids issues with drivers that do not handle interface down
   4770                         * on a running supplicant properly.
   4771                         */
   4772                         mWifiMonitor.killSupplicant(mP2pSupported);
   4773                         if(mWifiNative.startSupplicant(mP2pSupported)) {
   4774                             setWifiState(WIFI_STATE_ENABLING);
   4775                             if (DBG) log("Supplicant start successful");
   4776                             mWifiMonitor.startMonitoring();
   4777                             transitionTo(mSupplicantStartingState);
   4778                         } else {
   4779                             loge("Failed to start supplicant!");
   4780                         }
   4781                     } else {
   4782                         loge("Failed to load driver");
   4783                     }
   4784                     break;
   4785                 case CMD_START_AP:
   4786                     if (mWifiNative.loadDriver()) {
   4787                         setWifiApState(WIFI_AP_STATE_ENABLING);
   4788                         transitionTo(mSoftApStartingState);
   4789                     } else {
   4790                         loge("Failed to load driver for softap");
   4791                     }
   4792                 default:
   4793                     return NOT_HANDLED;
   4794             }
   4795             return HANDLED;
   4796         }
   4797     }
   4798 
   4799     class SupplicantStartingState extends State {
   4800         private void initializeWpsDetails() {
   4801             String detail;
   4802             detail = SystemProperties.get("ro.product.name", "");
   4803             if (!mWifiNative.setDeviceName(detail)) {
   4804                 loge("Failed to set device name " +  detail);
   4805             }
   4806             detail = SystemProperties.get("ro.product.manufacturer", "");
   4807             if (!mWifiNative.setManufacturer(detail)) {
   4808                 loge("Failed to set manufacturer " + detail);
   4809             }
   4810             detail = SystemProperties.get("ro.product.model", "");
   4811             if (!mWifiNative.setModelName(detail)) {
   4812                 loge("Failed to set model name " + detail);
   4813             }
   4814             detail = SystemProperties.get("ro.product.model", "");
   4815             if (!mWifiNative.setModelNumber(detail)) {
   4816                 loge("Failed to set model number " + detail);
   4817             }
   4818             detail = SystemProperties.get("ro.serialno", "");
   4819             if (!mWifiNative.setSerialNumber(detail)) {
   4820                 loge("Failed to set serial number " + detail);
   4821             }
   4822             if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) {
   4823                 loge("Failed to set WPS config methods");
   4824             }
   4825             if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
   4826                 loge("Failed to set primary device type " + mPrimaryDeviceType);
   4827             }
   4828         }
   4829 
   4830         @Override
   4831         public boolean processMessage(Message message) {
   4832             logStateAndMessage(message, getClass().getSimpleName());
   4833 
   4834             switch(message.what) {
   4835                 case WifiMonitor.SUP_CONNECTION_EVENT:
   4836                     if (DBG) log("Supplicant connection established");
   4837                     setWifiState(WIFI_STATE_ENABLED);
   4838                     mSupplicantRestartCount = 0;
   4839                     /* Reset the supplicant state to indicate the supplicant
   4840                      * state is not known at this time */
   4841                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
   4842                     /* Initialize data structures */
   4843                     mLastBssid = null;
   4844                     mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
   4845                     mLastSignalLevel = -1;
   4846 
   4847                     mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
   4848                     mWifiNative.enableSaveConfig();
   4849                     mWifiConfigStore.loadAndEnableAllNetworks();
   4850                     if (mWifiConfigStore.enableVerboseLogging > 0) {
   4851                         enableVerboseLogging(mWifiConfigStore.enableVerboseLogging);
   4852                     }
   4853                     if (mWifiConfigStore.associatedPartialScanPeriodMilli < 0) {
   4854                         mWifiConfigStore.associatedPartialScanPeriodMilli = 0;
   4855                     }
   4856                     initializeWpsDetails();
   4857 
   4858                     sendSupplicantConnectionChangedBroadcast(true);
   4859                     transitionTo(mDriverStartedState);
   4860                     break;
   4861                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   4862                     if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
   4863                         loge("Failed to setup control channel, restart supplicant");
   4864                         mWifiMonitor.killSupplicant(mP2pSupported);
   4865                         transitionTo(mInitialState);
   4866                         sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
   4867                     } else {
   4868                         loge("Failed " + mSupplicantRestartCount +
   4869                                 " times to start supplicant, unload driver");
   4870                         mSupplicantRestartCount = 0;
   4871                         setWifiState(WIFI_STATE_UNKNOWN);
   4872                         transitionTo(mInitialState);
   4873                     }
   4874                     break;
   4875                 case CMD_START_SUPPLICANT:
   4876                 case CMD_STOP_SUPPLICANT:
   4877                 case CMD_START_AP:
   4878                 case CMD_STOP_AP:
   4879                 case CMD_START_DRIVER:
   4880                 case CMD_STOP_DRIVER:
   4881                 case CMD_SET_OPERATIONAL_MODE:
   4882                 case CMD_SET_COUNTRY_CODE:
   4883                 case CMD_SET_FREQUENCY_BAND:
   4884                 case CMD_START_PACKET_FILTERING:
   4885                 case CMD_STOP_PACKET_FILTERING:
   4886                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   4887                     deferMessage(message);
   4888                     break;
   4889                 default:
   4890                     return NOT_HANDLED;
   4891             }
   4892             return HANDLED;
   4893         }
   4894     }
   4895 
   4896     class SupplicantStartedState extends State {
   4897         @Override
   4898         public void enter() {
   4899             /* Wifi is available as long as we have a connection to supplicant */
   4900             mNetworkInfo.setIsAvailable(true);
   4901             if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   4902 
   4903             int defaultInterval = mContext.getResources().getInteger(
   4904                     R.integer.config_wifi_supplicant_scan_interval);
   4905 
   4906             mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
   4907                     Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
   4908                     defaultInterval);
   4909 
   4910             mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
   4911             mWifiNative.setExternalSim(true);
   4912 
   4913             setRandomMacOui();
   4914             mWifiNative.enableAutoConnect(false);
   4915         }
   4916 
   4917         @Override
   4918         public boolean processMessage(Message message) {
   4919             logStateAndMessage(message, getClass().getSimpleName());
   4920 
   4921             switch(message.what) {
   4922                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
   4923                     if (mP2pSupported) {
   4924                         transitionTo(mWaitForP2pDisableState);
   4925                     } else {
   4926                         transitionTo(mSupplicantStoppingState);
   4927                     }
   4928                     break;
   4929                 case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
   4930                     loge("Connection lost, restart supplicant");
   4931                     handleSupplicantConnectionLoss();
   4932                     handleNetworkDisconnect();
   4933                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
   4934                     if (mP2pSupported) {
   4935                         transitionTo(mWaitForP2pDisableState);
   4936                     } else {
   4937                         transitionTo(mInitialState);
   4938                     }
   4939                     sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
   4940                     break;
   4941                 case WifiMonitor.SCAN_RESULTS_EVENT:
   4942                     closeRadioScanStats();
   4943                     noteScanEnd();
   4944                     setScanResults();
   4945                     if (mIsFullScanOngoing) {
   4946                         /* Just updated results from full scan, let apps know about this */
   4947                         sendScanResultsAvailableBroadcast();
   4948                     }
   4949                     mIsScanOngoing = false;
   4950                     mIsFullScanOngoing = false;
   4951                     if (mBufferedScanMsg.size() > 0)
   4952                         sendMessage(mBufferedScanMsg.remove());
   4953                     break;
   4954                 case CMD_PING_SUPPLICANT:
   4955                     boolean ok = mWifiNative.ping();
   4956                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
   4957                     break;
   4958                 case CMD_GET_CAPABILITY_FREQ:
   4959                     String freqs = mWifiNative.getFreqCapability();
   4960                     replyToMessage(message, message.what, freqs);
   4961                     break;
   4962                 case CMD_START_AP:
   4963                     /* Cannot start soft AP while in client mode */
   4964                     loge("Failed to start soft AP with a running supplicant");
   4965                     setWifiApState(WIFI_AP_STATE_FAILED);
   4966                     break;
   4967                 case CMD_SET_OPERATIONAL_MODE:
   4968                     mOperationalMode = message.arg1;
   4969                     break;
   4970                 case CMD_TARGET_BSSID:
   4971                     // Trying to associate to this BSSID
   4972                     if (message.obj != null) {
   4973                         mTargetRoamBSSID = (String) message.obj;
   4974                     }
   4975                     break;
   4976                 case CMD_GET_LINK_LAYER_STATS:
   4977                     WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG);
   4978                     if (stats == null) {
   4979                         // When firmware doesnt support link layer stats, return an empty object
   4980                         stats = new WifiLinkLayerStats();
   4981                     }
   4982                     replyToMessage(message, message.what, stats);
   4983                     break;
   4984                 default:
   4985                     return NOT_HANDLED;
   4986             }
   4987             return HANDLED;
   4988         }
   4989 
   4990         @Override
   4991         public void exit() {
   4992             mNetworkInfo.setIsAvailable(false);
   4993             if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   4994         }
   4995     }
   4996 
   4997     class SupplicantStoppingState extends State {
   4998         @Override
   4999         public void enter() {
   5000             /* Send any reset commands to supplicant before shutting it down */
   5001             handleNetworkDisconnect();
   5002             if (mDhcpStateMachine != null) {
   5003                 mDhcpStateMachine.doQuit();
   5004             }
   5005 
   5006             if (DBG) log("stopping supplicant");
   5007             mWifiMonitor.stopSupplicant();
   5008 
   5009             /* Send ourselves a delayed message to indicate failure after a wait time */
   5010             sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
   5011                     ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
   5012             setWifiState(WIFI_STATE_DISABLING);
   5013             mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
   5014         }
   5015         @Override
   5016         public boolean processMessage(Message message) {
   5017             logStateAndMessage(message, getClass().getSimpleName());
   5018 
   5019             switch(message.what) {
   5020                 case WifiMonitor.SUP_CONNECTION_EVENT:
   5021                     loge("Supplicant connection received while stopping");
   5022                     break;
   5023                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   5024                     if (DBG) log("Supplicant connection lost");
   5025                     handleSupplicantConnectionLoss();
   5026                     transitionTo(mInitialState);
   5027                     break;
   5028                 case CMD_STOP_SUPPLICANT_FAILED:
   5029                     if (message.arg1 == mSupplicantStopFailureToken) {
   5030                         loge("Timed out on a supplicant stop, kill and proceed");
   5031                         handleSupplicantConnectionLoss();
   5032                         transitionTo(mInitialState);
   5033                     }
   5034                     break;
   5035                 case CMD_START_SUPPLICANT:
   5036                 case CMD_STOP_SUPPLICANT:
   5037                 case CMD_START_AP:
   5038                 case CMD_STOP_AP:
   5039                 case CMD_START_DRIVER:
   5040                 case CMD_STOP_DRIVER:
   5041                 case CMD_SET_OPERATIONAL_MODE:
   5042                 case CMD_SET_COUNTRY_CODE:
   5043                 case CMD_SET_FREQUENCY_BAND:
   5044                 case CMD_START_PACKET_FILTERING:
   5045                 case CMD_STOP_PACKET_FILTERING:
   5046                     deferMessage(message);
   5047                     break;
   5048                 default:
   5049                     return NOT_HANDLED;
   5050             }
   5051             return HANDLED;
   5052         }
   5053     }
   5054 
   5055     class DriverStartingState extends State {
   5056         private int mTries;
   5057         @Override
   5058         public void enter() {
   5059             mTries = 1;
   5060             /* Send ourselves a delayed message to start driver a second time */
   5061             sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
   5062                         ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
   5063         }
   5064         @Override
   5065         public boolean processMessage(Message message) {
   5066             logStateAndMessage(message, getClass().getSimpleName());
   5067 
   5068             switch(message.what) {
   5069                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   5070                     SupplicantState state = handleSupplicantStateChange(message);
   5071                     /* If suplicant is exiting out of INTERFACE_DISABLED state into
   5072                      * a state that indicates driver has started, it is ready to
   5073                      * receive driver commands
   5074                      */
   5075                     if (SupplicantState.isDriverActive(state)) {
   5076                         transitionTo(mDriverStartedState);
   5077                     }
   5078                     break;
   5079                 case CMD_DRIVER_START_TIMED_OUT:
   5080                     if (message.arg1 == mDriverStartToken) {
   5081                         if (mTries >= 2) {
   5082                             loge("Failed to start driver after " + mTries);
   5083                             transitionTo(mDriverStoppedState);
   5084                         } else {
   5085                             loge("Driver start failed, retrying");
   5086                             mWakeLock.acquire();
   5087                             mWifiNative.startDriver();
   5088                             mWakeLock.release();
   5089 
   5090                             ++mTries;
   5091                             /* Send ourselves a delayed message to start driver again */
   5092                             sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
   5093                                         ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
   5094                         }
   5095                     }
   5096                     break;
   5097                     /* Queue driver commands & connection events */
   5098                 case CMD_START_DRIVER:
   5099                 case CMD_STOP_DRIVER:
   5100                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   5101                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   5102                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   5103                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   5104                 case WifiMonitor.WPS_OVERLAP_EVENT:
   5105                 case CMD_SET_COUNTRY_CODE:
   5106                 case CMD_SET_FREQUENCY_BAND:
   5107                 case CMD_START_PACKET_FILTERING:
   5108                 case CMD_STOP_PACKET_FILTERING:
   5109                 case CMD_START_SCAN:
   5110                 case CMD_DISCONNECT:
   5111                 case CMD_REASSOCIATE:
   5112                 case CMD_RECONNECT:
   5113                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   5114                     deferMessage(message);
   5115                     break;
   5116                 case WifiMonitor.SCAN_RESULTS_EVENT:
   5117                     // Loose scan results obtained in Driver Starting state, they can only confuse
   5118                     // the state machine
   5119                     break;
   5120                 default:
   5121                     return NOT_HANDLED;
   5122             }
   5123             return HANDLED;
   5124         }
   5125     }
   5126 
   5127     class DriverStartedState extends State {
   5128         @Override
   5129         public void enter() {
   5130 
   5131             if (PDBG) {
   5132                 loge("Driverstarted State enter");
   5133             }
   5134             mIsRunning = true;
   5135             mInDelayedStop = false;
   5136             mDelayedStopCounter++;
   5137             updateBatteryWorkSource(null);
   5138             /**
   5139              * Enable bluetooth coexistence scan mode when bluetooth connection is active.
   5140              * When this mode is on, some of the low-level scan parameters used by the
   5141              * driver are changed to reduce interference with bluetooth
   5142              */
   5143             mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
   5144             /* set country code */
   5145             setCountryCode();
   5146             /* set frequency band of operation */
   5147             setFrequencyBand();
   5148             /* initialize network state */
   5149             setNetworkDetailedState(DetailedState.DISCONNECTED);
   5150 
   5151             /* Remove any filtering on Multicast v6 at start */
   5152             mWifiNative.stopFilteringMulticastV6Packets();
   5153 
   5154             /* Reset Multicast v4 filtering state */
   5155             if (mFilteringMulticastV4Packets.get()) {
   5156                 mWifiNative.startFilteringMulticastV4Packets();
   5157             } else {
   5158                 mWifiNative.stopFilteringMulticastV4Packets();
   5159             }
   5160 
   5161             mDhcpActive = false;
   5162 
   5163             startBatchedScan();
   5164 
   5165             if (mOperationalMode != CONNECT_MODE) {
   5166                 mWifiNative.disconnect();
   5167                 mWifiConfigStore.disableAllNetworks();
   5168                 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
   5169                     setWifiState(WIFI_STATE_DISABLED);
   5170                 }
   5171                 transitionTo(mScanModeState);
   5172             } else {
   5173 
   5174                 // Status pulls in the current supplicant state and network connection state
   5175                 // events over the monitor connection. This helps framework sync up with
   5176                 // current supplicant state
   5177                 // TODO: actually check th supplicant status string and make sure the supplicant
   5178                 // is in disconnecte4d state.
   5179                 mWifiNative.status();
   5180                 // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin
   5181                 transitionTo(mDisconnectedState);
   5182             }
   5183 
   5184             // We may have missed screen update at boot
   5185             if (mScreenBroadcastReceived.get() == false) {
   5186                 PowerManager powerManager = (PowerManager)mContext.getSystemService(
   5187                         Context.POWER_SERVICE);
   5188                 handleScreenStateChanged(powerManager.isScreenOn(),
   5189                         /* startBackgroundScanIfNeeded = */ false);
   5190             } else {
   5191                 // Set the right suspend mode settings
   5192                 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
   5193                         && mUserWantsSuspendOpt.get());
   5194             }
   5195             mWifiNative.setPowerSave(true);
   5196 
   5197             if (mP2pSupported) {
   5198                 if (mOperationalMode == CONNECT_MODE) {
   5199                     mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
   5200                 } else {
   5201                     // P2P statemachine starts in disabled state, and is not enabled until
   5202                     // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
   5203                     // keep it disabled.
   5204                 }
   5205             }
   5206 
   5207             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
   5208             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   5209             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
   5210             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   5211 
   5212             if (PDBG) {
   5213                 loge("Driverstarted State enter done");
   5214             }
   5215         }
   5216 
   5217         @Override
   5218         public boolean processMessage(Message message) {
   5219             logStateAndMessage(message, getClass().getSimpleName());
   5220 
   5221             switch(message.what) {
   5222                 case CMD_START_SCAN:
   5223                     handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
   5224                     break;
   5225                 case CMD_SET_BATCHED_SCAN:
   5226                     if (recordBatchedScanSettings(message.arg1, message.arg2,
   5227                             (Bundle)message.obj)) {
   5228                         if (mBatchedScanSettings != null) {
   5229                             startBatchedScan();
   5230                         } else {
   5231                             stopBatchedScan();
   5232                         }
   5233                     }
   5234                     break;
   5235                 case CMD_SET_COUNTRY_CODE:
   5236                     String country = (String) message.obj;
   5237                     final boolean persist = (message.arg2 == 1);
   5238                     final int sequence = message.arg1;
   5239                     if (sequence != mCountryCodeSequence.get()) {
   5240                         if (DBG) log("set country code ignored due to sequnce num");
   5241                         break;
   5242                     }
   5243                     if (DBG) log("set country code " + country);
   5244                     if (persist) {
   5245                         mPersistedCountryCode = country;
   5246                         Settings.Global.putString(mContext.getContentResolver(),
   5247                                 Settings.Global.WIFI_COUNTRY_CODE,
   5248                                 country);
   5249                     }
   5250                     country = country.toUpperCase(Locale.ROOT);
   5251                     if (mLastSetCountryCode == null
   5252                             || country.equals(mLastSetCountryCode) == false) {
   5253                         if (mWifiNative.setCountryCode(country)) {
   5254                             mLastSetCountryCode = country;
   5255                         } else {
   5256                             loge("Failed to set country code " + country);
   5257                         }
   5258                     }
   5259                     mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country);
   5260                     break;
   5261                 case CMD_SET_FREQUENCY_BAND:
   5262                     int band =  message.arg1;
   5263                     if (DBG) log("set frequency band " + band);
   5264                     if (mWifiNative.setBand(band)) {
   5265 
   5266                         if (PDBG)  loge("did set frequency band " + band);
   5267 
   5268                         mFrequencyBand.set(band);
   5269                         // Flush old data - like scan results
   5270                         mWifiNative.bssFlush();
   5271                         // Fetch the latest scan results when frequency band is set
   5272                         startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null);
   5273 
   5274                         if (PDBG)  loge("done set frequency band " + band);
   5275 
   5276                     } else {
   5277                         loge("Failed to set frequency band " + band);
   5278                     }
   5279                     break;
   5280                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
   5281                     mBluetoothConnectionActive = (message.arg1 !=
   5282                             BluetoothAdapter.STATE_DISCONNECTED);
   5283                     mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
   5284                     break;
   5285                 case CMD_STOP_DRIVER:
   5286                     int mode = message.arg1;
   5287 
   5288                     /* Already doing a delayed stop */
   5289                     if (mInDelayedStop) {
   5290                         if (DBG) log("Already in delayed stop");
   5291                         break;
   5292                     }
   5293                     /* disconnect right now, but leave the driver running for a bit */
   5294                     mWifiConfigStore.disableAllNetworks();
   5295 
   5296                     mInDelayedStop = true;
   5297                     mDelayedStopCounter++;
   5298                     if (DBG) log("Delayed stop message " + mDelayedStopCounter);
   5299 
   5300                     /* send regular delayed shut down */
   5301                     Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
   5302                     driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
   5303                     mDriverStopIntent = PendingIntent.getBroadcast(mContext,
   5304                             DRIVER_STOP_REQUEST, driverStopIntent,
   5305                             PendingIntent.FLAG_UPDATE_CURRENT);
   5306 
   5307                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
   5308                             + mDriverStopDelayMs, mDriverStopIntent);
   5309                     break;
   5310                 case CMD_START_DRIVER:
   5311                     if (mInDelayedStop) {
   5312                         mInDelayedStop = false;
   5313                         mDelayedStopCounter++;
   5314                         mAlarmManager.cancel(mDriverStopIntent);
   5315                         if (DBG) log("Delayed stop ignored due to start");
   5316                         if (mOperationalMode == CONNECT_MODE) {
   5317                             mWifiConfigStore.enableAllNetworks();
   5318                         }
   5319                     }
   5320                     break;
   5321                 case CMD_DELAYED_STOP_DRIVER:
   5322                     if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter);
   5323                     if (message.arg1 != mDelayedStopCounter) break;
   5324                     if (getCurrentState() != mDisconnectedState) {
   5325                         mWifiNative.disconnect();
   5326                         handleNetworkDisconnect();
   5327                     }
   5328                     mWakeLock.acquire();
   5329                     mWifiNative.stopDriver();
   5330                     mWakeLock.release();
   5331                     if (mP2pSupported) {
   5332                         transitionTo(mWaitForP2pDisableState);
   5333                     } else {
   5334                         transitionTo(mDriverStoppingState);
   5335                     }
   5336                     break;
   5337                 case CMD_START_PACKET_FILTERING:
   5338                     if (message.arg1 == MULTICAST_V6) {
   5339                         mWifiNative.startFilteringMulticastV6Packets();
   5340                     } else if (message.arg1 == MULTICAST_V4) {
   5341                         mWifiNative.startFilteringMulticastV4Packets();
   5342                     } else {
   5343                         loge("Illegal arugments to CMD_START_PACKET_FILTERING");
   5344                     }
   5345                     break;
   5346                 case CMD_STOP_PACKET_FILTERING:
   5347                     if (message.arg1 == MULTICAST_V6) {
   5348                         mWifiNative.stopFilteringMulticastV6Packets();
   5349                     } else if (message.arg1 == MULTICAST_V4) {
   5350                         mWifiNative.stopFilteringMulticastV4Packets();
   5351                     } else {
   5352                         loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
   5353                     }
   5354                     break;
   5355                 case CMD_SET_SUSPEND_OPT_ENABLED:
   5356                     if (message.arg1 == 1) {
   5357                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
   5358                         mSuspendWakeLock.release();
   5359                     } else {
   5360                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
   5361                     }
   5362                     break;
   5363                 case CMD_SET_HIGH_PERF_MODE:
   5364                     if (message.arg1 == 1) {
   5365                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
   5366                     } else {
   5367                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
   5368                     }
   5369                     break;
   5370                 case CMD_ENABLE_TDLS:
   5371                     if (message.obj != null) {
   5372                         String remoteAddress = (String) message.obj;
   5373                         boolean enable = (message.arg1 == 1);
   5374                         mWifiNative.startTdls(remoteAddress, enable);
   5375                     }
   5376                     break;
   5377                 default:
   5378                     return NOT_HANDLED;
   5379             }
   5380             return HANDLED;
   5381         }
   5382         @Override
   5383         public void exit() {
   5384             mIsRunning = false;
   5385             updateBatteryWorkSource(null);
   5386             mScanResults = new ArrayList<ScanResult>();
   5387 
   5388             stopBatchedScan();
   5389 
   5390             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
   5391             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   5392             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
   5393             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   5394             noteScanEnd(); // wrap up any pending request.
   5395             mBufferedScanMsg.clear();
   5396 
   5397             mLastSetCountryCode = null;
   5398         }
   5399     }
   5400 
   5401     class WaitForP2pDisableState extends State {
   5402         private State mTransitionToState;
   5403         @Override
   5404         public void enter() {
   5405             switch (getCurrentMessage().what) {
   5406                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   5407                     mTransitionToState = mInitialState;
   5408                     break;
   5409                 case CMD_DELAYED_STOP_DRIVER:
   5410                     mTransitionToState = mDriverStoppingState;
   5411                     break;
   5412                 case CMD_STOP_SUPPLICANT:
   5413                     mTransitionToState = mSupplicantStoppingState;
   5414                     break;
   5415                 default:
   5416                     mTransitionToState = mDriverStoppingState;
   5417                     break;
   5418             }
   5419             mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
   5420         }
   5421         @Override
   5422         public boolean processMessage(Message message) {
   5423             logStateAndMessage(message, getClass().getSimpleName());
   5424 
   5425             switch(message.what) {
   5426                 case WifiStateMachine.CMD_DISABLE_P2P_RSP:
   5427                     transitionTo(mTransitionToState);
   5428                     break;
   5429                 /* Defer wifi start/shut and driver commands */
   5430                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   5431                 case CMD_START_SUPPLICANT:
   5432                 case CMD_STOP_SUPPLICANT:
   5433                 case CMD_START_AP:
   5434                 case CMD_STOP_AP:
   5435                 case CMD_START_DRIVER:
   5436                 case CMD_STOP_DRIVER:
   5437                 case CMD_SET_OPERATIONAL_MODE:
   5438                 case CMD_SET_COUNTRY_CODE:
   5439                 case CMD_SET_FREQUENCY_BAND:
   5440                 case CMD_START_PACKET_FILTERING:
   5441                 case CMD_STOP_PACKET_FILTERING:
   5442                 case CMD_START_SCAN:
   5443                 case CMD_DISCONNECT:
   5444                 case CMD_REASSOCIATE:
   5445                 case CMD_RECONNECT:
   5446                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   5447                     deferMessage(message);
   5448                     break;
   5449                 default:
   5450                     return NOT_HANDLED;
   5451             }
   5452             return HANDLED;
   5453         }
   5454     }
   5455 
   5456     class DriverStoppingState extends State {
   5457         @Override
   5458         public boolean processMessage(Message message) {
   5459             logStateAndMessage(message, getClass().getSimpleName());
   5460 
   5461             switch(message.what) {
   5462                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   5463                     SupplicantState state = handleSupplicantStateChange(message);
   5464                     if (state == SupplicantState.INTERFACE_DISABLED) {
   5465                         transitionTo(mDriverStoppedState);
   5466                     }
   5467                     break;
   5468                     /* Queue driver commands */
   5469                 case CMD_START_DRIVER:
   5470                 case CMD_STOP_DRIVER:
   5471                 case CMD_SET_COUNTRY_CODE:
   5472                 case CMD_SET_FREQUENCY_BAND:
   5473                 case CMD_START_PACKET_FILTERING:
   5474                 case CMD_STOP_PACKET_FILTERING:
   5475                 case CMD_START_SCAN:
   5476                 case CMD_DISCONNECT:
   5477                 case CMD_REASSOCIATE:
   5478                 case CMD_RECONNECT:
   5479                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   5480                     deferMessage(message);
   5481                     break;
   5482                 default:
   5483                     return NOT_HANDLED;
   5484             }
   5485             return HANDLED;
   5486         }
   5487     }
   5488 
   5489     class DriverStoppedState extends State {
   5490         @Override
   5491         public boolean processMessage(Message message) {
   5492             logStateAndMessage(message, getClass().getSimpleName());
   5493             switch (message.what) {
   5494                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   5495                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   5496                     SupplicantState state = stateChangeResult.state;
   5497                     // A WEXT bug means that we can be back to driver started state
   5498                     // unexpectedly
   5499                     if (SupplicantState.isDriverActive(state)) {
   5500                         transitionTo(mDriverStartedState);
   5501                     }
   5502                     break;
   5503                 case CMD_START_DRIVER:
   5504                     mWakeLock.acquire();
   5505                     mWifiNative.startDriver();
   5506                     mWakeLock.release();
   5507                     transitionTo(mDriverStartingState);
   5508                     break;
   5509                 default:
   5510                     return NOT_HANDLED;
   5511             }
   5512             return HANDLED;
   5513         }
   5514     }
   5515 
   5516     class ScanModeState extends State {
   5517         private int mLastOperationMode;
   5518         @Override
   5519         public void enter() {
   5520             mLastOperationMode = mOperationalMode;
   5521         }
   5522         @Override
   5523         public boolean processMessage(Message message) {
   5524             logStateAndMessage(message, getClass().getSimpleName());
   5525 
   5526             switch(message.what) {
   5527                 case CMD_SET_OPERATIONAL_MODE:
   5528                     if (message.arg1 == CONNECT_MODE) {
   5529 
   5530                         if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
   5531                             setWifiState(WIFI_STATE_ENABLED);
   5532                             // Load and re-enable networks when going back to enabled state
   5533                             // This is essential for networks to show up after restore
   5534                             mWifiConfigStore.loadAndEnableAllNetworks();
   5535                             mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
   5536                         } else {
   5537                             mWifiConfigStore.enableAllNetworks();
   5538                         }
   5539 
   5540                         mWifiNative.reconnect();
   5541 
   5542                         mOperationalMode = CONNECT_MODE;
   5543                         transitionTo(mDisconnectedState);
   5544                     } else {
   5545                         // Nothing to do
   5546                         return HANDLED;
   5547                     }
   5548                     break;
   5549                 // Handle scan. All the connection related commands are
   5550                 // handled only in ConnectModeState
   5551                 case CMD_START_SCAN:
   5552                     handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
   5553                     break;
   5554                 default:
   5555                     return NOT_HANDLED;
   5556             }
   5557             return HANDLED;
   5558         }
   5559     }
   5560 
   5561 
   5562     String smToString(Message message) {
   5563         return smToString(message.what);
   5564     }
   5565 
   5566     String smToString(int what) {
   5567         String s = "unknown";
   5568         switch (what) {
   5569             case WifiMonitor.DRIVER_HUNG_EVENT:
   5570                 s = "DRIVER_HUNG_EVENT";
   5571                 break;
   5572             case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
   5573                 s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED";
   5574                 break;
   5575             case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
   5576                 s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED";
   5577                 break;
   5578             case CMD_SET_FREQUENCY_BAND:
   5579                 s = "CMD_SET_FREQUENCY_BAND";
   5580                 break;
   5581             case CMD_DELAYED_NETWORK_DISCONNECT:
   5582                 s = "CMD_DELAYED_NETWORK_DISCONNECT";
   5583                 break;
   5584             case CMD_TEST_NETWORK_DISCONNECT:
   5585                 s = "CMD_TEST_NETWORK_DISCONNECT";
   5586                 break;
   5587             case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
   5588                 s = "CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER";
   5589                 break;
   5590             case CMD_START_DRIVER:
   5591                 s = "CMD_START_DRIVER";
   5592                 break;
   5593             case CMD_STOP_DRIVER:
   5594                 s = "CMD_STOP_DRIVER";
   5595                 break;
   5596             case CMD_STOP_SUPPLICANT:
   5597                 s = "CMD_STOP_SUPPLICANT";
   5598                 break;
   5599             case CMD_STOP_SUPPLICANT_FAILED:
   5600                 s = "CMD_STOP_SUPPLICANT_FAILED";
   5601                 break;
   5602             case CMD_START_SUPPLICANT:
   5603                 s = "CMD_START_SUPPLICANT";
   5604                 break;
   5605             case CMD_REQUEST_AP_CONFIG:
   5606                 s = "CMD_REQUEST_AP_CONFIG";
   5607                 break;
   5608             case CMD_RESPONSE_AP_CONFIG:
   5609                 s = "CMD_RESPONSE_AP_CONFIG";
   5610                 break;
   5611             case CMD_TETHER_STATE_CHANGE:
   5612                 s = "CMD_TETHER_STATE_CHANGE";
   5613                 break;
   5614             case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   5615                 s = "CMD_TETHER_NOTIFICATION_TIMED_OUT";
   5616                 break;
   5617             case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
   5618                 s = "CMD_BLUETOOTH_ADAPTER_STATE_CHANGE";
   5619                 break;
   5620             case CMD_ADD_OR_UPDATE_NETWORK:
   5621                 s = "CMD_ADD_OR_UPDATE_NETWORK";
   5622                 break;
   5623             case CMD_REMOVE_NETWORK:
   5624                 s = "CMD_REMOVE_NETWORK";
   5625                 break;
   5626             case CMD_ENABLE_NETWORK:
   5627                 s = "CMD_ENABLE_NETWORK";
   5628                 break;
   5629             case CMD_ENABLE_ALL_NETWORKS:
   5630                 s = "CMD_ENABLE_ALL_NETWORKS";
   5631                 break;
   5632             case CMD_AUTO_CONNECT:
   5633                 s = "CMD_AUTO_CONNECT";
   5634                 break;
   5635             case CMD_AUTO_ROAM:
   5636                 s = "CMD_AUTO_ROAM";
   5637                 break;
   5638             case CMD_AUTO_SAVE_NETWORK:
   5639                 s = "CMD_AUTO_SAVE_NETWORK";
   5640                 break;
   5641             case CMD_BOOT_COMPLETED:
   5642                 s = "CMD_BOOT_COMPLETED";
   5643                 break;
   5644             case DhcpStateMachine.CMD_START_DHCP:
   5645                 s = "CMD_START_DHCP";
   5646                 break;
   5647             case DhcpStateMachine.CMD_STOP_DHCP:
   5648                 s = "CMD_STOP_DHCP";
   5649                 break;
   5650             case DhcpStateMachine.CMD_RENEW_DHCP:
   5651                 s = "CMD_RENEW_DHCP";
   5652                 break;
   5653             case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   5654                 s = "CMD_PRE_DHCP_ACTION";
   5655                 break;
   5656             case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   5657                 s = "CMD_POST_DHCP_ACTION";
   5658                 break;
   5659             case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
   5660                 s = "CMD_PRE_DHCP_ACTION_COMPLETE";
   5661                 break;
   5662             case DhcpStateMachine.CMD_ON_QUIT:
   5663                 s = "CMD_ON_QUIT";
   5664                 break;
   5665             case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
   5666                 s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST";
   5667                 break;
   5668             case WifiManager.DISABLE_NETWORK:
   5669                 s = "WifiManager.DISABLE_NETWORK";
   5670                 break;
   5671             case CMD_BLACKLIST_NETWORK:
   5672                 s = "CMD_BLACKLIST_NETWORK";
   5673                 break;
   5674             case CMD_CLEAR_BLACKLIST:
   5675                 s = "CMD_CLEAR_BLACKLIST";
   5676                 break;
   5677             case CMD_SAVE_CONFIG:
   5678                 s = "CMD_SAVE_CONFIG";
   5679                 break;
   5680             case CMD_GET_CONFIGURED_NETWORKS:
   5681                 s = "CMD_GET_CONFIGURED_NETWORKS";
   5682                 break;
   5683             case CMD_GET_SUPPORTED_FEATURES:
   5684                 s = "CMD_GET_ADAPTORS";
   5685                 break;
   5686             case CMD_UNWANTED_NETWORK:
   5687                 s = "CMD_UNWANTED_NETWORK";
   5688                 break;
   5689             case CMD_GET_LINK_LAYER_STATS:
   5690                 s = "CMD_GET_LINK_LAYER_STATS";
   5691                 break;
   5692             case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
   5693                 s = "CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS";
   5694                 break;
   5695             case CMD_DISCONNECT:
   5696                 s = "CMD_DISCONNECT";
   5697                 break;
   5698             case CMD_RECONNECT:
   5699                 s = "CMD_RECONNECT";
   5700                 break;
   5701             case CMD_REASSOCIATE:
   5702                 s = "CMD_REASSOCIATE";
   5703                 break;
   5704             case CMD_GET_CONNECTION_STATISTICS:
   5705                 s = "CMD_GET_CONNECTION_STATISTICS";
   5706                 break;
   5707             case CMD_SET_HIGH_PERF_MODE:
   5708                 s = "CMD_SET_HIGH_PERF_MODE";
   5709                 break;
   5710             case CMD_SET_COUNTRY_CODE:
   5711                 s = "CMD_SET_COUNTRY_CODE";
   5712                 break;
   5713             case CMD_ENABLE_RSSI_POLL:
   5714                 s = "CMD_ENABLE_RSSI_POLL";
   5715                 break;
   5716             case CMD_RSSI_POLL:
   5717                 s = "CMD_RSSI_POLL";
   5718                 break;
   5719             case CMD_START_PACKET_FILTERING:
   5720                 s = "CMD_START_PACKET_FILTERING";
   5721                 break;
   5722             case CMD_STOP_PACKET_FILTERING:
   5723                 s = "CMD_STOP_PACKET_FILTERING";
   5724                 break;
   5725             case CMD_SET_SUSPEND_OPT_ENABLED:
   5726                 s = "CMD_SET_SUSPEND_OPT_ENABLED";
   5727                 break;
   5728             case CMD_NO_NETWORKS_PERIODIC_SCAN:
   5729                 s = "CMD_NO_NETWORKS_PERIODIC_SCAN";
   5730                 break;
   5731             case CMD_SET_BATCHED_SCAN:
   5732                 s = "CMD_SET_BATCHED_SCAN";
   5733                 break;
   5734             case CMD_START_NEXT_BATCHED_SCAN:
   5735                 s = "CMD_START_NEXT_BATCHED_SCAN";
   5736                 break;
   5737             case CMD_POLL_BATCHED_SCAN:
   5738                 s = "CMD_POLL_BATCHED_SCAN";
   5739                 break;
   5740             case CMD_UPDATE_LINKPROPERTIES:
   5741                 s = "CMD_UPDATE_LINKPROPERTIES";
   5742                 break;
   5743             case CMD_RELOAD_TLS_AND_RECONNECT:
   5744                 s = "CMD_RELOAD_TLS_AND_RECONNECT";
   5745                 break;
   5746             case WifiManager.CONNECT_NETWORK:
   5747                 s = "CONNECT_NETWORK";
   5748                 break;
   5749             case WifiManager.SAVE_NETWORK:
   5750                 s = "SAVE_NETWORK";
   5751                 break;
   5752             case WifiManager.FORGET_NETWORK:
   5753                 s = "FORGET_NETWORK";
   5754                 break;
   5755             case WifiMonitor.SUP_CONNECTION_EVENT:
   5756                 s = "SUP_CONNECTION_EVENT";
   5757                 break;
   5758             case WifiMonitor.SUP_DISCONNECTION_EVENT:
   5759                 s = "SUP_DISCONNECTION_EVENT";
   5760                 break;
   5761             case WifiMonitor.SCAN_RESULTS_EVENT:
   5762                 s = "SCAN_RESULTS_EVENT";
   5763                 break;
   5764             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   5765                 s = "SUPPLICANT_STATE_CHANGE_EVENT";
   5766                 break;
   5767             case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   5768                 s = "AUTHENTICATION_FAILURE_EVENT";
   5769                 break;
   5770             case WifiMonitor.SSID_TEMP_DISABLED:
   5771                 s = "SSID_TEMP_DISABLED";
   5772                 break;
   5773             case WifiMonitor.SSID_REENABLED:
   5774                 s = "SSID_REENABLED";
   5775                 break;
   5776             case WifiMonitor.WPS_SUCCESS_EVENT:
   5777                 s = "WPS_SUCCESS_EVENT";
   5778                 break;
   5779             case WifiMonitor.WPS_FAIL_EVENT:
   5780                 s = "WPS_FAIL_EVENT";
   5781                 break;
   5782             case WifiMonitor.SUP_REQUEST_IDENTITY:
   5783                 s = "SUP_REQUEST_IDENTITY";
   5784                 break;
   5785             case WifiMonitor.NETWORK_CONNECTION_EVENT:
   5786                 s = "NETWORK_CONNECTION_EVENT";
   5787                 break;
   5788             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   5789                 s = "NETWORK_DISCONNECTION_EVENT";
   5790                 break;
   5791             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   5792                 s = "ASSOCIATION_REJECTION_EVENT";
   5793                 break;
   5794             case CMD_SET_OPERATIONAL_MODE:
   5795                 s = "CMD_SET_OPERATIONAL_MODE";
   5796                 break;
   5797             case CMD_START_SCAN:
   5798                 s = "CMD_START_SCAN";
   5799                 break;
   5800             case CMD_DISABLE_P2P_RSP:
   5801                 s = "CMD_DISABLE_P2P_RSP";
   5802                 break;
   5803             case CMD_DISABLE_P2P_REQ:
   5804                 s = "CMD_DISABLE_P2P_REQ";
   5805                 break;
   5806             case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
   5807                 s = "GOOD_LINK_DETECTED";
   5808                 break;
   5809             case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
   5810                 s = "POOR_LINK_DETECTED";
   5811                 break;
   5812             case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT:
   5813                 s = "GROUP_CREATING_TIMED_OUT";
   5814                 break;
   5815             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
   5816                 s = "P2P_CONNECTION_CHANGED";
   5817                 break;
   5818             case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE:
   5819                 s = "P2P.DISCONNECT_WIFI_RESPONSE";
   5820                 break;
   5821             case WifiP2pServiceImpl.SET_MIRACAST_MODE:
   5822                 s = "P2P.SET_MIRACAST_MODE";
   5823                 break;
   5824             case WifiP2pServiceImpl.BLOCK_DISCOVERY:
   5825                 s = "P2P.BLOCK_DISCOVERY";
   5826                 break;
   5827             case WifiP2pServiceImpl.SET_COUNTRY_CODE:
   5828                 s = "P2P.SET_COUNTRY_CODE";
   5829                 break;
   5830             case WifiManager.CANCEL_WPS:
   5831                 s = "CANCEL_WPS";
   5832                 break;
   5833             case WifiManager.CANCEL_WPS_FAILED:
   5834                 s = "CANCEL_WPS_FAILED";
   5835                 break;
   5836             case WifiManager.CANCEL_WPS_SUCCEDED:
   5837                 s = "CANCEL_WPS_SUCCEDED";
   5838                 break;
   5839             case WifiManager.START_WPS:
   5840                 s = "START_WPS";
   5841                 break;
   5842             case WifiManager.START_WPS_SUCCEEDED:
   5843                 s = "START_WPS_SUCCEEDED";
   5844                 break;
   5845             case WifiManager.WPS_FAILED:
   5846                 s = "WPS_FAILED";
   5847                 break;
   5848             case WifiManager.WPS_COMPLETED:
   5849                 s = "WPS_COMPLETED";
   5850                 break;
   5851             case WifiManager.RSSI_PKTCNT_FETCH:
   5852                 s = "RSSI_PKTCNT_FETCH";
   5853                 break;
   5854             case CMD_IP_CONFIGURATION_LOST:
   5855                 s = "CMD_IP_CONFIGURATION_LOST";
   5856                 break;
   5857             case CMD_IP_CONFIGURATION_SUCCESSFUL:
   5858                 s = "CMD_IP_CONFIGURATION_SUCCESSFUL";
   5859                 break;
   5860             case CMD_STATIC_IP_SUCCESS:
   5861                 s = "CMD_STATIC_IP_SUCCESSFUL";
   5862                 break;
   5863             case CMD_STATIC_IP_FAILURE:
   5864                 s = "CMD_STATIC_IP_FAILURE";
   5865                 break;
   5866             case DhcpStateMachine.DHCP_SUCCESS:
   5867                 s = "DHCP_SUCCESS";
   5868                 break;
   5869             case DhcpStateMachine.DHCP_FAILURE:
   5870                 s = "DHCP_FAILURE";
   5871                 break;
   5872             case CMD_TARGET_BSSID:
   5873                 s = "CMD_TARGET_BSSID";
   5874                 break;
   5875             case CMD_ASSOCIATED_BSSID:
   5876                 s = "CMD_ASSOCIATED_BSSID";
   5877                 break;
   5878             case CMD_ROAM_WATCHDOG_TIMER:
   5879                 s = "CMD_ROAM_WATCHDOG_TIMER";
   5880                 break;
   5881             case CMD_SCREEN_STATE_CHANGED:
   5882                 s = "CMD_SCREEN_STATE_CHANGED";
   5883                 break;
   5884             case CMD_DISCONNECTING_WATCHDOG_TIMER:
   5885                 s = "CMD_DISCONNECTING_WATCHDOG_TIMER";
   5886                 break;
   5887             default:
   5888                 s = "what:" + Integer.toString(what);
   5889                 break;
   5890         }
   5891         return s;
   5892     }
   5893 
   5894     void registerConnected() {
   5895        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
   5896            long now_ms = System.currentTimeMillis();
   5897            // We are switching away from this configuration,
   5898            // hence record the time we were connected last
   5899            WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId);
   5900            if (config != null) {
   5901                config.lastConnected = System.currentTimeMillis();
   5902                config.autoJoinBailedDueToLowRssi = false;
   5903                config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
   5904                config.numConnectionFailures = 0;
   5905                config.numIpConfigFailures = 0;
   5906                config.numAuthFailures = 0;
   5907                config.numAssociation++;
   5908            }
   5909            mBadLinkspeedcount = 0;
   5910        }
   5911     }
   5912 
   5913     void registerDisconnected() {
   5914         if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
   5915             long now_ms = System.currentTimeMillis();
   5916             // We are switching away from this configuration,
   5917             // hence record the time we were connected last
   5918             WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId);
   5919             if (config != null) {
   5920                 config.lastDisconnected = System.currentTimeMillis();
   5921             }
   5922         }
   5923     }
   5924 
   5925     void noteWifiDisabledWhileAssociated() {
   5926         // We got disabled by user while we were associated, make note of it
   5927         int rssi = mWifiInfo.getRssi();
   5928         WifiConfiguration config = getCurrentWifiConfiguration();
   5929         if (getCurrentState() == mConnectedState
   5930                 && rssi != WifiInfo.INVALID_RSSI
   5931                 && config != null) {
   5932             boolean is24GHz = mWifiInfo.is24GHz();
   5933             boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24)
   5934                     || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5);
   5935             boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24)
   5936                     || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5);
   5937             boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24)
   5938                     || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5);
   5939             if (isBadRSSI) {
   5940                 // Take note that we got disabled while RSSI was Bad
   5941                 config.numUserTriggeredWifiDisableLowRSSI++;
   5942             } else if (isLowRSSI) {
   5943                 // Take note that we got disabled while RSSI was Low
   5944                 config.numUserTriggeredWifiDisableBadRSSI++;
   5945             } else if (!isHighRSSI) {
   5946                 // Take note that we got disabled while RSSI was Not high
   5947                 config.numUserTriggeredWifiDisableNotHighRSSI++;
   5948             }
   5949         }
   5950     }
   5951 
   5952     void setInternetAccessState(boolean enabled) {
   5953         WifiConfiguration config = getCurrentWifiConfiguration();
   5954         if (config != null) {
   5955             config.noInternetAccess = enabled;
   5956         }
   5957     }
   5958 
   5959     WifiConfiguration getCurrentWifiConfiguration() {
   5960         if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
   5961             return null;
   5962         }
   5963         return mWifiConfigStore.getWifiConfiguration(mLastNetworkId);
   5964     }
   5965 
   5966     ScanResult getCurrentScanResult() {
   5967         WifiConfiguration config = getCurrentWifiConfiguration();
   5968         if (config == null) {
   5969             return null;
   5970         }
   5971         String BSSID = mWifiInfo.getBSSID();
   5972         if (BSSID == null) {
   5973             BSSID = mTargetRoamBSSID;
   5974         }
   5975         if (config.scanResultCache == null) {
   5976             return null;
   5977         }
   5978         return config.scanResultCache.get(BSSID);
   5979     }
   5980 
   5981     String getCurrentBSSID() {
   5982         if (linkDebouncing) {
   5983             return null;
   5984         }
   5985         return mLastBssid;
   5986     }
   5987 
   5988     class ConnectModeState extends State {
   5989         @Override
   5990         public boolean processMessage(Message message) {
   5991             WifiConfiguration config;
   5992             int netId;
   5993             boolean ok;
   5994             boolean didDisconnect;
   5995             String bssid;
   5996             String ssid;
   5997             NetworkUpdateResult result;
   5998             logStateAndMessage(message, getClass().getSimpleName());
   5999 
   6000             switch (message.what) {
   6001                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   6002                     didBlackListBSSID = false;
   6003                     bssid = (String) message.obj;
   6004                     if (bssid == null || TextUtils.isEmpty(bssid)) {
   6005                         // If BSSID is null, use the target roam BSSID
   6006                         bssid = mTargetRoamBSSID;
   6007                     }
   6008                     if (bssid != null) {
   6009                         // If we have a BSSID, tell configStore to black list it
   6010                         synchronized(mScanResultCache) {
   6011                             didBlackListBSSID = mWifiConfigStore.handleBSSIDBlackList
   6012                                     (mLastNetworkId, bssid, false);
   6013                         }
   6014                     }
   6015                     mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
   6016                     break;
   6017                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   6018                     mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
   6019                     break;
   6020                 case WifiMonitor.SSID_TEMP_DISABLED:
   6021                 case WifiMonitor.SSID_REENABLED:
   6022                     String substr = (String) message.obj;
   6023                     String en = message.what == WifiMonitor.SSID_TEMP_DISABLED ?
   6024                             "temp-disabled" : "re-enabled";
   6025                     loge("ConnectModeState SSID state=" + en + " nid="
   6026                             + Integer.toString(message.arg1) + " [" + substr + "]");
   6027                     synchronized(mScanResultCache) {
   6028                         mWifiConfigStore.handleSSIDStateChange(message.arg1, message.what ==
   6029                                 WifiMonitor.SSID_REENABLED, substr, mWifiInfo.getBSSID());
   6030                     }
   6031                     break;
   6032                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   6033                     SupplicantState state = handleSupplicantStateChange(message);
   6034                     // A driver/firmware hang can now put the interface in a down state.
   6035                     // We detect the interface going down and recover from it
   6036                     if (!SupplicantState.isDriverActive(state)) {
   6037                         if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
   6038                             handleNetworkDisconnect();
   6039                         }
   6040                         log("Detected an interface down, restart driver");
   6041                         transitionTo(mDriverStoppedState);
   6042                         sendMessage(CMD_START_DRIVER);
   6043                         break;
   6044                     }
   6045 
   6046                     // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
   6047                     // when authentication times out after a successful connection,
   6048                     // we can figure this from the supplicant state. If supplicant
   6049                     // state is DISCONNECTED, but the mNetworkInfo says we are not
   6050                     // disconnected, we need to handle a disconnection
   6051                     if (!linkDebouncing && state == SupplicantState.DISCONNECTED &&
   6052                             mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
   6053                         if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
   6054                         handleNetworkDisconnect();
   6055                         transitionTo(mDisconnectedState);
   6056                     }
   6057                     break;
   6058                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
   6059                     if (message.arg1 == 1) {
   6060                         mWifiNative.disconnect();
   6061                         mTemporarilyDisconnectWifi = true;
   6062                     } else {
   6063                         mWifiNative.reconnect();
   6064                         mTemporarilyDisconnectWifi = false;
   6065                     }
   6066                     break;
   6067                 case CMD_ADD_OR_UPDATE_NETWORK:
   6068                     config = (WifiConfiguration) message.obj;
   6069                     int res = mWifiConfigStore.addOrUpdateNetwork(config, message.sendingUid);
   6070                     if (res < 0) {
   6071                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   6072                     } else {
   6073                         WifiConfiguration curConfig = getCurrentWifiConfiguration();
   6074                         if (curConfig != null && config != null) {
   6075                             if (curConfig.priority < config.priority
   6076                                     && config.status == WifiConfiguration.Status.ENABLED) {
   6077                                 // Interpret this as a connect attempt
   6078                                 // Set the last selected configuration so as to allow the system to
   6079                                 // stick the last user choice without persisting the choice
   6080                                 mWifiConfigStore.setLastSelectedConfiguration(res);
   6081 
   6082                                 // Remember time of last connection attempt
   6083                                 lastConnectAttempt = System.currentTimeMillis();
   6084 
   6085                                 mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
   6086 
   6087                                 // As a courtesy to the caller, trigger a scan now
   6088                                 startScan(ADD_OR_UPDATE_SOURCE, 0, null, null);
   6089                             }
   6090                         }
   6091                     }
   6092                     replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res);
   6093                     break;
   6094                 case CMD_REMOVE_NETWORK:
   6095                     ok = mWifiConfigStore.removeNetwork(message.arg1);
   6096                     if (!ok) {
   6097                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   6098                     }
   6099                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
   6100                     break;
   6101                 case CMD_ENABLE_NETWORK:
   6102                     boolean others = message.arg2 == 1;
   6103                     // Tell autojoin the user did try to select to that network
   6104                     // However, do NOT persist the choice by bumping the priority of the network
   6105                     if (others) {
   6106                         mWifiAutoJoinController.
   6107                                 updateConfigurationHistory(message.arg1, true, false);
   6108                         // Set the last selected configuration so as to allow the system to
   6109                         // stick the last user choice without persisting the choice
   6110                         mWifiConfigStore.setLastSelectedConfiguration(message.arg1);
   6111 
   6112                         // Remember time of last connection attempt
   6113                         lastConnectAttempt = System.currentTimeMillis();
   6114 
   6115                         mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
   6116                     }
   6117                     // Cancel auto roam requests
   6118                     autoRoamSetBSSID(message.arg1, "any");
   6119 
   6120                     ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
   6121                     if (!ok) {
   6122                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   6123                     }
   6124                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
   6125                     break;
   6126                 case CMD_ENABLE_ALL_NETWORKS:
   6127                     long time = android.os.SystemClock.elapsedRealtime();
   6128                     if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
   6129                         mWifiConfigStore.enableAllNetworks();
   6130                         mLastEnableAllNetworksTime = time;
   6131                     }
   6132                     break;
   6133                 case WifiManager.DISABLE_NETWORK:
   6134                     if (mWifiConfigStore.disableNetwork(message.arg1,
   6135                             WifiConfiguration.DISABLED_BY_WIFI_MANAGER) == true) {
   6136                         replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
   6137                     } else {
   6138                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   6139                         replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
   6140                                 WifiManager.ERROR);
   6141                     }
   6142                     break;
   6143                 case CMD_BLACKLIST_NETWORK:
   6144                     mWifiNative.addToBlacklist((String) message.obj);
   6145                     break;
   6146                 case CMD_CLEAR_BLACKLIST:
   6147                     mWifiNative.clearBlacklist();
   6148                     break;
   6149                 case CMD_SAVE_CONFIG:
   6150                     ok = mWifiConfigStore.saveConfig();
   6151 
   6152                     if (DBG) loge("wifistatemachine did save config " + ok);
   6153                     replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
   6154 
   6155                     // Inform the backup manager about a data change
   6156                     IBackupManager ibm = IBackupManager.Stub.asInterface(
   6157                             ServiceManager.getService(Context.BACKUP_SERVICE));
   6158                     if (ibm != null) {
   6159                         try {
   6160                             ibm.dataChanged("com.android.providers.settings");
   6161                         } catch (Exception e) {
   6162                             // Try again later
   6163                         }
   6164                     }
   6165                     break;
   6166                 case CMD_GET_CONFIGURED_NETWORKS:
   6167                     replyToMessage(message, message.what,
   6168                             mWifiConfigStore.getConfiguredNetworks());
   6169                     break;
   6170                 case WifiMonitor.SUP_REQUEST_IDENTITY:
   6171                     // Supplicant lacks credentials to connect to that network, hence black list
   6172                     ssid = (String) message.obj;
   6173 
   6174                     if (targetWificonfiguration != null && ssid != null
   6175                             && targetWificonfiguration.SSID != null
   6176                             && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
   6177                         mWifiConfigStore.handleSSIDStateChange(targetWificonfiguration.networkId,
   6178                                 false, "AUTH_FAILED no identity", null);
   6179                     }
   6180                     // Disconnect now, as we don't have any way to fullfill the  supplicant request.
   6181                     mWifiConfigStore.setLastSelectedConfiguration
   6182                             (WifiConfiguration.INVALID_NETWORK_ID);
   6183                     mWifiNative.disconnect();
   6184                     break;
   6185                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
   6186                     logd("Received SUP_REQUEST_SIM_AUTH");
   6187                     SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
   6188                     if (requestData != null) {
   6189                         if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
   6190                             handleGsmAuthRequest(requestData);
   6191                         } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA) {
   6192                             handle3GAuthRequest(requestData);
   6193                         }
   6194                     } else {
   6195                         loge("Invalid sim auth request");
   6196                     }
   6197                     break;
   6198                 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
   6199                     replyToMessage(message, message.what,
   6200                             mWifiConfigStore.getPrivilegedConfiguredNetworks());
   6201                     break;
   6202                     /* Do a redundant disconnect without transition */
   6203                 case CMD_DISCONNECT:
   6204                     mWifiConfigStore.setLastSelectedConfiguration
   6205                             (WifiConfiguration.INVALID_NETWORK_ID);
   6206                     mWifiNative.disconnect();
   6207                     break;
   6208                 case CMD_RECONNECT:
   6209                     lastConnectAttempt = System.currentTimeMillis();
   6210                     mWifiNative.reconnect();
   6211                     break;
   6212                 case CMD_REASSOCIATE:
   6213                     lastConnectAttempt = System.currentTimeMillis();
   6214                     mWifiNative.reassociate();
   6215                     break;
   6216                 case CMD_RELOAD_TLS_AND_RECONNECT:
   6217                     if (mWifiConfigStore.needsUnlockedKeyStore()) {
   6218                         logd("Reconnecting to give a chance to un-connected TLS networks");
   6219                         mWifiNative.disconnect();
   6220                         lastConnectAttempt = System.currentTimeMillis();
   6221                         mWifiNative.reconnect();
   6222                     }
   6223                     break;
   6224                 case CMD_AUTO_ROAM:
   6225                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   6226                     return HANDLED;
   6227                 case CMD_AUTO_CONNECT:
   6228                     /* Work Around: wpa_supplicant can get in a bad state where it returns a non
   6229                      * associated status to the STATUS command but somehow-someplace still thinks
   6230                      * it is associated and thus will ignore select/reconnect command with
   6231                      * following message:
   6232                      * "Already associated with the selected network - do nothing"
   6233                      *
   6234                      * Hence, sends a disconnect to supplicant first.
   6235                      */
   6236                     didDisconnect = false;
   6237                     if (getCurrentState() != mDisconnectedState) {
   6238                         /** Supplicant will ignore the reconnect if we are currently associated,
   6239                          * hence trigger a disconnect
   6240                          */
   6241                         didDisconnect = true;
   6242                         mWifiNative.disconnect();
   6243                     }
   6244 
   6245                     /* connect command coming from auto-join */
   6246                     config = (WifiConfiguration) message.obj;
   6247                     netId = message.arg1;
   6248                     int roam = message.arg2;
   6249                     loge("CMD_AUTO_CONNECT sup state "
   6250                             + mSupplicantStateTracker.getSupplicantStateName()
   6251                             + " my state " + getCurrentState().getName()
   6252                             + " nid=" + Integer.toString(netId)
   6253                             + " roam=" + Integer.toString(roam));
   6254                     if (config == null) {
   6255                         loge("AUTO_CONNECT and no config, bail out...");
   6256                         break;
   6257                     }
   6258 
   6259                     /* Make sure we cancel any previous roam request */
   6260                     autoRoamSetBSSID(netId, config.BSSID);
   6261 
   6262                     /* Save the network config */
   6263                     loge("CMD_AUTO_CONNECT will save config -> " + config.SSID
   6264                             + " nid=" + Integer.toString(netId));
   6265                     result = mWifiConfigStore.saveNetwork(config, -1);
   6266                     netId = result.getNetworkId();
   6267                     loge("CMD_AUTO_CONNECT did save config -> "
   6268                             + " nid=" + Integer.toString(netId));
   6269 
   6270                     // Make sure the network is enabled, since supplicant will not reenable it
   6271                     mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
   6272 
   6273                     if (mWifiConfigStore.selectNetwork(netId) &&
   6274                             mWifiNative.reconnect()) {
   6275                         lastConnectAttempt = System.currentTimeMillis();
   6276                         targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
   6277                         // We selected a better config,
   6278                         // maybe because we could not see the last user
   6279                         // selection, then forget it. We will remember the selection
   6280                         // only if it was persisted.
   6281                         mWifiConfigStore.
   6282                                 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
   6283 
   6284                         mAutoRoaming = roam;
   6285                         if (isRoaming() || linkDebouncing) {
   6286                             transitionTo(mRoamingState);
   6287                         } else if (didDisconnect) {
   6288                             transitionTo(mDisconnectingState);
   6289                         } else {
   6290                             transitionTo(mDisconnectedState);
   6291                         }
   6292                     } else {
   6293                         loge("Failed to connect config: " + config + " netId: " + netId);
   6294                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   6295                                 WifiManager.ERROR);
   6296                         break;
   6297                     }
   6298                     break;
   6299                 case WifiManager.CONNECT_NETWORK:
   6300                     /**
   6301                      *  The connect message can contain a network id passed as arg1 on message or
   6302                      * or a config passed as obj on message.
   6303                      * For a new network, a config is passed to create and connect.
   6304                      * For an existing network, a network id is passed
   6305                      */
   6306                     netId = message.arg1;
   6307                     config = (WifiConfiguration) message.obj;
   6308                     mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
   6309 
   6310                     /* Save the network config */
   6311                     if (config != null) {
   6312                         result = mWifiConfigStore.saveNetwork(config, message.sendingUid);
   6313                         netId = result.getNetworkId();
   6314                     }
   6315                     config = mWifiConfigStore.getWifiConfiguration(netId);
   6316 
   6317                     if (config == null) {
   6318                         loge("CONNECT_NETWORK id=" + Integer.toString(netId) + " "
   6319                                 + mSupplicantStateTracker.getSupplicantStateName() + " my state "
   6320                                 + getCurrentState().getName());
   6321                     } else {
   6322                         String wasSkipped = config.autoJoinBailedDueToLowRssi ? " skipped" : "";
   6323                         loge("CONNECT_NETWORK id=" + Integer.toString(netId)
   6324                                 + " config=" + config.SSID
   6325                                 + " cnid=" + config.networkId
   6326                                 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
   6327                                 + " my state " + getCurrentState().getName()
   6328                                 + " uid = " + message.sendingUid
   6329                                 + wasSkipped);
   6330                     }
   6331 
   6332                     autoRoamSetBSSID(netId, "any");
   6333 
   6334                     if (message.sendingUid == Process.WIFI_UID
   6335                         || message.sendingUid == Process.SYSTEM_UID) {
   6336                         // As a sanity measure, clear the BSSID in the supplicant network block.
   6337                         // If system or Wifi Settings want to connect, they will not
   6338                         // specify the BSSID.
   6339                         // If an app however had added a BSSID to this configuration, and the BSSID
   6340                         // was wrong, Then we would forever fail to connect until that BSSID
   6341                         // is cleaned up.
   6342                         clearConfigBSSID(config, "CONNECT_NETWORK");
   6343                     }
   6344 
   6345                     mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
   6346 
   6347                     /* Tell autojoin the user did try to connect to that network */
   6348                     mWifiAutoJoinController.updateConfigurationHistory(netId, true, true);
   6349 
   6350                     mWifiConfigStore.setLastSelectedConfiguration(netId);
   6351 
   6352                     didDisconnect = false;
   6353                     if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
   6354                             && mLastNetworkId != netId) {
   6355                         /** Supplicant will ignore the reconnect if we are currently associated,
   6356                          * hence trigger a disconnect
   6357                          */
   6358                         didDisconnect = true;
   6359                         mWifiNative.disconnect();
   6360                     }
   6361 
   6362                     // Make sure the network is enabled, since supplicant will not reenable it
   6363                     mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
   6364 
   6365                     if (mWifiConfigStore.selectNetwork(netId) &&
   6366                             mWifiNative.reconnect()) {
   6367                         lastConnectAttempt = System.currentTimeMillis();
   6368                         targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
   6369 
   6370                         /* The state tracker handles enabling networks upon completion/failure */
   6371                         mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
   6372                         replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
   6373                         if (didDisconnect) {
   6374                             /* Expect a disconnection from the old connection */
   6375                             transitionTo(mDisconnectingState);
   6376                         } else {
   6377                             /**
   6378                              *  Directly go to disconnected state where we
   6379                              * process the connection events from supplicant
   6380                              **/
   6381                             transitionTo(mDisconnectedState);
   6382                         }
   6383                     } else {
   6384                         loge("Failed to connect config: " + config + " netId: " + netId);
   6385                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   6386                                 WifiManager.ERROR);
   6387                         break;
   6388                     }
   6389                     break;
   6390                 case WifiManager.SAVE_NETWORK:
   6391                     mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
   6392                     // Fall thru
   6393                 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
   6394                     lastSavedConfigurationAttempt = null; // Used for debug
   6395                     config = (WifiConfiguration) message.obj;
   6396                     if (config == null) {
   6397                         loge("ERROR: SAVE_NETWORK with null configuration"
   6398                                 + mSupplicantStateTracker.getSupplicantStateName()
   6399                                 + " my state " + getCurrentState().getName());
   6400                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   6401                         replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
   6402                                 WifiManager.ERROR);
   6403                         break;
   6404                     }
   6405                     lastSavedConfigurationAttempt = new WifiConfiguration(config);
   6406                     int nid = config.networkId;
   6407                     loge("SAVE_NETWORK id=" + Integer.toString(nid)
   6408                                 + " config=" + config.SSID
   6409                                 + " nid=" + config.networkId
   6410                                 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
   6411                                 + " my state " + getCurrentState().getName());
   6412 
   6413                     result = mWifiConfigStore.saveNetwork(config, -1);
   6414                     if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
   6415                         if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
   6416                             if (result.hasIpChanged()) {
   6417                                 // The currently connection configuration was changed
   6418                                 // We switched from DHCP to static or from static to DHCP, or the
   6419                                 // static IP address has changed.
   6420                                 log("Reconfiguring IP on connection");
   6421                                 // TODO: clear addresses and disable IPv6
   6422                                 // to simplify obtainingIpState.
   6423                                 transitionTo(mObtainingIpState);
   6424                             }
   6425                             if (result.hasProxyChanged()) {
   6426                                 log("Reconfiguring proxy on connection");
   6427                                 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES);
   6428                             }
   6429                         }
   6430                         replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
   6431                         if (VDBG) {
   6432                            loge("Success save network nid="
   6433                                         + Integer.toString(result.getNetworkId()));
   6434                         }
   6435 
   6436                         synchronized(mScanResultCache) {
   6437                             /**
   6438                              * If the command comes from WifiManager, then
   6439                              * tell autojoin the user did try to modify and save that network,
   6440                              * and interpret the SAVE_NETWORK as a request to connect
   6441                              */
   6442                             boolean user = message.what == WifiManager.SAVE_NETWORK;
   6443                             mWifiAutoJoinController.updateConfigurationHistory(result.getNetworkId()
   6444                                     , user, true);
   6445                             mWifiAutoJoinController.attemptAutoJoin();
   6446                         }
   6447                     } else {
   6448                         loge("Failed to save network");
   6449                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   6450                         replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
   6451                                 WifiManager.ERROR);
   6452                     }
   6453                     break;
   6454                 case WifiManager.FORGET_NETWORK:
   6455                     // Debug only, remember last configuration that was forgotten
   6456                     WifiConfiguration toRemove
   6457                             = mWifiConfigStore.getWifiConfiguration(message.arg1);
   6458                     if (toRemove == null) {
   6459                         lastForgetConfigurationAttempt = null;
   6460                     } else {
   6461                         lastForgetConfigurationAttempt = new WifiConfiguration(toRemove);
   6462                     }
   6463                     if (mWifiConfigStore.forgetNetwork(message.arg1)) {
   6464                         replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
   6465                     } else {
   6466                         loge("Failed to forget network");
   6467                         replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
   6468                                 WifiManager.ERROR);
   6469                     }
   6470                     break;
   6471                 case WifiManager.START_WPS:
   6472                     WpsInfo wpsInfo = (WpsInfo) message.obj;
   6473                     WpsResult wpsResult;
   6474                     switch (wpsInfo.setup) {
   6475                         case WpsInfo.PBC:
   6476                             wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo);
   6477                             break;
   6478                         case WpsInfo.KEYPAD:
   6479                             wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo);
   6480                             break;
   6481                         case WpsInfo.DISPLAY:
   6482                             wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo);
   6483                             break;
   6484                         default:
   6485                             wpsResult = new WpsResult(Status.FAILURE);
   6486                             loge("Invalid setup for WPS");
   6487                             break;
   6488                     }
   6489                     mWifiConfigStore.setLastSelectedConfiguration
   6490                             (WifiConfiguration.INVALID_NETWORK_ID);
   6491                     if (wpsResult.status == Status.SUCCESS) {
   6492                         replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
   6493                         transitionTo(mWpsRunningState);
   6494                     } else {
   6495                         loge("Failed to start WPS with config " + wpsInfo.toString());
   6496                         replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
   6497                     }
   6498                     break;
   6499                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   6500                     if (DBG) log("Network connection established");
   6501                     mLastNetworkId = message.arg1;
   6502                     mLastBssid = (String) message.obj;
   6503 
   6504                     mWifiInfo.setBSSID(mLastBssid);
   6505                     mWifiInfo.setNetworkId(mLastNetworkId);
   6506                     // Send event to CM & network change broadcast
   6507                     setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
   6508                     sendNetworkStateChangeBroadcast(mLastBssid);
   6509                     transitionTo(mObtainingIpState);
   6510                     break;
   6511                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   6512                     // Calling handleNetworkDisconnect here is redundant because we might already
   6513                     // have called it when leaving L2ConnectedState to go to disconnecting state
   6514                     // or thru other path
   6515                     // We should normally check the mWifiInfo or mLastNetworkId so as to check
   6516                     // if they are valid, and only in this case call handleNEtworkDisconnect,
   6517                     // TODO: this should be fixed for a L MR release
   6518                     // The side effect of calling handleNetworkDisconnect twice is that a bunch of
   6519                     // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
   6520                     // at the chip etc...
   6521                     if (DBG) log("ConnectModeState: Network connection lost ");
   6522                     handleNetworkDisconnect();
   6523                     transitionTo(mDisconnectedState);
   6524                     break;
   6525                 default:
   6526                     return NOT_HANDLED;
   6527             }
   6528             return HANDLED;
   6529         }
   6530     }
   6531 
   6532     private class WifiNetworkAgent extends NetworkAgent {
   6533         public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
   6534                 NetworkCapabilities nc, LinkProperties lp, int score) {
   6535             super(l, c, TAG, ni, nc, lp, score);
   6536         }
   6537         protected void unwanted() {
   6538             // Ignore if we're not the current networkAgent.
   6539             if (this != mNetworkAgent) return;
   6540             if (DBG) log("WifiNetworkAgent -> Wifi unwanted score "
   6541                     + Integer.toString(mWifiInfo.score));
   6542             unwantedNetwork(network_status_unwanted_disconnect);
   6543         }
   6544 
   6545         protected void networkStatus(int status) {
   6546             if (status == NetworkAgent.INVALID_NETWORK) {
   6547                 if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid score "
   6548                         + Integer.toString(mWifiInfo.score));
   6549                 unwantedNetwork(network_status_unwanted_disable_autojoin);
   6550             }
   6551         }
   6552     }
   6553 
   6554     void unwantedNetwork(int reason) {
   6555         sendMessage(CMD_UNWANTED_NETWORK, reason);
   6556     }
   6557 
   6558 
   6559     boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) {
   6560         if (config == null)
   6561             return false;
   6562 
   6563         // We are still seeing a fairly high power consumption triggered by autojoin scans
   6564         // Hence do partial scans only for PSK configuration that are roamable since the
   6565         // primary purpose of the partial scans is roaming.
   6566         // Full badn scans with exponential backoff for the purpose or extended roaming and
   6567         // network switching are performed unconditionally.
   6568         if (config.scanResultCache == null
   6569                 || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
   6570                 || config.scanResultCache.size() > 6) {
   6571             //return true but to not trigger the scan
   6572             return true;
   6573         }
   6574         HashSet<Integer> channels
   6575                 = mWifiConfigStore.makeChannelList(config,
   6576                 ONE_HOUR_MILLI, restrictChannelList);
   6577         if (channels != null && channels.size() != 0) {
   6578             StringBuilder freqs = new StringBuilder();
   6579             boolean first = true;
   6580             for (Integer channel : channels) {
   6581                 if (!first)
   6582                     freqs.append(",");
   6583                 freqs.append(channel.toString());
   6584                 first = false;
   6585             }
   6586             //if (DBG) {
   6587             loge("WifiStateMachine starting scan for " + config.configKey() + " with " + freqs);
   6588             //}
   6589             // Call wifi native to start the scan
   6590             if (startScanNative(
   6591                     WifiNative.SCAN_WITHOUT_CONNECTION_SETUP,
   6592                     freqs.toString())) {
   6593                 // Only count battery consumption if scan request is accepted
   6594                 noteScanStart(SCAN_ALARM_SOURCE, null);
   6595                 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
   6596             } else {
   6597                 // used for debug only, mark scan as failed
   6598                 messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
   6599             }
   6600             return true;
   6601         } else {
   6602             if (DBG) loge("WifiStateMachine no channels for " + config.configKey());
   6603             return false;
   6604         }
   6605     }
   6606 
   6607     void clearCurrentConfigBSSID(String dbg) {
   6608         // Clear the bssid in the current config's network block
   6609         WifiConfiguration config = getCurrentWifiConfiguration();
   6610         if (config == null)
   6611             return;
   6612         clearConfigBSSID(config, dbg);
   6613     }
   6614     void clearConfigBSSID(WifiConfiguration config, String dbg) {
   6615         if (config == null)
   6616             return;
   6617         if (DBG) {
   6618             loge(dbg + " " + mTargetRoamBSSID + " config " + config.configKey()
   6619                     + " config.bssid " + config.BSSID);
   6620         }
   6621         config.autoJoinBSSID = "any";
   6622         config.BSSID = "any";
   6623         if (DBG) {
   6624            loge(dbg + " " + config.SSID
   6625                     + " nid=" + Integer.toString(config.networkId));
   6626         }
   6627         mWifiConfigStore.saveWifiConfigBSSID(config);
   6628     }
   6629 
   6630     class L2ConnectedState extends State {
   6631         @Override
   6632         public void enter() {
   6633             mRssiPollToken++;
   6634             if (mEnableRssiPolling) {
   6635                 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
   6636             }
   6637             if (mNetworkAgent != null) {
   6638                 loge("Have NetworkAgent when entering L2Connected");
   6639                 setNetworkDetailedState(DetailedState.DISCONNECTED);
   6640             }
   6641             setNetworkDetailedState(DetailedState.CONNECTING);
   6642 
   6643             if (TextUtils.isEmpty(mTcpBufferSizes) == false) {
   6644                 mLinkProperties.setTcpBufferSizes(mTcpBufferSizes);
   6645             }
   6646             mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
   6647                     "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
   6648                     mLinkProperties, 60);
   6649 
   6650             // We must clear the config BSSID, as the wifi chipset may decide to roam
   6651             // from this point on and having the BSSID specified in the network block would
   6652             // cause the roam to faile and the device to disconnect
   6653             clearCurrentConfigBSSID("L2ConnectedState");
   6654         }
   6655 
   6656         @Override
   6657         public void exit() {
   6658             // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
   6659             // Bug: 15347363
   6660             // For paranoia's sake, call handleNetworkDisconnect
   6661             // only if BSSID is null or last networkId
   6662             // is not invalid.
   6663             if (DBG) {
   6664                 StringBuilder sb = new StringBuilder();
   6665                 sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
   6666                 if (mLastBssid !=null) {
   6667                     sb.append(" ").append(mLastBssid);
   6668                 }
   6669             }
   6670             if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
   6671                 handleNetworkDisconnect();
   6672             }
   6673         }
   6674 
   6675         @Override
   6676         public boolean processMessage(Message message) {
   6677             logStateAndMessage(message, getClass().getSimpleName());
   6678 
   6679             switch (message.what) {
   6680               case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   6681                   handlePreDhcpSetup();
   6682                   break;
   6683               case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   6684                   handlePostDhcpSetup();
   6685                   if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
   6686                       if (DBG) log("WifiStateMachine DHCP successful");
   6687                       handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS);
   6688                       // We advance to mVerifyingLinkState because handleIPv4Success will call
   6689                       // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL.
   6690                   } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
   6691                       if (DBG) {
   6692                           int count = -1;
   6693                           WifiConfiguration config = getCurrentWifiConfiguration();
   6694                           if (config != null) {
   6695                               count = config.numConnectionFailures;
   6696                           }
   6697                           log("WifiStateMachine DHCP failure count=" + count);
   6698                       }
   6699                       handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE);
   6700                       // As above, we transition to mDisconnectingState via updateLinkProperties.
   6701                   }
   6702                   break;
   6703                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
   6704                     handleSuccessfulIpConfiguration();
   6705                     sendConnectedState();
   6706                     transitionTo(mConnectedState);
   6707                     break;
   6708                 case CMD_IP_CONFIGURATION_LOST:
   6709                     handleIpConfigurationLost();
   6710                     transitionTo(mDisconnectingState);
   6711                     break;
   6712                 case CMD_DISCONNECT:
   6713                     mWifiNative.disconnect();
   6714                     transitionTo(mDisconnectingState);
   6715                     break;
   6716                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
   6717                     if (message.arg1 == 1) {
   6718                         mWifiNative.disconnect();
   6719                         mTemporarilyDisconnectWifi = true;
   6720                         transitionTo(mDisconnectingState);
   6721                     }
   6722                     break;
   6723                 case CMD_SET_OPERATIONAL_MODE:
   6724                     if (message.arg1 != CONNECT_MODE) {
   6725                         sendMessage(CMD_DISCONNECT);
   6726                         deferMessage(message);
   6727                         if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
   6728                             noteWifiDisabledWhileAssociated();
   6729                         }
   6730                     }
   6731                     break;
   6732                 case CMD_SET_COUNTRY_CODE:
   6733                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   6734                     deferMessage(message);
   6735                     break;
   6736                 case CMD_START_SCAN:
   6737                     //if (DBG) {
   6738                         loge("WifiStateMachine CMD_START_SCAN source " + message.arg1
   6739                               + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate)
   6740                               + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate)
   6741                               + " targetRoamBSSID=" + mTargetRoamBSSID
   6742                               + " RSSI=" + mWifiInfo.getRssi());
   6743                     //}
   6744                     if (message.arg1 == SCAN_ALARM_SOURCE) {
   6745                         boolean tryFullBandScan = false;
   6746                         boolean restrictChannelList = false;
   6747                         long now_ms = System.currentTimeMillis();
   6748                         if (DBG) {
   6749                             loge("WifiStateMachine CMD_START_SCAN with age="
   6750                                     + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
   6751                                     + " interval=" + fullBandConnectedTimeIntervalMilli
   6752                                     + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
   6753                         }
   6754                         if (mWifiInfo != null) {
   6755                             if (mWifiConfigStore.enableFullBandScanWhenAssociated &&
   6756                                     (now_ms - lastFullBandConnectedTimeMilli)
   6757                                     > fullBandConnectedTimeIntervalMilli) {
   6758                                 if (DBG) {
   6759                                     loge("WifiStateMachine CMD_START_SCAN try full band scan age="
   6760                                          + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
   6761                                          + " interval=" + fullBandConnectedTimeIntervalMilli
   6762                                          + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
   6763                                 }
   6764                                 tryFullBandScan = true;
   6765                             }
   6766 
   6767                             if (mWifiInfo.txSuccessRate >
   6768                                     mWifiConfigStore.maxTxPacketForFullScans
   6769                                     || mWifiInfo.rxSuccessRate >
   6770                                     mWifiConfigStore.maxRxPacketForFullScans) {
   6771                                 // Too much traffic at the interface, hence no full band scan
   6772                                 if (DBG) {
   6773                                     loge("WifiStateMachine CMD_START_SCAN " +
   6774                                             "prevent full band scan due to pkt rate");
   6775                                 }
   6776                                 tryFullBandScan = false;
   6777                             }
   6778 
   6779                             if (mWifiInfo.txSuccessRate >
   6780                                     mWifiConfigStore.maxTxPacketForPartialScans
   6781                                     || mWifiInfo.rxSuccessRate >
   6782                                     mWifiConfigStore.maxRxPacketForPartialScans) {
   6783                                 // Don't scan if lots of packets are being sent
   6784                                 restrictChannelList = true;
   6785                                 if (mWifiConfigStore.alwaysEnableScansWhileAssociated == 0) {
   6786                                     if (DBG) {
   6787                                      loge("WifiStateMachine CMD_START_SCAN source " + message.arg1
   6788                                         + " ...and ignore scans"
   6789                                         + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate)
   6790                                         + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate));
   6791                                     }
   6792                                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
   6793                                     return HANDLED;
   6794                                 }
   6795                             }
   6796                         }
   6797 
   6798                         WifiConfiguration currentConfiguration = getCurrentWifiConfiguration();
   6799                         if (DBG) {
   6800                             loge("WifiStateMachine CMD_START_SCAN full=" +
   6801                                     tryFullBandScan);
   6802                         }
   6803                         if (currentConfiguration != null) {
   6804                             if (fullBandConnectedTimeIntervalMilli
   6805                                     < mWifiConfigStore.associatedPartialScanPeriodMilli) {
   6806                                 // Sanity
   6807                                 fullBandConnectedTimeIntervalMilli
   6808                                         = mWifiConfigStore.associatedPartialScanPeriodMilli;
   6809                             }
   6810                             if (tryFullBandScan) {
   6811                                 lastFullBandConnectedTimeMilli = now_ms;
   6812                                 if (fullBandConnectedTimeIntervalMilli
   6813                                         < mWifiConfigStore.associatedFullScanMaxIntervalMilli) {
   6814                                     // Increase the interval
   6815                                     fullBandConnectedTimeIntervalMilli
   6816                                             = fullBandConnectedTimeIntervalMilli
   6817                                             * mWifiConfigStore.associatedFullScanBackoff / 8;
   6818 
   6819                                     if (DBG) {
   6820                                         loge("WifiStateMachine CMD_START_SCAN bump interval ="
   6821                                         + fullBandConnectedTimeIntervalMilli);
   6822                                     }
   6823                                 }
   6824                                 handleScanRequest(
   6825                                         WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
   6826                             } else {
   6827                                 if (!startScanForConfiguration(
   6828                                         currentConfiguration, restrictChannelList)) {
   6829                                     if (DBG) {
   6830                                         loge("WifiStateMachine starting scan, " +
   6831                                                 " did not find channels -> full");
   6832                                     }
   6833                                     lastFullBandConnectedTimeMilli = now_ms;
   6834                                     if (fullBandConnectedTimeIntervalMilli
   6835                                             < mWifiConfigStore.associatedFullScanMaxIntervalMilli) {
   6836                                         // Increase the interval
   6837                                         fullBandConnectedTimeIntervalMilli
   6838                                                 = fullBandConnectedTimeIntervalMilli
   6839                                                 * mWifiConfigStore.associatedFullScanBackoff / 8;
   6840 
   6841                                         if (DBG) {
   6842                                             loge("WifiStateMachine CMD_START_SCAN bump interval ="
   6843                                                     + fullBandConnectedTimeIntervalMilli);
   6844                                         }
   6845                                     }
   6846                                     handleScanRequest(
   6847                                                 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
   6848                                 }
   6849                             }
   6850                         } else {
   6851                             loge("CMD_START_SCAN : connected mode and no configuration");
   6852                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
   6853                         }
   6854                     } else {
   6855                         // Not scan alarm source
   6856                         handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
   6857                     }
   6858                     break;
   6859                     /* Ignore connection to same network */
   6860                 case WifiManager.CONNECT_NETWORK:
   6861                     int netId = message.arg1;
   6862                     if (mWifiInfo.getNetworkId() == netId) {
   6863                         break;
   6864                     }
   6865                     return NOT_HANDLED;
   6866                     /* Ignore */
   6867                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   6868                     break;
   6869                 case CMD_RSSI_POLL:
   6870                     if (message.arg1 == mRssiPollToken) {
   6871                         if (mWifiConfigStore.enableChipWakeUpWhenAssociated) {
   6872                             if (VVDBG) log(" get link layer stats " + mWifiLinkLayerStatsSupported);
   6873                             WifiLinkLayerStats stats = getWifiLinkLayerStats(VDBG);
   6874                             if (stats != null) {
   6875                                 // Sanity check the results provided by driver
   6876                                 if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
   6877                                         && (stats.rssi_mgmt == 0
   6878                                         || stats.beacon_rx == 0)) {
   6879                                     stats = null;
   6880                                 }
   6881                             }
   6882                             // Get Info and continue polling
   6883                             fetchRssiLinkSpeedAndFrequencyNative();
   6884                             calculateWifiScore(stats);
   6885                         }
   6886                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
   6887                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
   6888 
   6889                         if (DBG) sendRssiChangeBroadcast(mWifiInfo.getRssi());
   6890                     } else {
   6891                         // Polling has completed
   6892                     }
   6893                     break;
   6894                 case CMD_ENABLE_RSSI_POLL:
   6895                     if (mWifiConfigStore.enableRssiPollWhenAssociated) {
   6896                         mEnableRssiPolling = (message.arg1 == 1);
   6897                     } else {
   6898                         mEnableRssiPolling = false;
   6899                     }
   6900                     mRssiPollToken++;
   6901                     if (mEnableRssiPolling) {
   6902                         // First poll
   6903                         fetchRssiLinkSpeedAndFrequencyNative();
   6904                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
   6905                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
   6906                     } else {
   6907                         cleanWifiScore();
   6908                     }
   6909                     break;
   6910                 case WifiManager.RSSI_PKTCNT_FETCH:
   6911                     RssiPacketCountInfo info = new RssiPacketCountInfo();
   6912                     fetchRssiLinkSpeedAndFrequencyNative();
   6913                     info.rssi = mWifiInfo.getRssi();
   6914                     fetchPktcntNative(info);
   6915                     replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
   6916                     break;
   6917                 case CMD_DELAYED_NETWORK_DISCONNECT:
   6918                     if (!linkDebouncing && mWifiConfigStore.enableLinkDebouncing) {
   6919 
   6920                         // Ignore if we are not debouncing
   6921                         loge("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore "
   6922                                 + message.arg1);
   6923                         return HANDLED;
   6924                     } else {
   6925                         loge("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect "
   6926                                 + message.arg1);
   6927 
   6928                         linkDebouncing = false;
   6929                         // If we are still debouncing while this message comes,
   6930                         // it means we were not able to reconnect within the alloted time
   6931                         // = LINK_FLAPPING_DEBOUNCE_MSEC
   6932                         // and thus, trigger a real disconnect
   6933                         handleNetworkDisconnect();
   6934                         transitionTo(mDisconnectedState);
   6935                     }
   6936                     break;
   6937                 case CMD_ASSOCIATED_BSSID:
   6938                     if ((String) message.obj == null) {
   6939                         loge("Associated command w/o BSSID");
   6940                         break;
   6941                     }
   6942                     mLastBssid = (String) message.obj;
   6943                     mWifiInfo.setBSSID((String) message.obj);
   6944                     break;
   6945                 default:
   6946                     return NOT_HANDLED;
   6947             }
   6948 
   6949             return HANDLED;
   6950         }
   6951     }
   6952 
   6953     class ObtainingIpState extends State {
   6954         @Override
   6955         public void enter() {
   6956             if (DBG) {
   6957                 String key = "";
   6958                 if (getCurrentWifiConfiguration() != null) {
   6959                     key = getCurrentWifiConfiguration().configKey();
   6960                 }
   6961                 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
   6962                         + " " + key + " "
   6963                         + " roam=" + mAutoRoaming
   6964                         + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId)
   6965                         + " watchdog= " + obtainingIpWatchdogCount);
   6966             }
   6967 
   6968             // Reset link Debouncing, indicating we have successfully re-connected to the AP
   6969             // We might still be roaming
   6970             linkDebouncing = false;
   6971 
   6972             // We must clear the config BSSID, as the wifi chipset may decide to roam
   6973             // from this point on and having the BSSID specified in the network block would
   6974             // cause the roam to faile and the device to disconnect
   6975             clearCurrentConfigBSSID("ObtainingIpAddress");
   6976 
   6977             try {
   6978                 mNwService.enableIpv6(mInterfaceName);
   6979             } catch (RemoteException re) {
   6980                 loge("Failed to enable IPv6: " + re);
   6981             } catch (IllegalStateException e) {
   6982                 loge("Failed to enable IPv6: " + e);
   6983             }
   6984 
   6985             if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
   6986                 if (isRoaming()) {
   6987                     renewDhcp();
   6988                 } else {
   6989                     // Remove any IP address on the interface in case we're switching from static
   6990                     // IP configuration to DHCP. This is safe because if we get here when not
   6991                     // roaming, we don't have a usable address.
   6992                     clearIPv4Address(mInterfaceName);
   6993                     startDhcp();
   6994                 }
   6995                 obtainingIpWatchdogCount++;
   6996                 loge("Start Dhcp Watchdog " + obtainingIpWatchdogCount);
   6997                 sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER,
   6998                         obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC);
   6999             } else {
   7000                 // stop any running dhcp before assigning static IP
   7001                 stopDhcp();
   7002                 StaticIpConfiguration config = mWifiConfigStore.getStaticIpConfiguration(
   7003                         mLastNetworkId);
   7004                 if (config.ipAddress == null) {
   7005                     loge("Static IP lacks address");
   7006                     sendMessage(CMD_STATIC_IP_FAILURE);
   7007                 } else {
   7008                     InterfaceConfiguration ifcg = new InterfaceConfiguration();
   7009                     ifcg.setLinkAddress(config.ipAddress);
   7010                     ifcg.setInterfaceUp();
   7011                     try {
   7012                         mNwService.setInterfaceConfig(mInterfaceName, ifcg);
   7013                         if (DBG) log("Static IP configuration succeeded");
   7014                         DhcpResults dhcpResults = new DhcpResults(config);
   7015                         sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults);
   7016                     } catch (RemoteException re) {
   7017                         loge("Static IP configuration failed: " + re);
   7018                         sendMessage(CMD_STATIC_IP_FAILURE);
   7019                     } catch (IllegalStateException e) {
   7020                         loge("Static IP configuration failed: " + e);
   7021                         sendMessage(CMD_STATIC_IP_FAILURE);
   7022                     }
   7023                 }
   7024             }
   7025         }
   7026       @Override
   7027       public boolean processMessage(Message message) {
   7028           logStateAndMessage(message, getClass().getSimpleName());
   7029 
   7030           switch(message.what) {
   7031               case CMD_STATIC_IP_SUCCESS:
   7032                   handleIPv4Success((DhcpResults) message.obj, CMD_STATIC_IP_SUCCESS);
   7033                   break;
   7034               case CMD_STATIC_IP_FAILURE:
   7035                   handleIPv4Failure(CMD_STATIC_IP_FAILURE);
   7036                   break;
   7037               case CMD_AUTO_CONNECT:
   7038               case CMD_AUTO_ROAM:
   7039                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   7040                   break;
   7041               case WifiManager.SAVE_NETWORK:
   7042               case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
   7043                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   7044                   deferMessage(message);
   7045                   break;
   7046                   /* Defer any power mode changes since we must keep active power mode at DHCP */
   7047               case CMD_SET_HIGH_PERF_MODE:
   7048                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   7049                   deferMessage(message);
   7050                   break;
   7051                   /* Defer scan request since we should not switch to other channels at DHCP */
   7052               case CMD_START_SCAN:
   7053                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   7054                   deferMessage(message);
   7055                   break;
   7056               case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
   7057                   if (message.arg1 == obtainingIpWatchdogCount) {
   7058                       loge("ObtainingIpAddress: Watchdog Triggered, count="
   7059                               + obtainingIpWatchdogCount);
   7060                       handleIpConfigurationLost();
   7061                       transitionTo(mDisconnectingState);
   7062                       break;
   7063                   }
   7064                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   7065                   break;
   7066               default:
   7067                   return NOT_HANDLED;
   7068           }
   7069           return HANDLED;
   7070       }
   7071     }
   7072 
   7073     class VerifyingLinkState extends State {
   7074         @Override
   7075         public void enter() {
   7076             log(getName() + " enter");
   7077             setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);
   7078             mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);
   7079             sendNetworkStateChangeBroadcast(mLastBssid);
   7080             // End roaming
   7081             mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
   7082         }
   7083         @Override
   7084         public boolean processMessage(Message message) {
   7085             logStateAndMessage(message, getClass().getSimpleName());
   7086 
   7087             switch (message.what) {
   7088                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
   7089                     // Stay here
   7090                     log(getName() + " POOR_LINK_DETECTED: no transition");
   7091                     break;
   7092                 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
   7093                     log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check");
   7094 
   7095                     log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED");
   7096                     sendConnectedState();
   7097                     transitionTo(mConnectedState);
   7098                     break;
   7099                 default:
   7100                     if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED");
   7101                     return NOT_HANDLED;
   7102             }
   7103             return HANDLED;
   7104         }
   7105     }
   7106 
   7107     private void sendConnectedState() {
   7108         // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve
   7109         // existing behaviour. The captive portal check really happens after we
   7110         // transition into DetailedState.CONNECTED.
   7111         setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK);
   7112         mWifiConfigStore.updateStatus(mLastNetworkId,
   7113         DetailedState.CAPTIVE_PORTAL_CHECK);
   7114         sendNetworkStateChangeBroadcast(mLastBssid);
   7115 
   7116         if (mWifiConfigStore.getLastSelectedConfiguration() != null) {
   7117             if (mNetworkAgent != null) mNetworkAgent.explicitlySelected();
   7118         }
   7119 
   7120         setNetworkDetailedState(DetailedState.CONNECTED);
   7121         mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
   7122         sendNetworkStateChangeBroadcast(mLastBssid);
   7123     }
   7124 
   7125     class RoamingState extends State {
   7126         boolean mAssociated;
   7127         @Override
   7128         public void enter() {
   7129             if (DBG) {
   7130                 log("RoamingState Enter"
   7131                         + " mScreenOn=" + mScreenOn );
   7132             }
   7133             setScanAlarm(false, 0);
   7134 
   7135             // Make sure we disconnect if roaming fails
   7136             roamWatchdogCount++;
   7137             loge("Start Roam Watchdog " + roamWatchdogCount);
   7138             sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
   7139                     roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
   7140             mAssociated = false;
   7141         }
   7142         @Override
   7143         public boolean processMessage(Message message) {
   7144             logStateAndMessage(message, getClass().getSimpleName());
   7145 
   7146             switch (message.what) {
   7147                case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
   7148                     if (DBG) log("Roaming and Watchdog reports poor link -> ignore");
   7149                     return HANDLED;
   7150                case CMD_UNWANTED_NETWORK:
   7151                     if (DBG) log("Roaming and CS doesnt want the network -> ignore");
   7152                     return HANDLED;
   7153                case CMD_SET_OPERATIONAL_MODE:
   7154                     if (message.arg1 != CONNECT_MODE) {
   7155                         deferMessage(message);
   7156                     }
   7157                     break;
   7158                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   7159                     /**
   7160                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
   7161                      * before NETWORK_DISCONNECTION_EVENT
   7162                      * And there is an associated BSSID corresponding to our target BSSID, then
   7163                      * we have missed the network disconnection, transition to mDisconnectedState
   7164                      * and handle the rest of the events there.
   7165                      */
   7166                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   7167                     if (stateChangeResult.state == SupplicantState.DISCONNECTED
   7168                             || stateChangeResult.state == SupplicantState.INACTIVE
   7169                             || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
   7170                         if (DBG) {
   7171                             log("STATE_CHANGE_EVENT in roaming state "
   7172                                     + stateChangeResult.toString() );
   7173                         }
   7174                         if (stateChangeResult.BSSID != null
   7175                                 && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
   7176                             handleNetworkDisconnect();
   7177                             transitionTo(mDisconnectedState);
   7178                         }
   7179                     }
   7180                     if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
   7181                         // We completed the layer2 roaming part
   7182                         mAssociated = true;
   7183                         if (stateChangeResult.BSSID != null) {
   7184                             mTargetRoamBSSID = (String) stateChangeResult.BSSID;
   7185                         }
   7186                     }
   7187                     break;
   7188                 case CMD_ROAM_WATCHDOG_TIMER:
   7189                     if (roamWatchdogCount == message.arg1) {
   7190                         if (DBG) log("roaming watchdog! -> disconnect");
   7191                         mRoamFailCount++;
   7192                         handleNetworkDisconnect();
   7193                         mWifiNative.disconnect();
   7194                         transitionTo(mDisconnectedState);
   7195                     }
   7196                     break;
   7197                case WifiMonitor.NETWORK_CONNECTION_EVENT:
   7198                    if (mAssociated) {
   7199                        if (DBG) log("roaming and Network connection established");
   7200                        mLastNetworkId = message.arg1;
   7201                        mLastBssid = (String) message.obj;
   7202                        mWifiInfo.setBSSID(mLastBssid);
   7203                        mWifiInfo.setNetworkId(mLastNetworkId);
   7204                        mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, mLastBssid, true);
   7205                        transitionTo(mObtainingIpState);
   7206                    } else {
   7207                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   7208                    }
   7209                    break;
   7210                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   7211                    // Throw away but only if it corresponds to the network we're roaming to
   7212                    String bssid = (String)message.obj;
   7213                    if (true) {
   7214                        String target = "";
   7215                        if (mTargetRoamBSSID != null) target = mTargetRoamBSSID;
   7216                        log("NETWORK_DISCONNECTION_EVENT in roaming state"
   7217                                + " BSSID=" + bssid
   7218                                + " target=" + target);
   7219                    }
   7220                    if (bssid != null && bssid.equals(mTargetRoamBSSID)) {
   7221                        handleNetworkDisconnect();
   7222                        transitionTo(mDisconnectedState);
   7223                    }
   7224                    break;
   7225                 case WifiMonitor.SSID_TEMP_DISABLED:
   7226                     // Auth error while roaming
   7227                     loge("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId)
   7228                             + " id=" + Integer.toString(message.arg1)
   7229                             + " isRoaming=" + isRoaming()
   7230                             + " roam=" + Integer.toString(mAutoRoaming));
   7231                     if (message.arg1 == mLastNetworkId) {
   7232                         handleNetworkDisconnect();
   7233                         transitionTo(mDisconnectingState);
   7234                     }
   7235                     return NOT_HANDLED;
   7236                 case CMD_START_SCAN:
   7237                     deferMessage(message);
   7238                     break;
   7239                 default:
   7240                     return NOT_HANDLED;
   7241             }
   7242             return HANDLED;
   7243         }
   7244 
   7245         @Override
   7246         public void exit() {
   7247             loge("WifiStateMachine: Leaving Roaming state");
   7248         }
   7249     }
   7250 
   7251     class ConnectedState extends State {
   7252         @Override
   7253         public void enter() {
   7254             String address;
   7255             updateDefaultRouteMacAddress(1000);
   7256             if (DBG) {
   7257                 log("ConnectedState Enter "
   7258                         + " mScreenOn=" + mScreenOn
   7259                         + " scanperiod="
   7260                         + Integer.toString(mWifiConfigStore.associatedPartialScanPeriodMilli) );
   7261             }
   7262             if (mScreenOn
   7263                     && mWifiConfigStore.enableAutoJoinScanWhenAssociated) {
   7264                 mCurrentScanAlarmMs = mWifiConfigStore.associatedPartialScanPeriodMilli;
   7265                 // Scan after 200ms
   7266                 setScanAlarm(true, 200);
   7267             } else {
   7268                 mCurrentScanAlarmMs = 0;
   7269             }
   7270             registerConnected();
   7271             lastConnectAttempt = 0;
   7272             targetWificonfiguration = null;
   7273             // Paranoia
   7274             linkDebouncing = false;
   7275 
   7276             // Not roaming anymore
   7277             mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
   7278 
   7279             if (testNetworkDisconnect) {
   7280                 testNetworkDisconnectCounter++;
   7281                 loge("ConnectedState Enter start disconnect test " +
   7282                         testNetworkDisconnectCounter);
   7283                 sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT,
   7284                         testNetworkDisconnectCounter, 0), 15000);
   7285             }
   7286 
   7287             // Reenable all networks, allow for hidden networks to be scanned
   7288             mWifiConfigStore.enableAllNetworks();
   7289 
   7290             mLastDriverRoamAttempt = 0;
   7291         }
   7292         @Override
   7293         public boolean processMessage(Message message) {
   7294             WifiConfiguration config = null;
   7295             logStateAndMessage(message, getClass().getSimpleName());
   7296 
   7297             switch (message.what) {
   7298                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
   7299                     if (DBG) log("Watchdog reports poor link");
   7300                     transitionTo(mVerifyingLinkState);
   7301                     break;
   7302                 case CMD_UNWANTED_NETWORK:
   7303                     if (message.arg1 == network_status_unwanted_disconnect) {
   7304                         mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo);
   7305                         mWifiNative.disconnect();
   7306                         transitionTo(mDisconnectingState);
   7307                     } else if (message.arg1 == network_status_unwanted_disconnect) {
   7308                         config = getCurrentWifiConfiguration();
   7309                         if (config != null) {
   7310                             // Disable autojoin
   7311                             config.noInternetAccess = true;
   7312                         }
   7313                     }
   7314                     return HANDLED;
   7315                 case CMD_TEST_NETWORK_DISCONNECT:
   7316                     // Force a disconnect
   7317                     if (message.arg1 == testNetworkDisconnectCounter) {
   7318                         mWifiNative.disconnect();
   7319                     }
   7320                     break;
   7321                 case CMD_ASSOCIATED_BSSID:
   7322                     // ASSOCIATING to a new BSSID while already connected, indicates
   7323                     // that driver is roaming
   7324                     mLastDriverRoamAttempt = System.currentTimeMillis();
   7325                     String toBSSID = (String)message.obj;
   7326                     if (toBSSID != null && !toBSSID.equals(mWifiInfo.getBSSID())) {
   7327                         mWifiConfigStore.driverRoamedFrom(mWifiInfo);
   7328                     }
   7329                     return NOT_HANDLED;
   7330                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   7331                     long lastRoam = 0;
   7332                     if (mLastDriverRoamAttempt != 0) {
   7333                         // Calculate time since last driver roam attempt
   7334                         lastRoam = System.currentTimeMillis() - mLastDriverRoamAttempt;
   7335                         mLastDriverRoamAttempt = 0;
   7336                     }
   7337                     config = getCurrentWifiConfiguration();
   7338                     if (mScreenOn
   7339                             && !linkDebouncing
   7340                             && config != null
   7341                             && config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED
   7342                             && !mWifiConfigStore.isLastSelectedConfiguration(config)
   7343                             && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */
   7344                                 || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
   7345                             && ((ScanResult.is24GHz(mWifiInfo.getFrequency())
   7346                                     && mWifiInfo.getRssi() >
   7347                                     WifiConfiguration.BAD_RSSI_24)
   7348                                     || (ScanResult.is5GHz(mWifiInfo.getFrequency())
   7349                                     && mWifiInfo.getRssi() >
   7350                                     WifiConfiguration.BAD_RSSI_5))) {
   7351                         // Start de-bouncing the L2 disconnection:
   7352                         // this L2 disconnection might be spurious.
   7353                         // Hence we allow 7 seconds for the state machine to try
   7354                         // to reconnect, go thru the
   7355                         // roaming cycle and enter Obtaining IP address
   7356                         // before signalling the disconnect to ConnectivityService and L3
   7357                         startScanForConfiguration(getCurrentWifiConfiguration(), false);
   7358                         linkDebouncing = true;
   7359 
   7360                         sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT,
   7361                                 0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC);
   7362                         if (DBG) {
   7363                             log("NETWORK_DISCONNECTION_EVENT in connected state"
   7364                                     + " BSSID=" + mWifiInfo.getBSSID()
   7365                                     + " RSSI=" + mWifiInfo.getRssi()
   7366                                     + " freq=" + mWifiInfo.getFrequency()
   7367                                     + " reason=" + message.arg2
   7368                                     + " -> debounce");
   7369                         }
   7370                         return HANDLED;
   7371                     } else {
   7372                         if (DBG) {
   7373                             int ajst = -1;
   7374                             if (config != null) ajst = config.autoJoinStatus;
   7375                             log("NETWORK_DISCONNECTION_EVENT in connected state"
   7376                                     + " BSSID=" + mWifiInfo.getBSSID()
   7377                                     + " RSSI=" + mWifiInfo.getRssi()
   7378                                     + " freq=" + mWifiInfo.getFrequency()
   7379                                     + " was debouncing=" + linkDebouncing
   7380                                     + " reason=" + message.arg2
   7381                                     + " ajst=" + ajst);
   7382                         }
   7383                     }
   7384                     break;
   7385                 case CMD_AUTO_ROAM:
   7386                     // Clear the driver roam indication since we are attempting a framerwork roam
   7387                     mLastDriverRoamAttempt = 0;
   7388 
   7389                     /* Connect command coming from auto-join */
   7390                     ScanResult candidate = (ScanResult)message.obj;
   7391                     String bssid = "any";
   7392                     if (candidate != null && candidate.is5GHz()) {
   7393                         // Only lock BSSID for 5GHz networks
   7394                         bssid = candidate.BSSID;
   7395                     }
   7396                     int netId = mLastNetworkId;
   7397                     config = getCurrentWifiConfiguration();
   7398 
   7399 
   7400                     if (config == null) {
   7401                         loge("AUTO_ROAM and no config, bail out...");
   7402                         break;
   7403                     }
   7404 
   7405                     loge("CMD_AUTO_ROAM sup state "
   7406                             + mSupplicantStateTracker.getSupplicantStateName()
   7407                             + " my state " + getCurrentState().getName()
   7408                             + " nid=" + Integer.toString(netId)
   7409                             + " config " + config.configKey()
   7410                             + " roam=" + Integer.toString(message.arg2)
   7411                             + " to " + bssid
   7412                             + " targetRoamBSSID " + mTargetRoamBSSID);
   7413 
   7414                     /* Save the BSSID so as to lock it @ firmware */
   7415                     if (!autoRoamSetBSSID(config, bssid) && !linkDebouncing) {
   7416                         loge("AUTO_ROAM nothing to do");
   7417                         // Same BSSID, nothing to do
   7418                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   7419                         break;
   7420                     };
   7421 
   7422                     // Make sure the network is enabled, since supplicant will not reenable it
   7423                     mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
   7424 
   7425                     boolean ret = false;
   7426                     if (mLastNetworkId != netId) {
   7427                        if (mWifiConfigStore.selectNetwork(netId) &&
   7428                            mWifiNative.reconnect()) {
   7429                            ret = true;
   7430                        }
   7431                     } else {
   7432                          ret = mWifiNative.reassociate();
   7433                     }
   7434                     if (ret) {
   7435                         lastConnectAttempt = System.currentTimeMillis();
   7436                         targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
   7437 
   7438                         // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
   7439                         mAutoRoaming = message.arg2;
   7440                         transitionTo(mRoamingState);
   7441 
   7442                     } else {
   7443                         loge("Failed to connect config: " + config + " netId: " + netId);
   7444                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   7445                                 WifiManager.ERROR);
   7446                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   7447                         break;
   7448                     }
   7449                     break;
   7450                 default:
   7451                     return NOT_HANDLED;
   7452             }
   7453             return HANDLED;
   7454         }
   7455 
   7456         @Override
   7457         public void exit() {
   7458             loge("WifiStateMachine: Leaving Connected state");
   7459             setScanAlarm(false, 0);
   7460             mLastDriverRoamAttempt = 0;
   7461         }
   7462     }
   7463 
   7464     class DisconnectingState extends State {
   7465 
   7466         @Override
   7467         public void enter() {
   7468             mCurrentScanAlarmMs = mDisconnectedScanPeriodMs;
   7469 
   7470             if (PDBG) {
   7471                 loge(" Enter DisconnectingState State scan interval " + mFrameworkScanIntervalMs
   7472                         + " mEnableBackgroundScan= " + mEnableBackgroundScan
   7473                         + " screenOn=" + mScreenOn);
   7474             }
   7475 
   7476             // Make sure we disconnect: we enter this state prior connecting to a new
   7477             // network, waiting for either a DISCONECT event or a SUPPLICANT_STATE_CHANGE
   7478             // event which in this case will be indicating that supplicant started to associate.
   7479             // In some cases supplicant doesn't ignore the connect requests (it might not
   7480             // find the target SSID in its cache),
   7481             // Therefore we end up stuck that state, hence the need for the watchdog.
   7482             disconnectingWatchdogCount++;
   7483             loge("Start Disconnecting Watchdog " + disconnectingWatchdogCount);
   7484             sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
   7485                     disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
   7486         }
   7487 
   7488         @Override
   7489         public boolean processMessage(Message message) {
   7490             logStateAndMessage(message, getClass().getSimpleName());
   7491             switch (message.what) {
   7492                 case CMD_SET_OPERATIONAL_MODE:
   7493                     if (message.arg1 != CONNECT_MODE) {
   7494                         deferMessage(message);
   7495                     }
   7496                     break;
   7497                 case CMD_START_SCAN:
   7498                     // Ignore scans while disconnecting
   7499                     return HANDLED;
   7500                 case CMD_DISCONNECTING_WATCHDOG_TIMER:
   7501                     if (disconnectingWatchdogCount == message.arg1) {
   7502                         if (DBG) log("disconnecting watchdog! -> disconnect");
   7503                         handleNetworkDisconnect();
   7504                         transitionTo(mDisconnectedState);
   7505                     }
   7506                     break;
   7507                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   7508                     /**
   7509                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
   7510                      * we have missed the network disconnection, transition to mDisconnectedState
   7511                      * and handle the rest of the events there
   7512                      */
   7513                     deferMessage(message);
   7514                     handleNetworkDisconnect();
   7515                     transitionTo(mDisconnectedState);
   7516                     break;
   7517                 default:
   7518                     return NOT_HANDLED;
   7519             }
   7520             return HANDLED;
   7521         }
   7522 
   7523         @Override
   7524         public void exit() {
   7525             mCurrentScanAlarmMs = 0;
   7526         }
   7527     }
   7528 
   7529     class DisconnectedState extends State {
   7530         @Override
   7531         public void enter() {
   7532             // We dont scan frequently if this is a temporary disconnect
   7533             // due to p2p
   7534             if (mTemporarilyDisconnectWifi) {
   7535                 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
   7536                 return;
   7537             }
   7538 
   7539             // Loose the last selection choice
   7540             // mWifiAutoJoinController.setLastSelectedConfiguration
   7541             // (WifiConfiguration.INVALID_NETWORK_ID);
   7542 
   7543             mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
   7544                     Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
   7545                     mDefaultFrameworkScanIntervalMs);
   7546 
   7547             if (mScreenOn)
   7548                 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs;
   7549 
   7550             if (PDBG) {
   7551                 loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs
   7552                         + " mEnableBackgroundScan= " + mEnableBackgroundScan
   7553                         + " screenOn=" + mScreenOn);
   7554             }
   7555 
   7556             /** clear the roaming state, if we were roaming, we failed */
   7557             mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
   7558 
   7559             // Reenable all networks, allow for hidden networks to be scanned
   7560             mWifiConfigStore.enableAllNetworks();
   7561 
   7562             /**
   7563              * - screen dark and PNO supported => scan alarm disabled
   7564              * - everything else => scan alarm enabled with mDefaultFrameworkScanIntervalMs period
   7565              */
   7566             if ((mScreenOn == false) && mEnableBackgroundScan) { //mEnableBackgroundScan) {
   7567                 /* If a regular scan result is pending, do not initiate background
   7568                  * scan until the scan results are returned. This is needed because
   7569                  * initiating a background scan will cancel the regular scan and
   7570                  * scan results will not be returned until background scanning is
   7571                  * cleared
   7572                  */
   7573                 if (!mIsScanOngoing) {
   7574                     mWifiNative.enableBackgroundScan(true);
   7575                 }
   7576             } else {
   7577                 setScanAlarm(true, 200);
   7578             }
   7579 
   7580             /**
   7581              * If we have no networks saved, the supplicant stops doing the periodic scan.
   7582              * The scans are useful to notify the user of the presence of an open network.
   7583              * Note that these are not wake up scans.
   7584              */
   7585             if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) {
   7586                 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
   7587                         ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
   7588             }
   7589 
   7590             mDisconnectedTimeStamp = System.currentTimeMillis();
   7591 
   7592         }
   7593         @Override
   7594         public boolean processMessage(Message message) {
   7595             boolean ret = HANDLED;
   7596 
   7597             logStateAndMessage(message, getClass().getSimpleName());
   7598 
   7599             switch (message.what) {
   7600                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
   7601                     if (mP2pConnected.get()) break;
   7602                     if (message.arg1 == mPeriodicScanToken &&
   7603                             mWifiConfigStore.getConfiguredNetworks().size() == 0) {
   7604                         startScan(UNKNOWN_SCAN_SOURCE, -1, null, null);
   7605                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
   7606                                     ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
   7607                     }
   7608                     break;
   7609                 case WifiManager.FORGET_NETWORK:
   7610                 case CMD_REMOVE_NETWORK:
   7611                     // Set up a delayed message here. After the forget/remove is handled
   7612                     // the handled delayed message will determine if there is a need to
   7613                     // scan and continue
   7614                     sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
   7615                                 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
   7616                     ret = NOT_HANDLED;
   7617                     break;
   7618                 case CMD_SET_OPERATIONAL_MODE:
   7619                     if (message.arg1 != CONNECT_MODE) {
   7620                         mOperationalMode = message.arg1;
   7621 
   7622                         mWifiConfigStore.disableAllNetworks();
   7623                         if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
   7624                             mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
   7625                             setWifiState(WIFI_STATE_DISABLED);
   7626                         }
   7627 
   7628                         transitionTo(mScanModeState);
   7629                     }
   7630                     break;
   7631                     /* Ignore network disconnect */
   7632                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   7633                     break;
   7634                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   7635                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   7636                     if (DBG) {
   7637                         loge("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state +
   7638                                 " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state)
   7639                                 + " debouncing=" + linkDebouncing);
   7640                     }
   7641                     setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
   7642                     /* ConnectModeState does the rest of the handling */
   7643                     ret = NOT_HANDLED;
   7644                     break;
   7645                 case CMD_START_SCAN:
   7646                     if (!isScanAllowed()) {
   7647                         // Ignore the scan request
   7648                         return HANDLED;
   7649                     }
   7650                     /* Disable background scan temporarily during a regular scan */
   7651                     if (mEnableBackgroundScan) {
   7652                         mWifiNative.enableBackgroundScan(false);
   7653                     }
   7654                     /* Handled in parent state */
   7655                     ret = NOT_HANDLED;
   7656                     break;
   7657                 case WifiMonitor.SCAN_RESULTS_EVENT:
   7658                     /* Re-enable background scan when a pending scan result is received */
   7659                     if (mEnableBackgroundScan && mIsScanOngoing) {
   7660                         mWifiNative.enableBackgroundScan(true);
   7661                     }
   7662                     /* Handled in parent state */
   7663                     ret = NOT_HANDLED;
   7664                     break;
   7665                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
   7666                     NetworkInfo info = (NetworkInfo) message.obj;
   7667                     mP2pConnected.set(info.isConnected());
   7668                     if (mP2pConnected.get()) {
   7669                         int defaultInterval = mContext.getResources().getInteger(
   7670                                 R.integer.config_wifi_scan_interval_p2p_connected);
   7671                         long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
   7672                                 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
   7673                                 defaultInterval);
   7674                         mWifiNative.setScanInterval((int) scanIntervalMs/1000);
   7675                     } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) {
   7676                         if (DBG) log("Turn on scanning after p2p disconnected");
   7677                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
   7678                                     ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
   7679                     }
   7680                 case CMD_RECONNECT:
   7681                 case CMD_REASSOCIATE:
   7682                     if (mTemporarilyDisconnectWifi) {
   7683                         // Drop a third party reconnect/reassociate if STA is
   7684                         // temporarily disconnected for p2p
   7685                         break;
   7686                     } else {
   7687                         // ConnectModeState handles it
   7688                         ret = NOT_HANDLED;
   7689                     }
   7690                     break;
   7691                 case CMD_SCREEN_STATE_CHANGED:
   7692                     handleScreenStateChanged(message.arg1 != 0,
   7693                             /* startBackgroundScanIfNeeded = */ true);
   7694                     break;
   7695                 default:
   7696                     ret = NOT_HANDLED;
   7697             }
   7698             return ret;
   7699         }
   7700 
   7701         @Override
   7702         public void exit() {
   7703             /* No need for a background scan upon exit from a disconnected state */
   7704             if (mEnableBackgroundScan) {
   7705                 mWifiNative.enableBackgroundScan(false);
   7706             }
   7707             mCurrentScanAlarmMs = 0;
   7708             setScanAlarm(false, 0);
   7709         }
   7710     }
   7711 
   7712     class WpsRunningState extends State {
   7713         // Tracks the source to provide a reply
   7714         private Message mSourceMessage;
   7715         @Override
   7716         public void enter() {
   7717             mSourceMessage = Message.obtain(getCurrentMessage());
   7718         }
   7719         @Override
   7720         public boolean processMessage(Message message) {
   7721             logStateAndMessage(message, getClass().getSimpleName());
   7722 
   7723             switch (message.what) {
   7724                 case WifiMonitor.WPS_SUCCESS_EVENT:
   7725                     // Ignore intermediate success, wait for full connection
   7726                     break;
   7727                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   7728                     replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
   7729                     mSourceMessage.recycle();
   7730                     mSourceMessage = null;
   7731                     deferMessage(message);
   7732                     transitionTo(mDisconnectedState);
   7733                     break;
   7734                 case WifiMonitor.WPS_OVERLAP_EVENT:
   7735                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
   7736                             WifiManager.WPS_OVERLAP_ERROR);
   7737                     mSourceMessage.recycle();
   7738                     mSourceMessage = null;
   7739                     transitionTo(mDisconnectedState);
   7740                     break;
   7741                 case WifiMonitor.WPS_FAIL_EVENT:
   7742                     // Arg1 has the reason for the failure
   7743                     if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
   7744                         replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
   7745                         mSourceMessage.recycle();
   7746                         mSourceMessage = null;
   7747                         transitionTo(mDisconnectedState);
   7748                     } else {
   7749                         if (DBG) log("Ignore unspecified fail event during WPS connection");
   7750                     }
   7751                     break;
   7752                 case WifiMonitor.WPS_TIMEOUT_EVENT:
   7753                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
   7754                             WifiManager.WPS_TIMED_OUT);
   7755                     mSourceMessage.recycle();
   7756                     mSourceMessage = null;
   7757                     transitionTo(mDisconnectedState);
   7758                     break;
   7759                 case WifiManager.START_WPS:
   7760                     replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
   7761                     break;
   7762                 case WifiManager.CANCEL_WPS:
   7763                     if (mWifiNative.cancelWps()) {
   7764                         replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
   7765                     } else {
   7766                         replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
   7767                     }
   7768                     transitionTo(mDisconnectedState);
   7769                     break;
   7770                 /**
   7771                  * Defer all commands that can cause connections to a different network
   7772                  * or put the state machine out of connect mode
   7773                  */
   7774                 case CMD_STOP_DRIVER:
   7775                 case CMD_SET_OPERATIONAL_MODE:
   7776                 case WifiManager.CONNECT_NETWORK:
   7777                 case CMD_ENABLE_NETWORK:
   7778                 case CMD_RECONNECT:
   7779                 case CMD_REASSOCIATE:
   7780                     deferMessage(message);
   7781                     break;
   7782                 case CMD_AUTO_CONNECT:
   7783                 case CMD_AUTO_ROAM:
   7784                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   7785                     return HANDLED;
   7786                 case CMD_START_SCAN:
   7787                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   7788                     return HANDLED;
   7789                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   7790                     if (DBG) log("Network connection lost");
   7791                     handleNetworkDisconnect();
   7792                     break;
   7793                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   7794                     if (DBG) log("Ignore Assoc reject event during WPS Connection");
   7795                     break;
   7796                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   7797                     // Disregard auth failure events during WPS connection. The
   7798                     // EAP sequence is retried several times, and there might be
   7799                     // failures (especially for wps pin). We will get a WPS_XXX
   7800                     // event at the end of the sequence anyway.
   7801                     if (DBG) log("Ignore auth failure during WPS connection");
   7802                     break;
   7803                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   7804                     // Throw away supplicant state changes when WPS is running.
   7805                     // We will start getting supplicant state changes once we get
   7806                     // a WPS success or failure
   7807                     break;
   7808                 default:
   7809                     return NOT_HANDLED;
   7810             }
   7811             return HANDLED;
   7812         }
   7813 
   7814         @Override
   7815         public void exit() {
   7816             mWifiConfigStore.enableAllNetworks();
   7817             mWifiConfigStore.loadConfiguredNetworks();
   7818         }
   7819     }
   7820 
   7821     class SoftApStartingState extends State {
   7822         @Override
   7823         public void enter() {
   7824             final Message message = getCurrentMessage();
   7825             if (message.what == CMD_START_AP) {
   7826                 final WifiConfiguration config = (WifiConfiguration) message.obj;
   7827 
   7828                 if (config == null) {
   7829                     mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
   7830                 } else {
   7831                     mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
   7832                     startSoftApWithConfig(config);
   7833                 }
   7834             } else {
   7835                 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
   7836             }
   7837         }
   7838         @Override
   7839         public boolean processMessage(Message message) {
   7840             logStateAndMessage(message, getClass().getSimpleName());
   7841 
   7842             switch(message.what) {
   7843                 case CMD_START_SUPPLICANT:
   7844                 case CMD_STOP_SUPPLICANT:
   7845                 case CMD_START_AP:
   7846                 case CMD_STOP_AP:
   7847                 case CMD_START_DRIVER:
   7848                 case CMD_STOP_DRIVER:
   7849                 case CMD_SET_OPERATIONAL_MODE:
   7850                 case CMD_SET_COUNTRY_CODE:
   7851                 case CMD_SET_FREQUENCY_BAND:
   7852                 case CMD_START_PACKET_FILTERING:
   7853                 case CMD_STOP_PACKET_FILTERING:
   7854                 case CMD_TETHER_STATE_CHANGE:
   7855                     deferMessage(message);
   7856                     break;
   7857                 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
   7858                     WifiConfiguration config = (WifiConfiguration) message.obj;
   7859                     if (config != null) {
   7860                         startSoftApWithConfig(config);
   7861                     } else {
   7862                         loge("Softap config is null!");
   7863                         sendMessage(CMD_START_AP_FAILURE);
   7864                     }
   7865                     break;
   7866                 case CMD_START_AP_SUCCESS:
   7867                     setWifiApState(WIFI_AP_STATE_ENABLED);
   7868                     transitionTo(mSoftApStartedState);
   7869                     break;
   7870                 case CMD_START_AP_FAILURE:
   7871                     setWifiApState(WIFI_AP_STATE_FAILED);
   7872                     transitionTo(mInitialState);
   7873                     break;
   7874                 default:
   7875                     return NOT_HANDLED;
   7876             }
   7877             return HANDLED;
   7878         }
   7879     }
   7880 
   7881     class SoftApStartedState extends State {
   7882         @Override
   7883         public boolean processMessage(Message message) {
   7884             logStateAndMessage(message, getClass().getSimpleName());
   7885 
   7886             switch(message.what) {
   7887                 case CMD_STOP_AP:
   7888                     if (DBG) log("Stopping Soft AP");
   7889                     /* We have not tethered at this point, so we just shutdown soft Ap */
   7890                     try {
   7891                         mNwService.stopAccessPoint(mInterfaceName);
   7892                     } catch(Exception e) {
   7893                         loge("Exception in stopAccessPoint()");
   7894                     }
   7895                     setWifiApState(WIFI_AP_STATE_DISABLED);
   7896                     transitionTo(mInitialState);
   7897                     break;
   7898                 case CMD_START_AP:
   7899                     // Ignore a start on a running access point
   7900                     break;
   7901                     // Fail client mode operation when soft AP is enabled
   7902                 case CMD_START_SUPPLICANT:
   7903                     loge("Cannot start supplicant with a running soft AP");
   7904                     setWifiState(WIFI_STATE_UNKNOWN);
   7905                     break;
   7906                 case CMD_TETHER_STATE_CHANGE:
   7907                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   7908                     if (startTethering(stateChange.available)) {
   7909                         transitionTo(mTetheringState);
   7910                     }
   7911                     break;
   7912                 default:
   7913                     return NOT_HANDLED;
   7914             }
   7915             return HANDLED;
   7916         }
   7917     }
   7918 
   7919     class TetheringState extends State {
   7920         @Override
   7921         public void enter() {
   7922             /* Send ourselves a delayed message to shut down if tethering fails to notify */
   7923             sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
   7924                     ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
   7925         }
   7926         @Override
   7927         public boolean processMessage(Message message) {
   7928             logStateAndMessage(message, getClass().getSimpleName());
   7929 
   7930             switch(message.what) {
   7931                 case CMD_TETHER_STATE_CHANGE:
   7932                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   7933                     if (isWifiTethered(stateChange.active)) {
   7934                         transitionTo(mTetheredState);
   7935                     }
   7936                     return HANDLED;
   7937                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   7938                     if (message.arg1 == mTetherToken) {
   7939                         loge("Failed to get tether update, shutdown soft access point");
   7940                         transitionTo(mSoftApStartedState);
   7941                         // Needs to be first thing handled
   7942                         sendMessageAtFrontOfQueue(CMD_STOP_AP);
   7943                     }
   7944                     break;
   7945                 case CMD_START_SUPPLICANT:
   7946                 case CMD_STOP_SUPPLICANT:
   7947                 case CMD_START_AP:
   7948                 case CMD_STOP_AP:
   7949                 case CMD_START_DRIVER:
   7950                 case CMD_STOP_DRIVER:
   7951                 case CMD_SET_OPERATIONAL_MODE:
   7952                 case CMD_SET_COUNTRY_CODE:
   7953                 case CMD_SET_FREQUENCY_BAND:
   7954                 case CMD_START_PACKET_FILTERING:
   7955                 case CMD_STOP_PACKET_FILTERING:
   7956                     deferMessage(message);
   7957                     break;
   7958                 default:
   7959                     return NOT_HANDLED;
   7960             }
   7961             return HANDLED;
   7962         }
   7963     }
   7964 
   7965     class TetheredState extends State {
   7966         @Override
   7967         public boolean processMessage(Message message) {
   7968             logStateAndMessage(message, getClass().getSimpleName());
   7969 
   7970             switch(message.what) {
   7971                 case CMD_TETHER_STATE_CHANGE:
   7972                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   7973                     if (!isWifiTethered(stateChange.active)) {
   7974                         loge("Tethering reports wifi as untethered!, shut down soft Ap");
   7975                         setHostApRunning(null, false);
   7976                         setHostApRunning(null, true);
   7977                     }
   7978                     return HANDLED;
   7979                 case CMD_STOP_AP:
   7980                     if (DBG) log("Untethering before stopping AP");
   7981                     setWifiApState(WIFI_AP_STATE_DISABLING);
   7982                     stopTethering();
   7983                     transitionTo(mUntetheringState);
   7984                     // More work to do after untethering
   7985                     deferMessage(message);
   7986                     break;
   7987                 default:
   7988                     return NOT_HANDLED;
   7989             }
   7990             return HANDLED;
   7991         }
   7992     }
   7993 
   7994     class UntetheringState extends State {
   7995         @Override
   7996         public void enter() {
   7997             /* Send ourselves a delayed message to shut down if tethering fails to notify */
   7998             sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
   7999                     ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
   8000 
   8001         }
   8002         @Override
   8003         public boolean processMessage(Message message) {
   8004             logStateAndMessage(message, getClass().getSimpleName());
   8005 
   8006             switch(message.what) {
   8007                 case CMD_TETHER_STATE_CHANGE:
   8008                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   8009 
   8010                     /* Wait till wifi is untethered */
   8011                     if (isWifiTethered(stateChange.active)) break;
   8012 
   8013                     transitionTo(mSoftApStartedState);
   8014                     break;
   8015                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   8016                     if (message.arg1 == mTetherToken) {
   8017                         loge("Failed to get tether update, force stop access point");
   8018                         transitionTo(mSoftApStartedState);
   8019                     }
   8020                     break;
   8021                 case CMD_START_SUPPLICANT:
   8022                 case CMD_STOP_SUPPLICANT:
   8023                 case CMD_START_AP:
   8024                 case CMD_STOP_AP:
   8025                 case CMD_START_DRIVER:
   8026                 case CMD_STOP_DRIVER:
   8027                 case CMD_SET_OPERATIONAL_MODE:
   8028                 case CMD_SET_COUNTRY_CODE:
   8029                 case CMD_SET_FREQUENCY_BAND:
   8030                 case CMD_START_PACKET_FILTERING:
   8031                 case CMD_STOP_PACKET_FILTERING:
   8032                     deferMessage(message);
   8033                     break;
   8034                 default:
   8035                     return NOT_HANDLED;
   8036             }
   8037             return HANDLED;
   8038         }
   8039     }
   8040 
   8041     //State machine initiated requests can have replyTo set to null indicating
   8042     //there are no recepients, we ignore those reply actions
   8043     private void replyToMessage(Message msg, int what) {
   8044         if (msg.replyTo == null) return;
   8045         Message dstMsg = obtainMessageWithArg2(msg);
   8046         dstMsg.what = what;
   8047         mReplyChannel.replyToMessage(msg, dstMsg);
   8048     }
   8049 
   8050     private void replyToMessage(Message msg, int what, int arg1) {
   8051         if (msg.replyTo == null) return;
   8052         Message dstMsg = obtainMessageWithArg2(msg);
   8053         dstMsg.what = what;
   8054         dstMsg.arg1 = arg1;
   8055         mReplyChannel.replyToMessage(msg, dstMsg);
   8056     }
   8057 
   8058     private void replyToMessage(Message msg, int what, Object obj) {
   8059         if (msg.replyTo == null) return;
   8060         Message dstMsg = obtainMessageWithArg2(msg);
   8061         dstMsg.what = what;
   8062         dstMsg.obj = obj;
   8063         mReplyChannel.replyToMessage(msg, dstMsg);
   8064     }
   8065 
   8066     /**
   8067      * arg2 on the source message has a unique id that needs to be retained in replies
   8068      * to match the request
   8069 
   8070      * see WifiManager for details
   8071      */
   8072     private Message obtainMessageWithArg2(Message srcMsg) {
   8073         Message msg = Message.obtain();
   8074         msg.arg2 = srcMsg.arg2;
   8075         return msg;
   8076     }
   8077 
   8078     private static int parseHex(char ch) {
   8079         if ('0' <= ch && ch <= '9') {
   8080             return ch - '0';
   8081         } else if ('a' <= ch && ch <= 'f') {
   8082             return ch - 'a' + 10;
   8083         } else if ('A' <= ch && ch <= 'F') {
   8084             return ch - 'A' + 10;
   8085         } else {
   8086             throw new NumberFormatException("" + ch + " is not a valid hex digit");
   8087         }
   8088     }
   8089 
   8090     private byte[] parseHex(String hex) {
   8091         /* This only works for good input; don't throw bad data at it */
   8092         if (hex == null) {
   8093             return new byte[0];
   8094         }
   8095 
   8096         if (hex.length() % 2 != 0) {
   8097             throw new NumberFormatException(hex + " is not a valid hex string");
   8098         }
   8099 
   8100         byte[] result = new byte[(hex.length())/2 + 1];
   8101         result[0] = (byte) ((hex.length())/2);
   8102         for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
   8103             int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1));
   8104             byte b = (byte) (val & 0xFF);
   8105             result[j] = b;
   8106         }
   8107 
   8108         return result;
   8109     }
   8110 
   8111     private static String makeHex(byte[] bytes) {
   8112         StringBuilder sb = new StringBuilder();
   8113         for (byte b : bytes) {
   8114             sb.append(String.format("%02x", b));
   8115         }
   8116         return sb.toString();
   8117     }
   8118 
   8119     private static String makeHex(byte[] bytes, int from, int len) {
   8120         StringBuilder sb = new StringBuilder();
   8121         for (int i = 0; i < len; i++) {
   8122             sb.append(String.format("%02x", bytes[from+i]));
   8123         }
   8124         return sb.toString();
   8125     }
   8126 
   8127 
   8128     private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) {
   8129 
   8130         int len = array1.length + array2.length + array3.length;
   8131 
   8132         if (array1.length != 0) {
   8133             len++;                      /* add another byte for size */
   8134         }
   8135 
   8136         if (array2.length != 0) {
   8137             len++;                      /* add another byte for size */
   8138         }
   8139 
   8140         if (array3.length != 0) {
   8141             len++;                      /* add another byte for size */
   8142         }
   8143 
   8144         byte[] result = new byte[len];
   8145 
   8146         int index = 0;
   8147         if (array1.length != 0) {
   8148             result[index] = (byte) (array1.length & 0xFF);
   8149             index++;
   8150             for (byte b : array1) {
   8151                 result[index] = b;
   8152                 index++;
   8153             }
   8154         }
   8155 
   8156         if (array2.length != 0) {
   8157             result[index] = (byte) (array2.length & 0xFF);
   8158             index++;
   8159             for (byte b : array2) {
   8160                 result[index] = b;
   8161                 index++;
   8162             }
   8163         }
   8164 
   8165         if (array3.length != 0) {
   8166             result[index] = (byte) (array3.length & 0xFF);
   8167             index++;
   8168             for (byte b : array3) {
   8169                 result[index] = b;
   8170                 index++;
   8171             }
   8172         }
   8173         return result;
   8174     }
   8175 
   8176     void handleGsmAuthRequest(SimAuthRequestData requestData) {
   8177         if (targetWificonfiguration == null
   8178                 || targetWificonfiguration.networkId == requestData.networkId) {
   8179             logd("id matches targetWifiConfiguration");
   8180         } else {
   8181             logd("id does not match targetWifiConfiguration");
   8182             return;
   8183         }
   8184 
   8185         TelephonyManager tm = (TelephonyManager)
   8186                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
   8187 
   8188         if (tm != null) {
   8189             StringBuilder sb = new StringBuilder();
   8190             for (String challenge : requestData.challenges) {
   8191 
   8192                 logd("RAND = " + challenge);
   8193 
   8194                 byte[] rand = null;
   8195                 try {
   8196                     rand = parseHex(challenge);
   8197                 } catch (NumberFormatException e) {
   8198                     loge("malformed challenge");
   8199                     continue;
   8200                 }
   8201 
   8202                 String base64Challenge = android.util.Base64.encodeToString(
   8203                         rand, android.util.Base64.NO_WRAP);
   8204                 /*
   8205                  * appType = 1 => SIM, 2 => USIM according to
   8206                  * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx
   8207                  */
   8208                 int appType = 2;
   8209                 String tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
   8210                 logv("Raw Response - " + tmResponse);
   8211 
   8212                 if (tmResponse != null && tmResponse.length() > 4) {
   8213                     byte[] result = android.util.Base64.decode(tmResponse,
   8214                             android.util.Base64.DEFAULT);
   8215                     logv("Hex Response -" + makeHex(result));
   8216                     int sres_len = result[0];
   8217                     String sres = makeHex(result, 1, sres_len);
   8218                     int kc_offset = 1+sres_len;
   8219                     int kc_len = result[kc_offset];
   8220                     String kc = makeHex(result, 1+kc_offset, kc_len);
   8221                     sb.append(":" + kc + ":" + sres);
   8222                     logv("kc:" + kc + " sres:" + sres);
   8223                 } else {
   8224                     loge("bad response - " + tmResponse);
   8225                 }
   8226             }
   8227 
   8228             String response = sb.toString();
   8229             logv("Supplicant Response -" + response);
   8230             mWifiNative.simAuthResponse(requestData.networkId, response);
   8231         } else {
   8232             loge("could not get telephony manager");
   8233         }
   8234     }
   8235 
   8236     void handle3GAuthRequest(SimAuthRequestData requestData) {
   8237 
   8238     }
   8239 }
   8240