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