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