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