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