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