Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.wifi;
     18 
     19 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
     20 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
     21 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
     22 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
     23 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
     24 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
     25 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
     26 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
     27 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
     28 /**
     29  * TODO:
     30  * Deprecate WIFI_STATE_UNKNOWN
     31  */
     32 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
     33 
     34 import android.Manifest;
     35 import android.app.ActivityManager;
     36 import android.app.AlarmManager;
     37 import android.app.PendingIntent;
     38 import android.app.backup.IBackupManager;
     39 import android.bluetooth.BluetoothAdapter;
     40 import android.content.BroadcastReceiver;
     41 import android.content.Context;
     42 import android.content.Intent;
     43 import android.content.IntentFilter;
     44 import android.content.pm.ApplicationInfo;
     45 import android.content.pm.IPackageManager;
     46 import android.content.pm.PackageManager;
     47 import android.database.ContentObserver;
     48 import android.net.ConnectivityManager;
     49 import android.net.DhcpResults;
     50 import android.net.BaseDhcpStateMachine;
     51 import android.net.DhcpStateMachine;
     52 import android.net.Network;
     53 import android.net.dhcp.DhcpClient;
     54 import android.net.InterfaceConfiguration;
     55 import android.net.IpReachabilityMonitor;
     56 import android.net.LinkAddress;
     57 import android.net.LinkProperties;
     58 import android.net.NetworkAgent;
     59 import android.net.NetworkCapabilities;
     60 import android.net.NetworkFactory;
     61 import android.net.NetworkInfo;
     62 import android.net.NetworkInfo.DetailedState;
     63 import android.net.NetworkRequest;
     64 import android.net.NetworkUtils;
     65 import android.net.RouteInfo;
     66 import android.net.StaticIpConfiguration;
     67 import android.net.TrafficStats;
     68 import android.net.wifi.RssiPacketCountInfo;
     69 import android.net.wifi.ScanResult;
     70 import android.net.wifi.ScanSettings;
     71 import android.net.wifi.SupplicantState;
     72 import android.net.wifi.WifiChannel;
     73 import android.net.wifi.WifiConfiguration;
     74 import android.net.wifi.WifiConnectionStatistics;
     75 import android.net.wifi.WifiEnterpriseConfig;
     76 import android.net.wifi.WifiInfo;
     77 import android.net.wifi.WifiLinkLayerStats;
     78 import android.net.wifi.WifiManager;
     79 import android.net.wifi.WifiScanner;
     80 import android.net.wifi.WifiSsid;
     81 import android.net.wifi.WpsInfo;
     82 import android.net.wifi.WpsResult;
     83 import android.net.wifi.WpsResult.Status;
     84 import android.net.wifi.p2p.IWifiP2pManager;
     85 import android.os.BatteryStats;
     86 import android.os.Binder;
     87 import android.os.Bundle;
     88 import android.os.IBinder;
     89 import android.os.INetworkManagementService;
     90 import android.os.Looper;
     91 import android.os.Message;
     92 import android.os.Messenger;
     93 import android.os.PowerManager;
     94 import android.os.Process;
     95 import android.os.RemoteException;
     96 import android.os.ServiceManager;
     97 import android.os.SystemClock;
     98 import android.os.SystemProperties;
     99 import android.os.UserHandle;
    100 import android.os.WorkSource;
    101 import android.provider.Settings;
    102 import android.telephony.TelephonyManager;
    103 import android.text.TextUtils;
    104 import android.util.Log;
    105 import android.util.LruCache;
    106 
    107 import com.android.internal.R;
    108 import com.android.internal.app.IBatteryStats;
    109 import com.android.internal.util.AsyncChannel;
    110 import com.android.internal.util.Protocol;
    111 import com.android.internal.util.State;
    112 import com.android.internal.util.StateMachine;
    113 import com.android.server.net.NetlinkTracker;
    114 import com.android.server.wifi.hotspot2.NetworkDetail;
    115 import com.android.server.wifi.hotspot2.SupplicantBridge;
    116 import com.android.server.wifi.hotspot2.Utils;
    117 import com.android.server.wifi.p2p.WifiP2pServiceImpl;
    118 
    119 import java.io.BufferedReader;
    120 import java.io.FileDescriptor;
    121 import java.io.FileNotFoundException;
    122 import java.io.FileReader;
    123 import java.io.IOException;
    124 import java.io.PrintWriter;
    125 import java.net.Inet4Address;
    126 import java.net.InetAddress;
    127 import java.util.ArrayList;
    128 import java.util.Calendar;
    129 import java.util.HashSet;
    130 import java.util.LinkedList;
    131 import java.util.List;
    132 import java.util.Locale;
    133 import java.util.Queue;
    134 import java.util.Random;
    135 import java.util.concurrent.atomic.AtomicBoolean;
    136 import java.util.concurrent.atomic.AtomicInteger;
    137 import java.util.regex.Pattern;
    138 
    139 /**
    140  * Track the state of Wifi connectivity. All event handling is done here,
    141  * and all changes in connectivity state are initiated here.
    142  *
    143  * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p
    144  * In the current implementation, we support concurrent wifi p2p and wifi operation.
    145  * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService
    146  * handles p2p operation.
    147  *
    148  * @hide
    149  */
    150 public class WifiStateMachine extends StateMachine implements WifiNative.WifiPnoEventHandler {
    151 
    152     private static final String NETWORKTYPE = "WIFI";
    153     private static final String NETWORKTYPE_UNTRUSTED = "WIFI_UT";
    154     private static boolean DBG = false;
    155     private static boolean VDBG = false;
    156     private static boolean VVDBG = false;
    157     private static boolean USE_PAUSE_SCANS = false;
    158     private static boolean mLogMessages = false;
    159     private static final String TAG = "WifiStateMachine";
    160 
    161     private static final int ONE_HOUR_MILLI = 1000 * 60 * 60;
    162 
    163     private static final String GOOGLE_OUI = "DA-A1-19";
    164 
    165     /* temporary debug flag - best network selection development */
    166     private static boolean PDBG = false;
    167 
    168     /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting
    169      * the corresponding BSSID.
    170      */
    171     private boolean didBlackListBSSID = false;
    172 
    173     /**
    174      * Log with error attribute
    175      *
    176      * @param s is string log
    177      */
    178     protected void loge(String s) {
    179         Log.e(getName(), s);
    180     }
    181     protected void logd(String s) {
    182         Log.d(getName(), s);
    183     }
    184     protected void log(String s) {;
    185         Log.d(getName(), s);
    186     }
    187 
    188     private WifiMonitor mWifiMonitor;
    189     private WifiNative mWifiNative;
    190     private WifiConfigStore mWifiConfigStore;
    191     private WifiAutoJoinController mWifiAutoJoinController;
    192     private INetworkManagementService mNwService;
    193     private ConnectivityManager mCm;
    194     private WifiLogger mWifiLogger;
    195     private WifiApConfigStore mWifiApConfigStore;
    196     private final boolean mP2pSupported;
    197     private final AtomicBoolean mP2pConnected = new AtomicBoolean(false);
    198     private boolean mTemporarilyDisconnectWifi = false;
    199     private final String mPrimaryDeviceType;
    200 
    201     /* Scan results handling */
    202     private List<ScanDetail> mScanResults = new ArrayList<>();
    203     private static final Pattern scanResultPattern = Pattern.compile("\t+");
    204     private static final int SCAN_RESULT_CACHE_SIZE = 160;
    205     private final LruCache<NetworkDetail, ScanDetail> mScanResultCache;
    206     // For debug, number of known scan results that were found as part of last scan result event,
    207     // as well the number of scans results returned by the supplicant with that message
    208     private int mNumScanResultsKnown;
    209     private int mNumScanResultsReturned;
    210 
    211     private boolean mScreenOn = false;
    212 
    213     /* Chipset supports background scan */
    214     private final boolean mBackgroundScanSupported;
    215 
    216     private final String mInterfaceName;
    217     /* Tethering interface could be separate from wlan interface */
    218     private String mTetherInterfaceName;
    219 
    220     private int mLastSignalLevel = -1;
    221     private String mLastBssid;
    222     private int mLastNetworkId; // The network Id we successfully joined
    223     private boolean linkDebouncing = false;
    224 
    225     private boolean mHalBasedPnoDriverSupported = false;
    226 
    227     // Below booleans are configurations coming from the Developper Settings
    228     private boolean mEnableAssociatedNetworkSwitchingInDevSettings = true;
    229     private boolean mHalBasedPnoEnableInDevSettings = false;
    230 
    231 
    232     private int mHalFeatureSet = 0;
    233     private static int mPnoResultFound = 0;
    234 
    235     @Override
    236     public void onPnoNetworkFound(ScanResult results[]) {
    237         if (DBG) {
    238             Log.e(TAG, "onPnoNetworkFound event received num = " + results.length);
    239             for (int i = 0; i < results.length; i++) {
    240                 Log.e(TAG, results[i].toString());
    241             }
    242         }
    243         sendMessage(CMD_PNO_NETWORK_FOUND, results.length, 0, results);
    244     }
    245 
    246     public void processPnoNetworkFound(ScanResult results[]) {
    247         ScanSettings settings = new ScanSettings();
    248         settings.channelSet = new ArrayList<WifiChannel>();
    249         StringBuilder sb = new StringBuilder();
    250         sb.append("");
    251         for (int i=0; i<results.length; i++) {
    252             WifiChannel channel = new WifiChannel();
    253             channel.freqMHz = results[i].frequency;
    254             settings.channelSet.add(channel);
    255             sb.append(results[i].SSID).append(" ");
    256         }
    257 
    258         stopPnoOffload();
    259 
    260         Log.e(TAG, "processPnoNetworkFound starting scan cnt=" + mPnoResultFound);
    261         startScan(PNO_NETWORK_FOUND_SOURCE, mPnoResultFound,  settings, null);
    262         mPnoResultFound ++;
    263         //sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
    264         int delay = 30 * 1000;
    265         // reconfigure Pno after 1 minutes if we're still in disconnected state
    266         sendMessageDelayed(CMD_RESTART_AUTOJOIN_OFFLOAD, delay,
    267                 mRestartAutoJoinOffloadCounter, " processPnoNetworkFound " + sb.toString(),
    268                 (long)delay);
    269         mRestartAutoJoinOffloadCounter++;
    270     }
    271 
    272     public void registerNetworkDisabled(int netId) {
    273         // Restart legacy PNO and autojoin offload if needed
    274         sendMessage(CMD_RESTART_AUTOJOIN_OFFLOAD, 0,
    275                 mRestartAutoJoinOffloadCounter, " registerNetworkDisabled " + netId);
    276         mRestartAutoJoinOffloadCounter++;
    277     }
    278 
    279     // Testing various network disconnect cases by sending lots of spurious
    280     // disconnect to supplicant
    281     private boolean testNetworkDisconnect = false;
    282 
    283     private boolean mEnableRssiPolling = false;
    284     private boolean mLegacyPnoEnabled = false;
    285     private int mRssiPollToken = 0;
    286     /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
    287     * In CONNECT_MODE, the STA can scan and connect to an access point
    288     * In SCAN_ONLY_MODE, the STA can only scan for access points
    289     * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off
    290     */
    291     private int mOperationalMode = CONNECT_MODE;
    292     private boolean mIsScanOngoing = false;
    293     private boolean mIsFullScanOngoing = false;
    294     private boolean mSendScanResultsBroadcast = false;
    295 
    296     private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>();
    297     private WorkSource mScanWorkSource = null;
    298     private static final int UNKNOWN_SCAN_SOURCE = -1;
    299     private static final int SCAN_ALARM_SOURCE = -2;
    300     private static final int ADD_OR_UPDATE_SOURCE = -3;
    301     private static final int SET_ALLOW_UNTRUSTED_SOURCE = -4;
    302     private static final int ENABLE_WIFI = -5;
    303     public static final int DFS_RESTRICTED_SCAN_REQUEST = -6;
    304     public static final int PNO_NETWORK_FOUND_SOURCE = -7;
    305 
    306     private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10;
    307     private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings";
    308     private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource";
    309     private static final String SCAN_REQUEST_TIME = "scan_request_time";
    310 
    311     /* Tracks if state machine has received any screen state change broadcast yet.
    312      * We can miss one of these at boot.
    313      */
    314     private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false);
    315 
    316     private boolean mBluetoothConnectionActive = false;
    317 
    318     private PowerManager.WakeLock mSuspendWakeLock;
    319 
    320     /**
    321      * Interval in milliseconds between polling for RSSI
    322      * and linkspeed information
    323      */
    324     private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
    325 
    326     /**
    327      * Interval in milliseconds between receiving a disconnect event
    328      * while connected to a good AP, and handling the disconnect proper
    329      */
    330     private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 7000;
    331 
    332     /**
    333      * Delay between supplicant restarts upon failure to establish connection
    334      */
    335     private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000;
    336 
    337     /**
    338      * Number of times we attempt to restart supplicant
    339      */
    340     private static final int SUPPLICANT_RESTART_TRIES = 5;
    341 
    342     private int mSupplicantRestartCount = 0;
    343     /* Tracks sequence number on stop failure message */
    344     private int mSupplicantStopFailureToken = 0;
    345 
    346     /**
    347      * Tether state change notification time out
    348      */
    349     private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000;
    350 
    351     /* Tracks sequence number on a tether notification time out */
    352     private int mTetherToken = 0;
    353 
    354     /**
    355      * Driver start time out.
    356      */
    357     private static final int DRIVER_START_TIME_OUT_MSECS = 10000;
    358 
    359     /* Tracks sequence number on a driver time out */
    360     private int mDriverStartToken = 0;
    361 
    362     /**
    363      * Don't select new network when previous network selection is
    364      * pending connection for this much time
    365      */
    366     private static final int CONNECT_TIMEOUT_MSEC = 3000;
    367 
    368     /**
    369      * The link properties of the wifi interface.
    370      * Do not modify this directly; use updateLinkProperties instead.
    371      */
    372     private LinkProperties mLinkProperties;
    373 
    374     /* Tracks sequence number on a periodic scan message */
    375     private int mPeriodicScanToken = 0;
    376 
    377     // Wakelock held during wifi start/stop and driver load/unload
    378     private PowerManager.WakeLock mWakeLock;
    379 
    380     private Context mContext;
    381 
    382     private final Object mDhcpResultsLock = new Object();
    383     private DhcpResults mDhcpResults;
    384 
    385     // NOTE: Do not return to clients - use #getWiFiInfoForUid(int)
    386     private WifiInfo mWifiInfo;
    387     private NetworkInfo mNetworkInfo;
    388     private NetworkCapabilities mNetworkCapabilities;
    389     private SupplicantStateTracker mSupplicantStateTracker;
    390     private BaseDhcpStateMachine mDhcpStateMachine;
    391     private boolean mDhcpActive = false;
    392 
    393     private int mWifiLinkLayerStatsSupported = 4; // Temporary disable
    394 
    395     private final AtomicInteger mCountryCodeSequence = new AtomicInteger();
    396 
    397     // Whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress
    398     private int mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
    399 
    400     // Roaming failure count
    401     private int mRoamFailCount = 0;
    402 
    403     // This is the BSSID we are trying to associate to, it can be set to "any"
    404     // if we havent selected a BSSID for joining.
    405     // if we havent selected a BSSID for joining.
    406     // The BSSID we are associated to is found in mWifiInfo
    407     private String mTargetRoamBSSID = "any";
    408 
    409     private long mLastDriverRoamAttempt = 0;
    410 
    411     private WifiConfiguration targetWificonfiguration = null;
    412 
    413     // Used as debug to indicate which configuration last was saved
    414     private WifiConfiguration lastSavedConfigurationAttempt = null;
    415 
    416     // Used as debug to indicate which configuration last was removed
    417     private WifiConfiguration lastForgetConfigurationAttempt = null;
    418 
    419     //Random used by softAP channel Selection
    420     private static Random mRandom = new Random(Calendar.getInstance().getTimeInMillis());
    421 
    422     boolean isRoaming() {
    423         return mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_ROAMING
    424                 || mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_EXTENDED_ROAMING;
    425     }
    426 
    427     public void autoRoamSetBSSID(int netId, String bssid) {
    428         autoRoamSetBSSID(mWifiConfigStore.getWifiConfiguration(netId), bssid);
    429     }
    430 
    431     public boolean autoRoamSetBSSID(WifiConfiguration config, String bssid) {
    432         boolean ret = true;
    433         if (mTargetRoamBSSID == null) mTargetRoamBSSID = "any";
    434         if (bssid == null) bssid = "any";
    435         if (config == null) return false; // Nothing to do
    436 
    437         if (mTargetRoamBSSID != null && bssid == mTargetRoamBSSID && bssid == config.BSSID) {
    438             return false; // We didnt change anything
    439         }
    440         if (!mTargetRoamBSSID.equals("any") && bssid.equals("any")) {
    441             // Changing to ANY
    442             if (!mWifiConfigStore.roamOnAny) {
    443                 ret = false; // Nothing to do
    444             }
    445         }
    446         if (VDBG) {
    447             logd("autoRoamSetBSSID " + bssid + " key=" + config.configKey());
    448         }
    449         config.autoJoinBSSID = bssid;
    450         mTargetRoamBSSID = bssid;
    451         mWifiConfigStore.saveWifiConfigBSSID(config);
    452         return ret;
    453     }
    454 
    455     /**
    456      * Save the UID correctly depending on if this is a new or existing network.
    457      * @return true if operation is authorized, false otherwise
    458      */
    459     boolean recordUidIfAuthorized(WifiConfiguration config, int uid, boolean onlyAnnotate) {
    460         if (!mWifiConfigStore.isNetworkConfigured(config)) {
    461             config.creatorUid = uid;
    462             config.creatorName = mContext.getPackageManager().getNameForUid(uid);
    463         } else if (!mWifiConfigStore.canModifyNetwork(uid, config, onlyAnnotate)) {
    464             return false;
    465         }
    466 
    467         config.lastUpdateUid = uid;
    468         config.lastUpdateName = mContext.getPackageManager().getNameForUid(uid);
    469 
    470         return true;
    471 
    472     }
    473 
    474     /**
    475      * Checks to see if user has specified if the apps configuration is connectable.
    476      * If the user hasn't specified we query the user and return true.
    477      *
    478      * @param message The message to be deferred
    479      * @param netId Network id of the configuration to check against
    480      * @param allowOverride If true we won't defer to the user if the uid of the message holds the
    481      *                      CONFIG_OVERRIDE_PERMISSION
    482      * @return True if we are waiting for user feedback or netId is invalid. False otherwise.
    483      */
    484     boolean deferForUserInput(Message message, int netId, boolean allowOverride){
    485         final WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(netId);
    486 
    487         // We can only evaluate saved configurations.
    488         if (config == null) {
    489             logd("deferForUserInput: configuration for netId=" + netId + " not stored");
    490             return true;
    491         }
    492 
    493         switch (config.userApproved) {
    494             case WifiConfiguration.USER_APPROVED:
    495             case WifiConfiguration.USER_BANNED:
    496                 return false;
    497             case WifiConfiguration.USER_PENDING:
    498             default: // USER_UNSPECIFIED
    499                /* the intention was to ask user here; but a dialog box is   *
    500                 * too invasive; so we are going to allow connection for now */
    501                 config.userApproved = WifiConfiguration.USER_APPROVED;
    502                 return false;
    503         }
    504     }
    505 
    506     /**
    507      * Subset of link properties coming from netlink.
    508      * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers
    509      * and domains obtained from router advertisements (RFC 6106).
    510      */
    511     private NetlinkTracker mNetlinkTracker;
    512 
    513     private IpReachabilityMonitor mIpReachabilityMonitor;
    514 
    515     private AlarmManager mAlarmManager;
    516     private PendingIntent mScanIntent;
    517     private PendingIntent mDriverStopIntent;
    518     private PendingIntent mPnoIntent;
    519 
    520     private int mDisconnectedPnoAlarmCount = 0;
    521     /* Tracks current frequency mode */
    522     private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
    523 
    524     /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */
    525     private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true);
    526 
    527     // Channel for sending replies.
    528     private AsyncChannel mReplyChannel = new AsyncChannel();
    529 
    530     private WifiP2pServiceImpl mWifiP2pServiceImpl;
    531 
    532     // Used to initiate a connection with WifiP2pService
    533     private AsyncChannel mWifiP2pChannel;
    534     private AsyncChannel mWifiApConfigChannel;
    535 
    536     private WifiScanner mWifiScanner;
    537 
    538     private int mConnectionRequests = 0;
    539     private WifiNetworkFactory mNetworkFactory;
    540     private UntrustedWifiNetworkFactory mUntrustedNetworkFactory;
    541     private WifiNetworkAgent mNetworkAgent;
    542 
    543     private String[] mWhiteListedSsids = null;
    544 
    545     // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi
    546     // We should really persist that into the networkHistory.txt file, and read it back when
    547     // WifiStateMachine starts up
    548     private WifiConnectionStatistics mWifiConnectionStatistics = new WifiConnectionStatistics();
    549 
    550     // Used to filter out requests we couldn't possibly satisfy.
    551     private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities();
    552 
    553     /* The base for wifi message types */
    554     static final int BASE = Protocol.BASE_WIFI;
    555     /* Start the supplicant */
    556     static final int CMD_START_SUPPLICANT                               = BASE + 11;
    557     /* Stop the supplicant */
    558     static final int CMD_STOP_SUPPLICANT                                = BASE + 12;
    559     /* Start the driver */
    560     static final int CMD_START_DRIVER                                   = BASE + 13;
    561     /* Stop the driver */
    562     static final int CMD_STOP_DRIVER                                    = BASE + 14;
    563     /* Indicates Static IP succeeded */
    564     static final int CMD_STATIC_IP_SUCCESS                              = BASE + 15;
    565     /* Indicates Static IP failed */
    566     static final int CMD_STATIC_IP_FAILURE                              = BASE + 16;
    567     /* Indicates supplicant stop failed */
    568     static final int CMD_STOP_SUPPLICANT_FAILED                         = BASE + 17;
    569     /* Delayed stop to avoid shutting down driver too quick*/
    570     static final int CMD_DELAYED_STOP_DRIVER                            = BASE + 18;
    571     /* A delayed message sent to start driver when it fail to come up */
    572     static final int CMD_DRIVER_START_TIMED_OUT                         = BASE + 19;
    573 
    574     /* Start the soft access point */
    575     static final int CMD_START_AP                                       = BASE + 21;
    576     /* Indicates soft ap start succeeded */
    577     static final int CMD_START_AP_SUCCESS                               = BASE + 22;
    578     /* Indicates soft ap start failed */
    579     static final int CMD_START_AP_FAILURE                               = BASE + 23;
    580     /* Stop the soft access point */
    581     static final int CMD_STOP_AP                                        = BASE + 24;
    582     /* Set the soft access point configuration */
    583     static final int CMD_SET_AP_CONFIG                                  = BASE + 25;
    584     /* Soft access point configuration set completed */
    585     static final int CMD_SET_AP_CONFIG_COMPLETED                        = BASE + 26;
    586     /* Request the soft access point configuration */
    587     static final int CMD_REQUEST_AP_CONFIG                              = BASE + 27;
    588     /* Response to access point configuration request */
    589     static final int CMD_RESPONSE_AP_CONFIG                             = BASE + 28;
    590     /* Invoked when getting a tether state change notification */
    591     static final int CMD_TETHER_STATE_CHANGE                            = BASE + 29;
    592     /* A delayed message sent to indicate tether state change failed to arrive */
    593     static final int CMD_TETHER_NOTIFICATION_TIMED_OUT                  = BASE + 30;
    594 
    595     static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE                 = BASE + 31;
    596 
    597     /* Supplicant commands */
    598     /* Is supplicant alive ? */
    599     static final int CMD_PING_SUPPLICANT                                = BASE + 51;
    600     /* Add/update a network configuration */
    601     static final int CMD_ADD_OR_UPDATE_NETWORK                          = BASE + 52;
    602     /* Delete a network */
    603     static final int CMD_REMOVE_NETWORK                                 = BASE + 53;
    604     /* Enable a network. The device will attempt a connection to the given network. */
    605     static final int CMD_ENABLE_NETWORK                                 = BASE + 54;
    606     /* Enable all networks */
    607     static final int CMD_ENABLE_ALL_NETWORKS                            = BASE + 55;
    608     /* Blacklist network. De-prioritizes the given BSSID for connection. */
    609     static final int CMD_BLACKLIST_NETWORK                              = BASE + 56;
    610     /* Clear the blacklist network list */
    611     static final int CMD_CLEAR_BLACKLIST                                = BASE + 57;
    612     /* Save configuration */
    613     static final int CMD_SAVE_CONFIG                                    = BASE + 58;
    614     /* Get configured networks */
    615     static final int CMD_GET_CONFIGURED_NETWORKS                        = BASE + 59;
    616     /* Get available frequencies */
    617     static final int CMD_GET_CAPABILITY_FREQ                            = BASE + 60;
    618     /* Get adaptors */
    619     static final int CMD_GET_SUPPORTED_FEATURES                         = BASE + 61;
    620     /* Get configured networks with real preSharedKey */
    621     static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS             = BASE + 62;
    622     /* Get Link Layer Stats thru HAL */
    623     static final int CMD_GET_LINK_LAYER_STATS                           = BASE + 63;
    624     /* Supplicant commands after driver start*/
    625     /* Initiate a scan */
    626     static final int CMD_START_SCAN                                     = BASE + 71;
    627     /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */
    628     static final int CMD_SET_OPERATIONAL_MODE                           = BASE + 72;
    629     /* Disconnect from a network */
    630     static final int CMD_DISCONNECT                                     = BASE + 73;
    631     /* Reconnect to a network */
    632     static final int CMD_RECONNECT                                      = BASE + 74;
    633     /* Reassociate to a network */
    634     static final int CMD_REASSOCIATE                                    = BASE + 75;
    635     /* Get Connection Statistis */
    636     static final int CMD_GET_CONNECTION_STATISTICS                      = BASE + 76;
    637 
    638     /* Controls suspend mode optimizations
    639      *
    640      * When high perf mode is enabled, suspend mode optimizations are disabled
    641      *
    642      * When high perf mode is disabled, suspend mode optimizations are enabled
    643      *
    644      * Suspend mode optimizations include:
    645      * - packet filtering
    646      * - turn off roaming
    647      * - DTIM wake up settings
    648      */
    649     static final int CMD_SET_HIGH_PERF_MODE                             = BASE + 77;
    650     /* Set the country code */
    651     static final int CMD_SET_COUNTRY_CODE                               = BASE + 80;
    652     /* Enables RSSI poll */
    653     static final int CMD_ENABLE_RSSI_POLL                               = BASE + 82;
    654     /* RSSI poll */
    655     static final int CMD_RSSI_POLL                                      = BASE + 83;
    656     /* Set up packet filtering */
    657     static final int CMD_START_PACKET_FILTERING                         = BASE + 84;
    658     /* Clear packet filter */
    659     static final int CMD_STOP_PACKET_FILTERING                          = BASE + 85;
    660     /* Enable suspend mode optimizations in the driver */
    661     static final int CMD_SET_SUSPEND_OPT_ENABLED                        = BASE + 86;
    662     /* Delayed NETWORK_DISCONNECT */
    663     static final int CMD_DELAYED_NETWORK_DISCONNECT                     = BASE + 87;
    664     /* When there are no saved networks, we do a periodic scan to notify user of
    665      * an open network */
    666     static final int CMD_NO_NETWORKS_PERIODIC_SCAN                      = BASE + 88;
    667     /* Test network Disconnection NETWORK_DISCONNECT */
    668     static final int CMD_TEST_NETWORK_DISCONNECT                        = BASE + 89;
    669 
    670     private int testNetworkDisconnectCounter = 0;
    671 
    672     /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */
    673     static final int MULTICAST_V6 = 1;
    674     static final int MULTICAST_V4 = 0;
    675 
    676     /* Set the frequency band */
    677     static final int CMD_SET_FREQUENCY_BAND                             = BASE + 90;
    678     /* Enable TDLS on a specific MAC address */
    679     static final int CMD_ENABLE_TDLS                                    = BASE + 92;
    680     /* DHCP/IP configuration watchdog */
    681     static final int CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER            = BASE + 93;
    682 
    683     /**
    684      * Watchdog for protecting against b/16823537
    685      * Leave time for 4-way handshake to succeed
    686      */
    687     static final int ROAM_GUARD_TIMER_MSEC = 15000;
    688 
    689     int roamWatchdogCount = 0;
    690     /* Roam state watchdog */
    691     static final int CMD_ROAM_WATCHDOG_TIMER                            = BASE + 94;
    692     /* Screen change intent handling */
    693     static final int CMD_SCREEN_STATE_CHANGED                           = BASE + 95;
    694 
    695     /* Disconnecting state watchdog */
    696     static final int CMD_DISCONNECTING_WATCHDOG_TIMER                   = BASE + 96;
    697 
    698     /* Remove a packages associated configrations */
    699     static final int CMD_REMOVE_APP_CONFIGURATIONS                      = BASE + 97;
    700 
    701     /* Disable an ephemeral network */
    702     static final int CMD_DISABLE_EPHEMERAL_NETWORK                      = BASE + 98;
    703 
    704     /* Get matching network */
    705     static final int CMD_GET_MATCHING_CONFIG                            = BASE + 99;
    706 
    707     /* alert from firmware */
    708     static final int CMD_FIRMWARE_ALERT                                 = BASE + 100;
    709 
    710     /**
    711      * Make this timer 40 seconds, which is about the normal DHCP timeout.
    712      * In no valid case, the WiFiStateMachine should remain stuck in ObtainingIpAddress
    713      * for more than 30 seconds.
    714      */
    715     static final int OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC = 40000;
    716 
    717     int obtainingIpWatchdogCount = 0;
    718 
    719     /* Commands from/to the SupplicantStateTracker */
    720     /* Reset the supplicant state tracker */
    721     static final int CMD_RESET_SUPPLICANT_STATE                         = BASE + 111;
    722 
    723     int disconnectingWatchdogCount = 0;
    724     static final int DISCONNECTING_GUARD_TIMER_MSEC = 5000;
    725 
    726     /* P2p commands */
    727     /* We are ok with no response here since we wont do much with it anyway */
    728     public static final int CMD_ENABLE_P2P                              = BASE + 131;
    729     /* In order to shut down supplicant cleanly, we wait till p2p has
    730      * been disabled */
    731     public static final int CMD_DISABLE_P2P_REQ                         = BASE + 132;
    732     public static final int CMD_DISABLE_P2P_RSP                         = BASE + 133;
    733 
    734     public static final int CMD_BOOT_COMPLETED                          = BASE + 134;
    735 
    736     /* We now have a valid IP configuration. */
    737     static final int CMD_IP_CONFIGURATION_SUCCESSFUL                    = BASE + 138;
    738     /* We no longer have a valid IP configuration. */
    739     static final int CMD_IP_CONFIGURATION_LOST                          = BASE + 139;
    740     /* Link configuration (IP address, DNS, ...) changes notified via netlink */
    741     static final int CMD_UPDATE_LINKPROPERTIES                          = BASE + 140;
    742 
    743     /* Supplicant is trying to associate to a given BSSID */
    744     static final int CMD_TARGET_BSSID                                   = BASE + 141;
    745 
    746     /* Reload all networks and reconnect */
    747     static final int CMD_RELOAD_TLS_AND_RECONNECT                       = BASE + 142;
    748 
    749     static final int CMD_AUTO_CONNECT                                   = BASE + 143;
    750 
    751     private static final int NETWORK_STATUS_UNWANTED_DISCONNECT         = 0;
    752     private static final int NETWORK_STATUS_UNWANTED_VALIDATION_FAILED  = 1;
    753     private static final int NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN   = 2;
    754 
    755     static final int CMD_UNWANTED_NETWORK                               = BASE + 144;
    756 
    757     static final int CMD_AUTO_ROAM                                      = BASE + 145;
    758 
    759     static final int CMD_AUTO_SAVE_NETWORK                              = BASE + 146;
    760 
    761     static final int CMD_ASSOCIATED_BSSID                               = BASE + 147;
    762 
    763     static final int CMD_NETWORK_STATUS                                 = BASE + 148;
    764 
    765     /* A layer 3 neighbor on the Wi-Fi link became unreachable. */
    766     static final int CMD_IP_REACHABILITY_LOST                           = BASE + 149;
    767 
    768     /* Remove a packages associated configrations */
    769     static final int CMD_REMOVE_USER_CONFIGURATIONS                     = BASE + 152;
    770 
    771     static final int CMD_ACCEPT_UNVALIDATED                             = BASE + 153;
    772 
    773     /* used to restart PNO when it was stopped due to association attempt */
    774     static final int CMD_RESTART_AUTOJOIN_OFFLOAD                       = BASE + 154;
    775 
    776     static int mRestartAutoJoinOffloadCounter = 0;
    777 
    778     /* used to log if PNO was started */
    779     static final int CMD_STARTED_PNO_DBG                                = BASE + 155;
    780 
    781     static final int CMD_PNO_NETWORK_FOUND                              = BASE + 156;
    782 
    783     /* used to log if PNO was started */
    784     static final int CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION              = BASE + 158;
    785 
    786     /* used to log if GSCAN was started */
    787     static final int CMD_STARTED_GSCAN_DBG                              = BASE + 159;
    788 
    789 
    790     /* Wifi state machine modes of operation */
    791     /* CONNECT_MODE - connect to any 'known' AP when it becomes available */
    792     public static final int CONNECT_MODE = 1;
    793     /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */
    794     public static final int SCAN_ONLY_MODE = 2;
    795     /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */
    796     public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
    797 
    798     private static final int SUCCESS = 1;
    799     private static final int FAILURE = -1;
    800 
    801     /* Tracks if suspend optimizations need to be disabled by DHCP,
    802      * screen or due to high perf mode.
    803      * When any of them needs to disable it, we keep the suspend optimizations
    804      * disabled
    805      */
    806     private int mSuspendOptNeedsDisabled = 0;
    807 
    808     private static final int SUSPEND_DUE_TO_DHCP = 1;
    809     private static final int SUSPEND_DUE_TO_HIGH_PERF = 1 << 1;
    810     private static final int SUSPEND_DUE_TO_SCREEN = 1 << 2;
    811 
    812     /* Tracks if user has enabled suspend optimizations through settings */
    813     private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true);
    814 
    815     /**
    816      * Default framework scan interval in milliseconds. This is used in the scenario in which
    817      * wifi chipset does not support background scanning to set up a
    818      * periodic wake up scan so that the device can connect to a new access
    819      * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can
    820      * override this.
    821      */
    822     private final int mDefaultFrameworkScanIntervalMs;
    823 
    824 
    825     /**
    826      * Scan period for the NO_NETWORKS_PERIIDOC_SCAN_FEATURE
    827      */
    828     private final int mNoNetworksPeriodicScan;
    829 
    830     /**
    831      * Supplicant scan interval in milliseconds.
    832      * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or
    833      * from the default config if the setting is not set
    834      */
    835     private long mSupplicantScanIntervalMs;
    836 
    837     /**
    838      * timeStamp of last full band scan we perfoemed for autojoin while connected with screen lit
    839      */
    840     private long lastFullBandConnectedTimeMilli;
    841 
    842     /**
    843      * time interval to the next full band scan we will perform for
    844      * autojoin while connected with screen lit
    845      */
    846     private long fullBandConnectedTimeIntervalMilli;
    847 
    848     /**
    849      * max time interval to the next full band scan we will perform for
    850      * autojoin while connected with screen lit
    851      * Max time is 5 minutes
    852      */
    853     private static final long maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5;
    854 
    855     /**
    856      * Minimum time interval between enabling all networks.
    857      * A device can end up repeatedly connecting to a bad network on screen on/off toggle
    858      * due to enabling every time. We add a threshold to avoid this.
    859      */
    860     private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */
    861     private long mLastEnableAllNetworksTime;
    862 
    863     int mRunningBeaconCount = 0;
    864 
    865     /**
    866      * Starting and shutting down driver too quick causes problems leading to driver
    867      * being in a bad state. Delay driver stop.
    868      */
    869     private final int mDriverStopDelayMs;
    870     private int mDelayedStopCounter;
    871     private boolean mInDelayedStop = false;
    872 
    873     // there is a delay between StateMachine change country code and Supplicant change country code
    874     // here save the current WifiStateMachine set country code
    875     private volatile String mSetCountryCode = null;
    876 
    877     // Supplicant doesn't like setting the same country code multiple times (it may drop
    878     // currently connected network), so we save the current device set country code here to avoid
    879     // redundency
    880     private String mDriverSetCountryCode = null;
    881 
    882     /* Default parent state */
    883     private State mDefaultState = new DefaultState();
    884     /* Temporary initial state */
    885     private State mInitialState = new InitialState();
    886     /* Driver loaded, waiting for supplicant to start */
    887     private State mSupplicantStartingState = new SupplicantStartingState();
    888     /* Driver loaded and supplicant ready */
    889     private State mSupplicantStartedState = new SupplicantStartedState();
    890     /* Waiting for supplicant to stop and monitor to exit */
    891     private State mSupplicantStoppingState = new SupplicantStoppingState();
    892     /* Driver start issued, waiting for completed event */
    893     private State mDriverStartingState = new DriverStartingState();
    894     /* Driver started */
    895     private State mDriverStartedState = new DriverStartedState();
    896     /* Wait until p2p is disabled
    897      * This is a special state which is entered right after we exit out of DriverStartedState
    898      * before transitioning to another state.
    899      */
    900     private State mWaitForP2pDisableState = new WaitForP2pDisableState();
    901     /* Driver stopping */
    902     private State mDriverStoppingState = new DriverStoppingState();
    903     /* Driver stopped */
    904     private State mDriverStoppedState = new DriverStoppedState();
    905     /* Scan for networks, no connection will be established */
    906     private State mScanModeState = new ScanModeState();
    907     /* Connecting to an access point */
    908     private State mConnectModeState = new ConnectModeState();
    909     /* Connected at 802.11 (L2) level */
    910     private State mL2ConnectedState = new L2ConnectedState();
    911     /* fetching IP after connection to access point (assoc+auth complete) */
    912     private State mObtainingIpState = new ObtainingIpState();
    913     /* Waiting for link quality verification to be complete */
    914     private State mVerifyingLinkState = new VerifyingLinkState();
    915     /* Connected with IP addr */
    916     private State mConnectedState = new ConnectedState();
    917     /* Roaming */
    918     private State mRoamingState = new RoamingState();
    919     /* disconnect issued, waiting for network disconnect confirmation */
    920     private State mDisconnectingState = new DisconnectingState();
    921     /* Network is not connected, supplicant assoc+auth is not complete */
    922     private State mDisconnectedState = new DisconnectedState();
    923     /* Waiting for WPS to be completed*/
    924     private State mWpsRunningState = new WpsRunningState();
    925 
    926     /* Soft ap is starting up */
    927     private State mSoftApStartingState = new SoftApStartingState();
    928     /* Soft ap is running */
    929     private State mSoftApStartedState = new SoftApStartedState();
    930     /* Soft ap is running and we are waiting for tether notification */
    931     private State mTetheringState = new TetheringState();
    932     /* Soft ap is running and we are tethered through connectivity service */
    933     private State mTetheredState = new TetheredState();
    934     /* Waiting for untether confirmation before stopping soft Ap */
    935     private State mUntetheringState = new UntetheringState();
    936 
    937 
    938 
    939     private class WifiScanListener implements WifiScanner.ScanListener {
    940         @Override
    941         public void onSuccess() {
    942             Log.e(TAG, "WifiScanListener onSuccess");
    943         };
    944         @Override
    945         public void onFailure(int reason, String description) {
    946             Log.e(TAG, "WifiScanListener onFailure");
    947         };
    948         @Override
    949         public void onPeriodChanged(int periodInMs) {
    950             Log.e(TAG, "WifiScanListener onPeriodChanged  period=" + periodInMs);
    951         }
    952         @Override
    953         public void onResults(WifiScanner.ScanData[] results) {
    954             Log.e(TAG, "WifiScanListener onResults2 "  + results.length);
    955         }
    956         @Override
    957         public void onFullResult(ScanResult fullScanResult) {
    958             Log.e(TAG, "WifiScanListener onFullResult " + fullScanResult.toString());
    959         }
    960 
    961         WifiScanListener() {}
    962     }
    963 
    964     WifiScanListener mWifiScanListener = new WifiScanListener();
    965 
    966 
    967     private class TetherStateChange {
    968         ArrayList<String> available;
    969         ArrayList<String> active;
    970 
    971         TetherStateChange(ArrayList<String> av, ArrayList<String> ac) {
    972             available = av;
    973             active = ac;
    974         }
    975     }
    976 
    977     public static class SimAuthRequestData {
    978         int networkId;
    979         int protocol;
    980         String ssid;
    981         // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges
    982         // EAP-AKA/AKA': data[] contains rand & authn couple for the single challenge
    983         String[] data;
    984     }
    985 
    986     /**
    987      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
    988      * {@link WifiManager#WIFI_STATE_DISABLING},
    989      * {@link WifiManager#WIFI_STATE_ENABLED},
    990      * {@link WifiManager#WIFI_STATE_ENABLING},
    991      * {@link WifiManager#WIFI_STATE_UNKNOWN}
    992      */
    993     private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
    994 
    995     /**
    996      * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
    997      * {@link WifiManager#WIFI_AP_STATE_DISABLING},
    998      * {@link WifiManager#WIFI_AP_STATE_ENABLED},
    999      * {@link WifiManager#WIFI_AP_STATE_ENABLING},
   1000      * {@link WifiManager#WIFI_AP_STATE_FAILED}
   1001      */
   1002     private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
   1003 
   1004     private static final int SCAN_REQUEST = 0;
   1005     private static final String ACTION_START_SCAN =
   1006             "com.android.server.WifiManager.action.START_SCAN";
   1007 
   1008     private static final int PNO_START_REQUEST = 0;
   1009     private static final String ACTION_START_PNO =
   1010             "com.android.server.WifiManager.action.START_PNO";
   1011 
   1012     private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter";
   1013     private static final int DRIVER_STOP_REQUEST = 0;
   1014     private static final String ACTION_DELAYED_DRIVER_STOP =
   1015             "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
   1016 
   1017     /**
   1018      * Keep track of whether WIFI is running.
   1019      */
   1020     private boolean mIsRunning = false;
   1021 
   1022     /**
   1023      * Keep track of whether we last told the battery stats we had started.
   1024      */
   1025     private boolean mReportedRunning = false;
   1026 
   1027     /**
   1028      * Most recently set source of starting WIFI.
   1029      */
   1030     private final WorkSource mRunningWifiUids = new WorkSource();
   1031 
   1032     /**
   1033      * The last reported UIDs that were responsible for starting WIFI.
   1034      */
   1035     private final WorkSource mLastRunningWifiUids = new WorkSource();
   1036 
   1037     private final IBatteryStats mBatteryStats;
   1038 
   1039     private String mTcpBufferSizes = null;
   1040 
   1041     // Used for debug and stats gathering
   1042     private static int sScanAlarmIntentCount = 0;
   1043 
   1044     final static int frameworkMinScanIntervalSaneValue = 10000;
   1045 
   1046     boolean mPnoEnabled;
   1047     boolean mLazyRoamEnabled;
   1048     long mGScanStartTimeMilli;
   1049     long mGScanPeriodMilli;
   1050 
   1051     public WifiStateMachine(Context context, String wlanInterface,
   1052                             WifiTrafficPoller trafficPoller) {
   1053         super("WifiStateMachine");
   1054         mContext = context;
   1055         mSetCountryCode = Settings.Global.getString(
   1056                 mContext.getContentResolver(), Settings.Global.WIFI_COUNTRY_CODE);
   1057         mInterfaceName = wlanInterface;
   1058         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
   1059         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
   1060                 BatteryStats.SERVICE_NAME));
   1061 
   1062         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
   1063         mNwService = INetworkManagementService.Stub.asInterface(b);
   1064 
   1065         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
   1066                 PackageManager.FEATURE_WIFI_DIRECT);
   1067 
   1068         mWifiNative = new WifiNative(mInterfaceName);
   1069         mWifiConfigStore = new WifiConfigStore(context,this,  mWifiNative);
   1070         mWifiAutoJoinController = new WifiAutoJoinController(context, this,
   1071                 mWifiConfigStore, mWifiConnectionStatistics, mWifiNative);
   1072         mWifiMonitor = new WifiMonitor(this, mWifiNative);
   1073         mWifiLogger = new WifiLogger(this);
   1074 
   1075         mWifiInfo = new WifiInfo();
   1076         mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore,
   1077                 getHandler());
   1078         mLinkProperties = new LinkProperties();
   1079 
   1080         IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE);
   1081         mWifiP2pServiceImpl = (WifiP2pServiceImpl) IWifiP2pManager.Stub.asInterface(s1);
   1082 
   1083         IBinder s2 = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE);
   1084 
   1085         mNetworkInfo.setIsAvailable(false);
   1086         mLastBssid = null;
   1087         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
   1088         mLastSignalLevel = -1;
   1089 
   1090         mNetlinkTracker = new NetlinkTracker(mInterfaceName, new NetlinkTracker.Callback() {
   1091             public void update() {
   1092                 sendMessage(CMD_UPDATE_LINKPROPERTIES);
   1093             }
   1094         });
   1095         try {
   1096             mNwService.registerObserver(mNetlinkTracker);
   1097         } catch (RemoteException e) {
   1098             loge("Couldn't register netlink tracker: " + e.toString());
   1099         }
   1100 
   1101         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
   1102         mScanIntent = getPrivateBroadcast(ACTION_START_SCAN, SCAN_REQUEST);
   1103         mPnoIntent = getPrivateBroadcast(ACTION_START_PNO, PNO_START_REQUEST);
   1104 
   1105         // Make sure the interval is not configured less than 10 seconds
   1106         int period = mContext.getResources().getInteger(
   1107                 R.integer.config_wifi_framework_scan_interval);
   1108         if (period < frameworkMinScanIntervalSaneValue) {
   1109             period = frameworkMinScanIntervalSaneValue;
   1110         }
   1111         mDefaultFrameworkScanIntervalMs = period;
   1112 
   1113         mNoNetworksPeriodicScan = mContext.getResources().getInteger(
   1114                 R.integer.config_wifi_no_network_periodic_scan_interval);
   1115 
   1116         mDriverStopDelayMs = mContext.getResources().getInteger(
   1117                 R.integer.config_wifi_driver_stop_delay);
   1118 
   1119         mBackgroundScanSupported = mContext.getResources().getBoolean(
   1120                 R.bool.config_wifi_background_scan_support);
   1121 
   1122         mPrimaryDeviceType = mContext.getResources().getString(
   1123                 R.string.config_wifi_p2p_device_type);
   1124 
   1125         mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
   1126                 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
   1127 
   1128         mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
   1129         mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
   1130         mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
   1131         mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024);
   1132         mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024);
   1133         // TODO - needs to be a bit more dynamic
   1134         mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter);
   1135 
   1136         mContext.registerReceiver(
   1137                 new BroadcastReceiver() {
   1138                     @Override
   1139                     public void onReceive(Context context, Intent intent) {
   1140                         ArrayList<String> available = intent.getStringArrayListExtra(
   1141                                 ConnectivityManager.EXTRA_AVAILABLE_TETHER);
   1142                         ArrayList<String> active = intent.getStringArrayListExtra(
   1143                                 ConnectivityManager.EXTRA_ACTIVE_TETHER);
   1144                         sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active));
   1145                     }
   1146                 }, new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
   1147 
   1148         mContext.registerReceiver(
   1149                 new BroadcastReceiver() {
   1150                     @Override
   1151                     public void onReceive(Context context, Intent intent) {
   1152                         sScanAlarmIntentCount++; // Used for debug only
   1153                         startScan(SCAN_ALARM_SOURCE, mDelayedScanCounter.incrementAndGet(), null, null);
   1154                         if (VDBG)
   1155                             logd("SCAN ALARM -> " + mDelayedScanCounter.get());
   1156                     }
   1157                 },
   1158                 new IntentFilter(ACTION_START_SCAN));
   1159 
   1160         mContext.registerReceiver(
   1161                 new BroadcastReceiver() {
   1162                     @Override
   1163                     public void onReceive(Context context, Intent intent) {
   1164                         sendMessage(CMD_RESTART_AUTOJOIN_OFFLOAD, 0,
   1165                                 mRestartAutoJoinOffloadCounter, "pno alarm");
   1166                         if (DBG)
   1167                             logd("PNO START ALARM sent");
   1168                     }
   1169                 },
   1170                 new IntentFilter(ACTION_START_PNO));
   1171 
   1172 
   1173         IntentFilter filter = new IntentFilter();
   1174         filter.addAction(Intent.ACTION_SCREEN_ON);
   1175         filter.addAction(Intent.ACTION_SCREEN_OFF);
   1176         mContext.registerReceiver(
   1177                 new BroadcastReceiver() {
   1178                     @Override
   1179                     public void onReceive(Context context, Intent intent) {
   1180                         String action = intent.getAction();
   1181 
   1182                         if (action.equals(Intent.ACTION_SCREEN_ON)) {
   1183                             sendMessage(CMD_SCREEN_STATE_CHANGED, 1);
   1184                         } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
   1185                             sendMessage(CMD_SCREEN_STATE_CHANGED, 0);
   1186                         }
   1187                     }
   1188                 }, filter);
   1189 
   1190         mContext.registerReceiver(
   1191                 new BroadcastReceiver() {
   1192                     @Override
   1193                     public void onReceive(Context context, Intent intent) {
   1194                         int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0);
   1195                         sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0);
   1196                     }
   1197                 },
   1198                 new IntentFilter(ACTION_DELAYED_DRIVER_STOP));
   1199 
   1200         mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
   1201                         Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false,
   1202                 new ContentObserver(getHandler()) {
   1203                     @Override
   1204                     public void onChange(boolean selfChange) {
   1205                         mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
   1206                                 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
   1207                     }
   1208                 });
   1209 
   1210         mContext.registerReceiver(
   1211                 new BroadcastReceiver() {
   1212                     @Override
   1213                     public void onReceive(Context context, Intent intent) {
   1214                         sendMessage(CMD_BOOT_COMPLETED);
   1215                     }
   1216                 },
   1217                 new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
   1218 
   1219         mScanResultCache = new LruCache<>(SCAN_RESULT_CACHE_SIZE);
   1220 
   1221         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
   1222         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName());
   1223 
   1224         mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
   1225         mSuspendWakeLock.setReferenceCounted(false);
   1226 
   1227         mTcpBufferSizes = mContext.getResources().getString(
   1228                 com.android.internal.R.string.config_wifi_tcp_buffers);
   1229 
   1230         addState(mDefaultState);
   1231             addState(mInitialState, mDefaultState);
   1232             addState(mSupplicantStartingState, mDefaultState);
   1233             addState(mSupplicantStartedState, mDefaultState);
   1234                 addState(mDriverStartingState, mSupplicantStartedState);
   1235                 addState(mDriverStartedState, mSupplicantStartedState);
   1236                     addState(mScanModeState, mDriverStartedState);
   1237                     addState(mConnectModeState, mDriverStartedState);
   1238                         addState(mL2ConnectedState, mConnectModeState);
   1239                             addState(mObtainingIpState, mL2ConnectedState);
   1240                             addState(mVerifyingLinkState, mL2ConnectedState);
   1241                             addState(mConnectedState, mL2ConnectedState);
   1242                             addState(mRoamingState, mL2ConnectedState);
   1243                         addState(mDisconnectingState, mConnectModeState);
   1244                         addState(mDisconnectedState, mConnectModeState);
   1245                         addState(mWpsRunningState, mConnectModeState);
   1246                 addState(mWaitForP2pDisableState, mSupplicantStartedState);
   1247                 addState(mDriverStoppingState, mSupplicantStartedState);
   1248                 addState(mDriverStoppedState, mSupplicantStartedState);
   1249             addState(mSupplicantStoppingState, mDefaultState);
   1250             addState(mSoftApStartingState, mDefaultState);
   1251             addState(mSoftApStartedState, mDefaultState);
   1252                 addState(mTetheringState, mSoftApStartedState);
   1253                 addState(mTetheredState, mSoftApStartedState);
   1254                 addState(mUntetheringState, mSoftApStartedState);
   1255 
   1256         setInitialState(mInitialState);
   1257 
   1258         setLogRecSize(ActivityManager.isLowRamDeviceStatic() ? 100 : 3000);
   1259         setLogOnlyTransitions(false);
   1260         if (VDBG) setDbg(true);
   1261 
   1262         //start the state machine
   1263         start();
   1264 
   1265         final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
   1266         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1267         intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
   1268         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1269     }
   1270 
   1271 
   1272     PendingIntent getPrivateBroadcast(String action, int requestCode) {
   1273         Intent intent = new Intent(action, null);
   1274         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1275         //intent.setPackage(this.getClass().getPackage().getName());
   1276         intent.setPackage("android");
   1277         return PendingIntent.getBroadcast(mContext, requestCode, intent, 0);
   1278     }
   1279 
   1280     private int mVerboseLoggingLevel = 0;
   1281 
   1282     int getVerboseLoggingLevel() {
   1283         return mVerboseLoggingLevel;
   1284     }
   1285 
   1286     void enableVerboseLogging(int verbose) {
   1287         mVerboseLoggingLevel = verbose;
   1288         if (verbose > 0) {
   1289             DBG = true;
   1290             VDBG = true;
   1291             PDBG = true;
   1292             mLogMessages = true;
   1293             mWifiNative.setSupplicantLogLevel("DEBUG");
   1294         } else {
   1295             DBG = false;
   1296             VDBG = false;
   1297             PDBG = false;
   1298             mLogMessages = false;
   1299             mWifiNative.setSupplicantLogLevel("INFO");
   1300         }
   1301         mWifiLogger.startLogging(mVerboseLoggingLevel > 0);
   1302         mWifiAutoJoinController.enableVerboseLogging(verbose);
   1303         mWifiMonitor.enableVerboseLogging(verbose);
   1304         mWifiNative.enableVerboseLogging(verbose);
   1305         mWifiConfigStore.enableVerboseLogging(verbose);
   1306         mSupplicantStateTracker.enableVerboseLogging(verbose);
   1307     }
   1308 
   1309     public void setHalBasedAutojoinOffload(int enabled) {
   1310         // Shoult be used for debug only, triggered form developper settings
   1311         // enabling HAl based PNO dynamically is not safe and not a normal operation
   1312         mHalBasedPnoEnableInDevSettings = enabled > 0;
   1313         mWifiConfigStore.enableHalBasedPno.set(mHalBasedPnoEnableInDevSettings);
   1314         mWifiConfigStore.enableSsidWhitelist.set(mHalBasedPnoEnableInDevSettings);
   1315         sendMessage(CMD_DISCONNECT);
   1316     }
   1317 
   1318     int getHalBasedAutojoinOffload() {
   1319         return mHalBasedPnoEnableInDevSettings ? 1 : 0;
   1320     }
   1321 
   1322     boolean useHalBasedAutoJoinOffload() {
   1323         // all three settings need to be true:
   1324         // - developper settings switch
   1325         // - driver support
   1326         // - config option
   1327         return mHalBasedPnoEnableInDevSettings
   1328                 && mHalBasedPnoDriverSupported
   1329                 && mWifiConfigStore.enableHalBasedPno.get();
   1330     }
   1331 
   1332     boolean allowFullBandScanAndAssociated() {
   1333 
   1334         if (!getEnableAutoJoinWhenAssociated()) {
   1335             if (DBG) {
   1336                 Log.e(TAG, "allowFullBandScanAndAssociated: "
   1337                         + " enableAutoJoinWhenAssociated : disallow");
   1338             }
   1339             return false;
   1340         }
   1341 
   1342         if (mWifiInfo.txSuccessRate >
   1343                 mWifiConfigStore.maxTxPacketForFullScans
   1344                 || mWifiInfo.rxSuccessRate >
   1345                 mWifiConfigStore.maxRxPacketForFullScans) {
   1346             if (DBG) {
   1347                 Log.e(TAG, "allowFullBandScanAndAssociated: packet rate tx"
   1348                         + mWifiInfo.txSuccessRate + "  rx "
   1349                         + mWifiInfo.rxSuccessRate
   1350                         + " allow scan with traffic " + getAllowScansWithTraffic());
   1351             }
   1352             // Too much traffic at the interface, hence no full band scan
   1353             if (getAllowScansWithTraffic() == 0) {
   1354                 return false;
   1355             }
   1356         }
   1357 
   1358         if (getCurrentState() != mConnectedState) {
   1359             if (DBG) {
   1360                 Log.e(TAG, "allowFullBandScanAndAssociated: getCurrentState() : disallow");
   1361             }
   1362             return false;
   1363         }
   1364 
   1365         return true;
   1366     }
   1367 
   1368     long mLastScanPermissionUpdate = 0;
   1369     boolean mConnectedModeGScanOffloadStarted = false;
   1370     // Don't do a G-scan enable/re-enable cycle more than once within 20seconds
   1371     // The function updateAssociatedScanPermission() can be called quite frequently, hence
   1372     // we want to throttle the GScan Stop->Start transition
   1373     static final long SCAN_PERMISSION_UPDATE_THROTTLE_MILLI = 20000;
   1374     void updateAssociatedScanPermission() {
   1375 
   1376         if (useHalBasedAutoJoinOffload()) {
   1377             boolean allowed = allowFullBandScanAndAssociated();
   1378 
   1379             long now = System.currentTimeMillis();
   1380             if (mConnectedModeGScanOffloadStarted && !allowed) {
   1381                 if (DBG) {
   1382                     Log.e(TAG, " useHalBasedAutoJoinOffload stop offload");
   1383                 }
   1384                 stopPnoOffload();
   1385                 stopGScan(" useHalBasedAutoJoinOffload");
   1386             }
   1387             if (!mConnectedModeGScanOffloadStarted && allowed) {
   1388                 if ((now - mLastScanPermissionUpdate) > SCAN_PERMISSION_UPDATE_THROTTLE_MILLI) {
   1389                     // Re-enable Gscan offload, this will trigger periodic scans and allow firmware
   1390                     // to look for 5GHz BSSIDs and better networks
   1391                     if (DBG) {
   1392                         Log.e(TAG, " useHalBasedAutoJoinOffload restart offload");
   1393                     }
   1394                     startGScanConnectedModeOffload("updatePermission "
   1395                             + (now - mLastScanPermissionUpdate) + "ms");
   1396                     mLastScanPermissionUpdate = now;
   1397                 }
   1398             }
   1399         }
   1400     }
   1401 
   1402     private int mAggressiveHandover = 0;
   1403 
   1404     int getAggressiveHandover() {
   1405         return mAggressiveHandover;
   1406     }
   1407 
   1408     void enableAggressiveHandover(int enabled) {
   1409         mAggressiveHandover = enabled;
   1410     }
   1411 
   1412     public void clearANQPCache() {
   1413         mWifiConfigStore.trimANQPCache(true);
   1414     }
   1415 
   1416     public void setAllowScansWithTraffic(int enabled) {
   1417         mWifiConfigStore.alwaysEnableScansWhileAssociated.set(enabled);
   1418     }
   1419 
   1420     public int getAllowScansWithTraffic() {
   1421         return mWifiConfigStore.alwaysEnableScansWhileAssociated.get();
   1422     }
   1423 
   1424     public boolean enableAutoJoinWhenAssociated(boolean enabled) {
   1425         boolean old_state = getEnableAutoJoinWhenAssociated();
   1426         mWifiConfigStore.enableAutoJoinWhenAssociated.set(enabled);
   1427         if (!old_state && enabled && mScreenOn && getCurrentState() == mConnectedState) {
   1428             startDelayedScan(mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get(), null,
   1429                     null);
   1430         }
   1431         return true;
   1432     }
   1433 
   1434     public boolean getEnableAutoJoinWhenAssociated() {
   1435         return mWifiConfigStore.enableAutoJoinWhenAssociated.get();
   1436     }
   1437     /*
   1438      *
   1439      * Framework scan control
   1440      */
   1441 
   1442     private boolean mAlarmEnabled = false;
   1443 
   1444     private AtomicInteger mDelayedScanCounter = new AtomicInteger();
   1445 
   1446     private void setScanAlarm(boolean enabled) {
   1447         if (PDBG) {
   1448             String state;
   1449             if (enabled) state = "enabled"; else state = "disabled";
   1450             logd("setScanAlarm " + state
   1451                     + " defaultperiod " + mDefaultFrameworkScanIntervalMs
   1452                     + " mBackgroundScanSupported " + mBackgroundScanSupported);
   1453         }
   1454         if (mBackgroundScanSupported == false) {
   1455             // Scan alarm is only used for background scans if they are not
   1456             // offloaded to the wifi chipset, hence enable the scan alarm
   1457             // gicing us RTC_WAKEUP of backgroundScan is NOT supported
   1458             enabled = true;
   1459         }
   1460 
   1461         if (enabled == mAlarmEnabled) return;
   1462         if (enabled) {
   1463             /* Set RTC_WAKEUP alarms if PNO is not supported - because no one is */
   1464             /* going to wake up the host processor to look for access points */
   1465             mAlarmManager.set(AlarmManager.RTC_WAKEUP,
   1466                     System.currentTimeMillis() + mDefaultFrameworkScanIntervalMs,
   1467                     mScanIntent);
   1468             mAlarmEnabled = true;
   1469         } else {
   1470             mAlarmManager.cancel(mScanIntent);
   1471             mAlarmEnabled = false;
   1472         }
   1473     }
   1474 
   1475     private void cancelDelayedScan() {
   1476         mDelayedScanCounter.incrementAndGet();
   1477     }
   1478 
   1479     private boolean checkAndRestartDelayedScan(int counter, boolean restart, int milli,
   1480                                                ScanSettings settings, WorkSource workSource) {
   1481 
   1482         if (counter != mDelayedScanCounter.get()) {
   1483             return false;
   1484         }
   1485         if (restart)
   1486             startDelayedScan(milli, settings, workSource);
   1487         return true;
   1488     }
   1489 
   1490     private void startDelayedScan(int milli, ScanSettings settings, WorkSource workSource) {
   1491         if (milli <= 0) return;
   1492         /**
   1493          * The cases where the scan alarm should be run are :
   1494          * - DisconnectedState && screenOn => used delayed timer
   1495          * - DisconnectedState && !screenOn && mBackgroundScanSupported => PNO
   1496          * - DisconnectedState && !screenOn && !mBackgroundScanSupported => used RTC_WAKEUP Alarm
   1497          * - ConnectedState && screenOn => used delayed timer
   1498          */
   1499 
   1500         mDelayedScanCounter.incrementAndGet();
   1501         if (mScreenOn &&
   1502                 (getCurrentState() == mDisconnectedState
   1503                         || getCurrentState() == mConnectedState)) {
   1504             Bundle bundle = new Bundle();
   1505             bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
   1506             bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
   1507             bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis());
   1508             sendMessageDelayed(CMD_START_SCAN, SCAN_ALARM_SOURCE,
   1509                     mDelayedScanCounter.get(), bundle, milli);
   1510             if (DBG) logd("startDelayedScan send -> " + mDelayedScanCounter + " milli " + milli);
   1511         } else if (mBackgroundScanSupported == false
   1512                 && !mScreenOn && getCurrentState() == mDisconnectedState) {
   1513             setScanAlarm(true);
   1514             if (DBG) logd("startDelayedScan start scan alarm -> "
   1515                     + mDelayedScanCounter + " milli " + milli);
   1516         } else {
   1517             if (DBG) logd("startDelayedScan unhandled -> "
   1518                     + mDelayedScanCounter + " milli " + milli);
   1519         }
   1520     }
   1521 
   1522     private boolean setRandomMacOui() {
   1523         String oui = mContext.getResources().getString(
   1524                 R.string.config_wifi_random_mac_oui, GOOGLE_OUI);
   1525         String[] ouiParts = oui.split("-");
   1526         byte[] ouiBytes = new byte[3];
   1527         ouiBytes[0] = (byte) (Integer.parseInt(ouiParts[0], 16) & 0xFF);
   1528         ouiBytes[1] = (byte) (Integer.parseInt(ouiParts[1], 16) & 0xFF);
   1529         ouiBytes[2] = (byte) (Integer.parseInt(ouiParts[2], 16) & 0xFF);
   1530 
   1531         logd("Setting OUI to " + oui);
   1532         return mWifiNative.setScanningMacOui(ouiBytes);
   1533     }
   1534 
   1535     /**
   1536      * ******************************************************
   1537      * Methods exposed for public use
   1538      * ******************************************************
   1539      */
   1540 
   1541     public Messenger getMessenger() {
   1542         return new Messenger(getHandler());
   1543     }
   1544 
   1545     public WifiMonitor getWifiMonitor() {
   1546         return mWifiMonitor;
   1547     }
   1548 
   1549     /**
   1550      * TODO: doc
   1551      */
   1552     public boolean syncPingSupplicant(AsyncChannel channel) {
   1553         Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT);
   1554         boolean result = (resultMsg.arg1 != FAILURE);
   1555         resultMsg.recycle();
   1556         return result;
   1557     }
   1558 
   1559     public List<WifiChannel> syncGetChannelList(AsyncChannel channel) {
   1560         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ);
   1561         List<WifiChannel> list = null;
   1562         if (resultMsg.obj != null) {
   1563             list = new ArrayList<WifiChannel>();
   1564             String freqs = (String) resultMsg.obj;
   1565             String[] lines = freqs.split("\n");
   1566             for (String line : lines)
   1567                 if (line.contains("MHz")) {
   1568                     // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)"
   1569                     WifiChannel c = new WifiChannel();
   1570                     String[] prop = line.split(" ");
   1571                     if (prop.length < 5) continue;
   1572                     try {
   1573                         c.channelNum = Integer.parseInt(prop[1]);
   1574                         c.freqMHz = Integer.parseInt(prop[3]);
   1575                     } catch (NumberFormatException e) {
   1576                     }
   1577                     c.isDFS = line.contains("(DFS)");
   1578                     list.add(c);
   1579                 } else if (line.contains("Mode[B] Channels:")) {
   1580                     // B channels are the same as G channels, skipped
   1581                     break;
   1582                 }
   1583         }
   1584         resultMsg.recycle();
   1585         return (list != null && list.size() > 0) ? list : null;
   1586     }
   1587 
   1588     /**
   1589      * When settings allowing making use of untrusted networks change, trigger a scan
   1590      * so as to kick of autojoin.
   1591      */
   1592     public void startScanForUntrustedSettingChange() {
   1593         startScan(SET_ALLOW_UNTRUSTED_SOURCE, 0, null, null);
   1594     }
   1595 
   1596     /**
   1597      * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is
   1598      * given to callingUid.
   1599      *
   1600      * @param callingUid The uid initiating the wifi scan. Blame will be given here unless
   1601      *                   workSource is specified.
   1602      * @param workSource If not null, blame is given to workSource.
   1603      * @param settings   Scan settings, see {@link ScanSettings}.
   1604      */
   1605     public void startScan(int callingUid, int scanCounter,
   1606                           ScanSettings settings, WorkSource workSource) {
   1607         Bundle bundle = new Bundle();
   1608         bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
   1609         bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
   1610         bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis());
   1611         sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);
   1612     }
   1613 
   1614     // called from BroadcastListener
   1615 
   1616     /**
   1617      * Start reading new scan data
   1618      * Data comes in as:
   1619      * "scancount=5\n"
   1620      * "nextcount=5\n"
   1621      * "apcount=3\n"
   1622      * "trunc\n" (optional)
   1623      * "bssid=...\n"
   1624      * "ssid=...\n"
   1625      * "freq=...\n" (in Mhz)
   1626      * "level=...\n"
   1627      * "dist=...\n" (in cm)
   1628      * "distsd=...\n" (standard deviation, in cm)
   1629      * "===="
   1630      * "bssid=...\n"
   1631      * etc
   1632      * "===="
   1633      * "bssid=...\n"
   1634      * etc
   1635      * "%%%%"
   1636      * "apcount=2\n"
   1637      * "bssid=...\n"
   1638      * etc
   1639      * "%%%%
   1640      * etc
   1641      * "----"
   1642      */
   1643     private final static boolean DEBUG_PARSE = false;
   1644 
   1645     private long mDisconnectedTimeStamp = 0;
   1646 
   1647     public long getDisconnectedTimeMilli() {
   1648         if (getCurrentState() == mDisconnectedState
   1649                 && mDisconnectedTimeStamp != 0) {
   1650             long now_ms = System.currentTimeMillis();
   1651             return now_ms - mDisconnectedTimeStamp;
   1652         }
   1653         return 0;
   1654     }
   1655 
   1656     // Keeping track of scan requests
   1657     private long lastStartScanTimeStamp = 0;
   1658     private long lastScanDuration = 0;
   1659     // Last connect attempt is used to prevent scan requests:
   1660     //  - for a period of 10 seconds after attempting to connect
   1661     private long lastConnectAttemptTimestamp = 0;
   1662     private String lastScanFreqs = null;
   1663 
   1664     // For debugging, keep track of last message status handling
   1665     // TODO, find an equivalent mechanism as part of parent class
   1666     private static int MESSAGE_HANDLING_STATUS_PROCESSED = 2;
   1667     private static int MESSAGE_HANDLING_STATUS_OK = 1;
   1668     private static int MESSAGE_HANDLING_STATUS_UNKNOWN = 0;
   1669     private static int MESSAGE_HANDLING_STATUS_REFUSED = -1;
   1670     private static int MESSAGE_HANDLING_STATUS_FAIL = -2;
   1671     private static int MESSAGE_HANDLING_STATUS_OBSOLETE = -3;
   1672     private static int MESSAGE_HANDLING_STATUS_DEFERRED = -4;
   1673     private static int MESSAGE_HANDLING_STATUS_DISCARD = -5;
   1674     private static int MESSAGE_HANDLING_STATUS_LOOPED = -6;
   1675     private static int MESSAGE_HANDLING_STATUS_HANDLING_ERROR = -7;
   1676 
   1677     private int messageHandlingStatus = 0;
   1678 
   1679     //TODO: this is used only to track connection attempts, however the link state and packet per
   1680     //TODO: second logic should be folded into that
   1681     private boolean checkOrDeferScanAllowed(Message msg) {
   1682         long now = System.currentTimeMillis();
   1683         if (lastConnectAttemptTimestamp != 0 && (now - lastConnectAttemptTimestamp) < 10000) {
   1684             Message dmsg = Message.obtain(msg);
   1685             sendMessageDelayed(dmsg, 11000 - (now - lastConnectAttemptTimestamp));
   1686             return false;
   1687         }
   1688         return true;
   1689     }
   1690 
   1691     private int mOnTime = 0;
   1692     private int mTxTime = 0;
   1693     private int mRxTime = 0;
   1694     private int mOnTimeStartScan = 0;
   1695     private int mTxTimeStartScan = 0;
   1696     private int mRxTimeStartScan = 0;
   1697     private int mOnTimeScan = 0;
   1698     private int mTxTimeScan = 0;
   1699     private int mRxTimeScan = 0;
   1700     private int mOnTimeThisScan = 0;
   1701     private int mTxTimeThisScan = 0;
   1702     private int mRxTimeThisScan = 0;
   1703 
   1704     private int mOnTimeScreenStateChange = 0;
   1705     private int mOnTimeAtLastReport = 0;
   1706     private long lastOntimeReportTimeStamp = 0;
   1707     private long lastScreenStateChangeTimeStamp = 0;
   1708     private int mOnTimeLastReport = 0;
   1709     private int mTxTimeLastReport = 0;
   1710     private int mRxTimeLastReport = 0;
   1711 
   1712     private long lastLinkLayerStatsUpdate = 0;
   1713 
   1714     String reportOnTime() {
   1715         long now = System.currentTimeMillis();
   1716         StringBuilder sb = new StringBuilder();
   1717         // Report stats since last report
   1718         int on = mOnTime - mOnTimeLastReport;
   1719         mOnTimeLastReport = mOnTime;
   1720         int tx = mTxTime - mTxTimeLastReport;
   1721         mTxTimeLastReport = mTxTime;
   1722         int rx = mRxTime - mRxTimeLastReport;
   1723         mRxTimeLastReport = mRxTime;
   1724         int period = (int) (now - lastOntimeReportTimeStamp);
   1725         lastOntimeReportTimeStamp = now;
   1726         sb.append(String.format("[on:%d tx:%d rx:%d period:%d]", on, tx, rx, period));
   1727         // Report stats since Screen State Changed
   1728         on = mOnTime - mOnTimeScreenStateChange;
   1729         period = (int) (now - lastScreenStateChangeTimeStamp);
   1730         sb.append(String.format(" from screen [on:%d period:%d]", on, period));
   1731         return sb.toString();
   1732     }
   1733 
   1734     WifiLinkLayerStats getWifiLinkLayerStats(boolean dbg) {
   1735         WifiLinkLayerStats stats = null;
   1736         if (mWifiLinkLayerStatsSupported > 0) {
   1737             String name = "wlan0";
   1738             stats = mWifiNative.getWifiLinkLayerStats(name);
   1739             if (name != null && stats == null && mWifiLinkLayerStatsSupported > 0) {
   1740                 mWifiLinkLayerStatsSupported -= 1;
   1741             } else if (stats != null) {
   1742                 lastLinkLayerStatsUpdate = System.currentTimeMillis();
   1743                 mOnTime = stats.on_time;
   1744                 mTxTime = stats.tx_time;
   1745                 mRxTime = stats.rx_time;
   1746                 mRunningBeaconCount = stats.beacon_rx;
   1747             }
   1748         }
   1749         if (stats == null || mWifiLinkLayerStatsSupported <= 0) {
   1750             long mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
   1751             long mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
   1752             mWifiInfo.updatePacketRates(mTxPkts, mRxPkts);
   1753         } else {
   1754             mWifiInfo.updatePacketRates(stats);
   1755         }
   1756         if (useHalBasedAutoJoinOffload()) {
   1757             sendMessage(CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION);
   1758         }
   1759         return stats;
   1760     }
   1761 
   1762     void startRadioScanStats() {
   1763         WifiLinkLayerStats stats = getWifiLinkLayerStats(false);
   1764         if (stats != null) {
   1765             mOnTimeStartScan = stats.on_time;
   1766             mTxTimeStartScan = stats.tx_time;
   1767             mRxTimeStartScan = stats.rx_time;
   1768             mOnTime = stats.on_time;
   1769             mTxTime = stats.tx_time;
   1770             mRxTime = stats.rx_time;
   1771         }
   1772     }
   1773 
   1774     void closeRadioScanStats() {
   1775         WifiLinkLayerStats stats = getWifiLinkLayerStats(false);
   1776         if (stats != null) {
   1777             mOnTimeThisScan = stats.on_time - mOnTimeStartScan;
   1778             mTxTimeThisScan = stats.tx_time - mTxTimeStartScan;
   1779             mRxTimeThisScan = stats.rx_time - mRxTimeStartScan;
   1780             mOnTimeScan += mOnTimeThisScan;
   1781             mTxTimeScan += mTxTimeThisScan;
   1782             mRxTimeScan += mRxTimeThisScan;
   1783         }
   1784     }
   1785 
   1786     // If workSource is not null, blame is given to it, otherwise blame is given to callingUid.
   1787     private void noteScanStart(int callingUid, WorkSource workSource) {
   1788         long now = System.currentTimeMillis();
   1789         lastStartScanTimeStamp = now;
   1790         lastScanDuration = 0;
   1791         if (DBG) {
   1792             String ts = String.format("[%,d ms]", now);
   1793             if (workSource != null) {
   1794                 if (DBG) logd(ts + " noteScanStart" + workSource.toString()
   1795                         + " uid " + Integer.toString(callingUid));
   1796             } else {
   1797                 if (DBG) logd(ts + " noteScanstart no scan source"
   1798                         + " uid " + Integer.toString(callingUid));
   1799             }
   1800         }
   1801         startRadioScanStats();
   1802         if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE
   1803                 && callingUid != SCAN_ALARM_SOURCE)
   1804                 || workSource != null)) {
   1805             mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid);
   1806 
   1807             WorkSource batteryWorkSource = mScanWorkSource;
   1808             if (mScanWorkSource.size() == 1 && mScanWorkSource.get(0) < 0) {
   1809                 // WiFi uses negative UIDs to mean special things. BatteryStats don't care!
   1810                 batteryWorkSource = new WorkSource(Process.WIFI_UID);
   1811             }
   1812 
   1813             try {
   1814                 mBatteryStats.noteWifiScanStartedFromSource(batteryWorkSource);
   1815             } catch (RemoteException e) {
   1816                 log(e.toString());
   1817             }
   1818         }
   1819     }
   1820 
   1821     private void noteScanEnd() {
   1822         long now = System.currentTimeMillis();
   1823         if (lastStartScanTimeStamp != 0) {
   1824             lastScanDuration = now - lastStartScanTimeStamp;
   1825         }
   1826         lastStartScanTimeStamp = 0;
   1827         if (DBG) {
   1828             String ts = String.format("[%,d ms]", now);
   1829             if (mScanWorkSource != null)
   1830                 logd(ts + " noteScanEnd " + mScanWorkSource.toString()
   1831                         + " onTime=" + mOnTimeThisScan);
   1832             else
   1833                 logd(ts + " noteScanEnd no scan source"
   1834                         + " onTime=" + mOnTimeThisScan);
   1835         }
   1836         if (mScanWorkSource != null) {
   1837             try {
   1838                 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource);
   1839             } catch (RemoteException e) {
   1840                 log(e.toString());
   1841             } finally {
   1842                 mScanWorkSource = null;
   1843             }
   1844         }
   1845     }
   1846 
   1847     private void handleScanRequest(int type, Message message) {
   1848         ScanSettings settings = null;
   1849         WorkSource workSource = null;
   1850 
   1851         // unbundle parameters
   1852         Bundle bundle = (Bundle) message.obj;
   1853 
   1854         if (bundle != null) {
   1855             settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING);
   1856             workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE);
   1857         }
   1858 
   1859         // parse scan settings
   1860         String freqs = null;
   1861         if (settings != null && settings.channelSet != null) {
   1862             StringBuilder sb = new StringBuilder();
   1863             boolean first = true;
   1864             for (WifiChannel channel : settings.channelSet) {
   1865                 if (!first) sb.append(',');
   1866                 else first = false;
   1867                 sb.append(channel.freqMHz);
   1868             }
   1869             freqs = sb.toString();
   1870         }
   1871 
   1872         // call wifi native to start the scan
   1873         if (startScanNative(type, freqs)) {
   1874             // only count battery consumption if scan request is accepted
   1875             noteScanStart(message.arg1, workSource);
   1876             // a full scan covers everything, clearing scan request buffer
   1877             if (freqs == null)
   1878                 mBufferedScanMsg.clear();
   1879             messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
   1880             if (workSource != null) {
   1881                 // External worksource was passed along the scan request,
   1882                 // hence always send a broadcast
   1883                 mSendScanResultsBroadcast = true;
   1884             }
   1885             return;
   1886         }
   1887 
   1888         // if reach here, scan request is rejected
   1889 
   1890         if (!mIsScanOngoing) {
   1891             // if rejection is NOT due to ongoing scan (e.g. bad scan parameters),
   1892 
   1893             // discard this request and pop up the next one
   1894             if (mBufferedScanMsg.size() > 0) {
   1895                 sendMessage(mBufferedScanMsg.remove());
   1896             }
   1897             messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   1898         } else if (!mIsFullScanOngoing) {
   1899             // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan,
   1900             // buffer the scan request to make sure specified channels will be scanned eventually
   1901             if (freqs == null)
   1902                 mBufferedScanMsg.clear();
   1903             if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) {
   1904                 Message msg = obtainMessage(CMD_START_SCAN,
   1905                         message.arg1, message.arg2, bundle);
   1906                 mBufferedScanMsg.add(msg);
   1907             } else {
   1908                 // if too many requests in buffer, combine them into a single full scan
   1909                 bundle = new Bundle();
   1910                 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null);
   1911                 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
   1912                 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle);
   1913                 mBufferedScanMsg.clear();
   1914                 mBufferedScanMsg.add(msg);
   1915             }
   1916             messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED;
   1917         } else {
   1918             // mIsScanOngoing and mIsFullScanOngoing
   1919             messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   1920         }
   1921     }
   1922 
   1923 
   1924     /**
   1925      * return true iff scan request is accepted
   1926      */
   1927     private boolean startScanNative(int type, String freqs) {
   1928         if (mWifiNative.scan(type, freqs)) {
   1929             mIsScanOngoing = true;
   1930             mIsFullScanOngoing = (freqs == null);
   1931             lastScanFreqs = freqs;
   1932             return true;
   1933         }
   1934         return false;
   1935     }
   1936 
   1937     /**
   1938      * TODO: doc
   1939      */
   1940     public void setSupplicantRunning(boolean enable) {
   1941         if (enable) {
   1942             sendMessage(CMD_START_SUPPLICANT);
   1943         } else {
   1944             sendMessage(CMD_STOP_SUPPLICANT);
   1945         }
   1946     }
   1947 
   1948     /**
   1949      * TODO: doc
   1950      */
   1951     public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
   1952         if (enable) {
   1953             sendMessage(CMD_START_AP, wifiConfig);
   1954         } else {
   1955             sendMessage(CMD_STOP_AP);
   1956         }
   1957     }
   1958 
   1959     public void setWifiApConfiguration(WifiConfiguration config) {
   1960         mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
   1961     }
   1962 
   1963     public WifiConfiguration syncGetWifiApConfiguration() {
   1964         Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
   1965         WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
   1966         resultMsg.recycle();
   1967         return ret;
   1968     }
   1969 
   1970     /**
   1971      * TODO: doc
   1972      */
   1973     public int syncGetWifiState() {
   1974         return mWifiState.get();
   1975     }
   1976 
   1977     /**
   1978      * TODO: doc
   1979      */
   1980     public String syncGetWifiStateByName() {
   1981         switch (mWifiState.get()) {
   1982             case WIFI_STATE_DISABLING:
   1983                 return "disabling";
   1984             case WIFI_STATE_DISABLED:
   1985                 return "disabled";
   1986             case WIFI_STATE_ENABLING:
   1987                 return "enabling";
   1988             case WIFI_STATE_ENABLED:
   1989                 return "enabled";
   1990             case WIFI_STATE_UNKNOWN:
   1991                 return "unknown state";
   1992             default:
   1993                 return "[invalid state]";
   1994         }
   1995     }
   1996 
   1997     /**
   1998      * TODO: doc
   1999      */
   2000     public int syncGetWifiApState() {
   2001         return mWifiApState.get();
   2002     }
   2003 
   2004     /**
   2005      * TODO: doc
   2006      */
   2007     public String syncGetWifiApStateByName() {
   2008         switch (mWifiApState.get()) {
   2009             case WIFI_AP_STATE_DISABLING:
   2010                 return "disabling";
   2011             case WIFI_AP_STATE_DISABLED:
   2012                 return "disabled";
   2013             case WIFI_AP_STATE_ENABLING:
   2014                 return "enabling";
   2015             case WIFI_AP_STATE_ENABLED:
   2016                 return "enabled";
   2017             case WIFI_AP_STATE_FAILED:
   2018                 return "failed";
   2019             default:
   2020                 return "[invalid state]";
   2021         }
   2022     }
   2023 
   2024     /**
   2025      * Get status information for the current connection, if any.
   2026      *
   2027      * @return a {@link WifiInfo} object containing information about the current connection
   2028      */
   2029     public WifiInfo syncRequestConnectionInfo() {
   2030         return getWiFiInfoForUid(Binder.getCallingUid());
   2031     }
   2032 
   2033     public DhcpResults syncGetDhcpResults() {
   2034         synchronized (mDhcpResultsLock) {
   2035             return new DhcpResults(mDhcpResults);
   2036         }
   2037     }
   2038 
   2039     /**
   2040      * TODO: doc
   2041      */
   2042     public void setDriverStart(boolean enable) {
   2043         if (enable) {
   2044             sendMessage(CMD_START_DRIVER);
   2045         } else {
   2046             sendMessage(CMD_STOP_DRIVER);
   2047         }
   2048     }
   2049 
   2050     /**
   2051      * TODO: doc
   2052      */
   2053     public void setOperationalMode(int mode) {
   2054         if (DBG) log("setting operational mode to " + String.valueOf(mode));
   2055         sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
   2056     }
   2057 
   2058     /**
   2059      * TODO: doc
   2060      */
   2061     public List<ScanResult> syncGetScanResultsList() {
   2062         synchronized (mScanResultCache) {
   2063             List<ScanResult> scanList = new ArrayList<ScanResult>();
   2064             for (ScanDetail result : mScanResults) {
   2065                 scanList.add(new ScanResult(result.getScanResult()));
   2066             }
   2067             return scanList;
   2068         }
   2069     }
   2070 
   2071     public void disableEphemeralNetwork(String SSID) {
   2072         if (SSID != null) {
   2073             sendMessage(CMD_DISABLE_EPHEMERAL_NETWORK, SSID);
   2074         }
   2075     }
   2076 
   2077     /**
   2078      * Get unsynchronized pointer to scan result list
   2079      * Can be called only from AutoJoinController which runs in the WifiStateMachine context
   2080      */
   2081     public List<ScanDetail> getScanResultsListNoCopyUnsync() {
   2082         return mScanResults;
   2083     }
   2084 
   2085     /**
   2086      * Disconnect from Access Point
   2087      */
   2088     public void disconnectCommand() {
   2089         sendMessage(CMD_DISCONNECT);
   2090     }
   2091 
   2092     public void disconnectCommand(int uid, int reason) {
   2093         sendMessage(CMD_DISCONNECT, uid, reason);
   2094     }
   2095 
   2096     /**
   2097      * Initiate a reconnection to AP
   2098      */
   2099     public void reconnectCommand() {
   2100         sendMessage(CMD_RECONNECT);
   2101     }
   2102 
   2103     /**
   2104      * Initiate a re-association to AP
   2105      */
   2106     public void reassociateCommand() {
   2107         sendMessage(CMD_REASSOCIATE);
   2108     }
   2109 
   2110     /**
   2111      * Reload networks and then reconnect; helps load correct data for TLS networks
   2112      */
   2113 
   2114     public void reloadTlsNetworksAndReconnect() {
   2115         sendMessage(CMD_RELOAD_TLS_AND_RECONNECT);
   2116     }
   2117 
   2118     /**
   2119      * Add a network synchronously
   2120      *
   2121      * @return network id of the new network
   2122      */
   2123     public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) {
   2124         Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config);
   2125         int result = resultMsg.arg1;
   2126         resultMsg.recycle();
   2127         return result;
   2128     }
   2129 
   2130     /**
   2131      * Get configured networks synchronously
   2132      *
   2133      * @param channel
   2134      * @return
   2135      */
   2136 
   2137     public List<WifiConfiguration> syncGetConfiguredNetworks(int uuid, AsyncChannel channel) {
   2138         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS, uuid);
   2139         List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
   2140         resultMsg.recycle();
   2141         return result;
   2142     }
   2143 
   2144     public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) {
   2145         Message resultMsg = channel.sendMessageSynchronously(
   2146                 CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS);
   2147         List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
   2148         resultMsg.recycle();
   2149         return result;
   2150     }
   2151 
   2152     public WifiConfiguration syncGetMatchingWifiConfig(ScanResult scanResult, AsyncChannel channel) {
   2153         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_MATCHING_CONFIG, scanResult);
   2154         return (WifiConfiguration) resultMsg.obj;
   2155     }
   2156 
   2157     /**
   2158      * Get connection statistics synchronously
   2159      *
   2160      * @param channel
   2161      * @return
   2162      */
   2163 
   2164     public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) {
   2165         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS);
   2166         WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj;
   2167         resultMsg.recycle();
   2168         return result;
   2169     }
   2170 
   2171     /**
   2172      * Get adaptors synchronously
   2173      */
   2174 
   2175     public int syncGetSupportedFeatures(AsyncChannel channel) {
   2176         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_SUPPORTED_FEATURES);
   2177         int supportedFeatureSet = resultMsg.arg1;
   2178         resultMsg.recycle();
   2179         return supportedFeatureSet;
   2180     }
   2181 
   2182     /**
   2183      * Get link layers stats for adapter synchronously
   2184      */
   2185     public WifiLinkLayerStats syncGetLinkLayerStats(AsyncChannel channel) {
   2186         Message resultMsg = channel.sendMessageSynchronously(CMD_GET_LINK_LAYER_STATS);
   2187         WifiLinkLayerStats result = (WifiLinkLayerStats) resultMsg.obj;
   2188         resultMsg.recycle();
   2189         return result;
   2190     }
   2191 
   2192     /**
   2193      * Delete a network
   2194      *
   2195      * @param networkId id of the network to be removed
   2196      */
   2197     public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) {
   2198         Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId);
   2199         boolean result = (resultMsg.arg1 != FAILURE);
   2200         resultMsg.recycle();
   2201         return result;
   2202     }
   2203 
   2204     /**
   2205      * Enable a network
   2206      *
   2207      * @param netId         network id of the network
   2208      * @param disableOthers true, if all other networks have to be disabled
   2209      * @return {@code true} if the operation succeeds, {@code false} otherwise
   2210      */
   2211     public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) {
   2212         Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId,
   2213                 disableOthers ? 1 : 0);
   2214         boolean result = (resultMsg.arg1 != FAILURE);
   2215         resultMsg.recycle();
   2216         return result;
   2217     }
   2218 
   2219     /**
   2220      * Disable a network
   2221      *
   2222      * @param netId network id of the network
   2223      * @return {@code true} if the operation succeeds, {@code false} otherwise
   2224      */
   2225     public boolean syncDisableNetwork(AsyncChannel channel, int netId) {
   2226         Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId);
   2227         boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED);
   2228         resultMsg.recycle();
   2229         return result;
   2230     }
   2231 
   2232     /**
   2233      * Retrieves a WPS-NFC configuration token for the specified network
   2234      *
   2235      * @return a hex string representation of the WPS-NFC configuration token
   2236      */
   2237     public String syncGetWpsNfcConfigurationToken(int netId) {
   2238         return mWifiNative.getNfcWpsConfigurationToken(netId);
   2239     }
   2240 
   2241     void enableBackgroundScan(boolean enable) {
   2242         if (enable) {
   2243             mWifiConfigStore.enableAllNetworks();
   2244         }
   2245         boolean ret = mWifiNative.enableBackgroundScan(enable);
   2246         if (ret) {
   2247             mLegacyPnoEnabled = enable;
   2248         } else {
   2249             Log.e(TAG, " Fail to set up pno, want " + enable + " now " + mLegacyPnoEnabled);
   2250         }
   2251     }
   2252 
   2253     /**
   2254      * Blacklist a BSSID. This will avoid the AP if there are
   2255      * alternate APs to connect
   2256      *
   2257      * @param bssid BSSID of the network
   2258      */
   2259     public void addToBlacklist(String bssid) {
   2260         sendMessage(CMD_BLACKLIST_NETWORK, bssid);
   2261     }
   2262 
   2263     /**
   2264      * Clear the blacklist list
   2265      */
   2266     public void clearBlacklist() {
   2267         sendMessage(CMD_CLEAR_BLACKLIST);
   2268     }
   2269 
   2270     public void enableRssiPolling(boolean enabled) {
   2271         sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
   2272     }
   2273 
   2274     public void enableAllNetworks() {
   2275         sendMessage(CMD_ENABLE_ALL_NETWORKS);
   2276     }
   2277 
   2278     /**
   2279      * Start filtering Multicast v4 packets
   2280      */
   2281     public void startFilteringMulticastV4Packets() {
   2282         mFilteringMulticastV4Packets.set(true);
   2283         sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0);
   2284     }
   2285 
   2286     /**
   2287      * Stop filtering Multicast v4 packets
   2288      */
   2289     public void stopFilteringMulticastV4Packets() {
   2290         mFilteringMulticastV4Packets.set(false);
   2291         sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0);
   2292     }
   2293 
   2294     /**
   2295      * Start filtering Multicast v4 packets
   2296      */
   2297     public void startFilteringMulticastV6Packets() {
   2298         sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0);
   2299     }
   2300 
   2301     /**
   2302      * Stop filtering Multicast v4 packets
   2303      */
   2304     public void stopFilteringMulticastV6Packets() {
   2305         sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0);
   2306     }
   2307 
   2308     /**
   2309      * Set high performance mode of operation.
   2310      * Enabling would set active power mode and disable suspend optimizations;
   2311      * disabling would set auto power mode and enable suspend optimizations
   2312      *
   2313      * @param enable true if enable, false otherwise
   2314      */
   2315     public void setHighPerfModeEnabled(boolean enable) {
   2316         sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);
   2317     }
   2318 
   2319     /**
   2320      * Set the country code
   2321      *
   2322      * @param countryCode following ISO 3166 format
   2323      * @param persist     {@code true} if the setting should be remembered.
   2324      */
   2325     public synchronized void setCountryCode(String countryCode, boolean persist) {
   2326         // If it's a good country code, apply after the current
   2327         // wifi connection is terminated; ignore resetting of code
   2328         // for now (it is unclear what the chipset should do when
   2329         // country code is reset)
   2330 
   2331         if (TextUtils.isEmpty(countryCode)) {
   2332             log("Ignoring resetting of country code");
   2333         } else {
   2334             // if mCountryCodeSequence == 0, it is the first time to set country code, always set
   2335             // else only when the new country code is different from the current one to set
   2336             int countryCodeSequence = mCountryCodeSequence.get();
   2337             if (countryCodeSequence == 0 || countryCode.equals(mSetCountryCode) == false) {
   2338 
   2339                 countryCodeSequence = mCountryCodeSequence.incrementAndGet();
   2340                 mSetCountryCode = countryCode;
   2341                 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0,
   2342                         countryCode);
   2343             }
   2344 
   2345             if (persist) {
   2346                 Settings.Global.putString(mContext.getContentResolver(),
   2347                         Settings.Global.WIFI_COUNTRY_CODE,
   2348                         countryCode);
   2349             }
   2350         }
   2351     }
   2352 
   2353     /**
   2354      * Get Network object of current wifi network
   2355      * @return Network object of current wifi network
   2356      */
   2357     public Network getCurrentNetwork() {
   2358         if (mNetworkAgent != null) {
   2359             return new Network(mNetworkAgent.netId);
   2360         } else {
   2361             return null;
   2362         }
   2363     }
   2364 
   2365     /**
   2366      * Get the country code
   2367      *
   2368      * @param countryCode following ISO 3166 format
   2369      */
   2370     public String getCountryCode() {
   2371         return mSetCountryCode;
   2372     }
   2373 
   2374 
   2375     /**
   2376      * Set the operational frequency band
   2377      *
   2378      * @param band
   2379      * @param persist {@code true} if the setting should be remembered.
   2380      */
   2381     public void setFrequencyBand(int band, boolean persist) {
   2382         if (persist) {
   2383             Settings.Global.putInt(mContext.getContentResolver(),
   2384                     Settings.Global.WIFI_FREQUENCY_BAND,
   2385                     band);
   2386         }
   2387         sendMessage(CMD_SET_FREQUENCY_BAND, band, 0);
   2388     }
   2389 
   2390     /**
   2391      * Enable TDLS for a specific MAC address
   2392      */
   2393     public void enableTdls(String remoteMacAddress, boolean enable) {
   2394         int enabler = enable ? 1 : 0;
   2395         sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress);
   2396     }
   2397 
   2398     /**
   2399      * Returns the operational frequency band
   2400      */
   2401     public int getFrequencyBand() {
   2402         return mFrequencyBand.get();
   2403     }
   2404 
   2405     /**
   2406      * Returns the wifi configuration file
   2407      */
   2408     public String getConfigFile() {
   2409         return mWifiConfigStore.getConfigFile();
   2410     }
   2411 
   2412     /**
   2413      * Send a message indicating bluetooth adapter connection state changed
   2414      */
   2415     public void sendBluetoothAdapterStateChange(int state) {
   2416         sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0);
   2417     }
   2418 
   2419     /**
   2420      * Send a message indicating a package has been uninstalled.
   2421      */
   2422     public void removeAppConfigs(String packageName, int uid) {
   2423         // Build partial AppInfo manually - package may not exist in database any more
   2424         ApplicationInfo ai = new ApplicationInfo();
   2425         ai.packageName = packageName;
   2426         ai.uid = uid;
   2427         sendMessage(CMD_REMOVE_APP_CONFIGURATIONS, ai);
   2428     }
   2429 
   2430     /**
   2431      * Send a message indicating a user has been removed.
   2432      */
   2433     public void removeUserConfigs(int userId) {
   2434         sendMessage(CMD_REMOVE_USER_CONFIGURATIONS, userId);
   2435     }
   2436 
   2437     /**
   2438      * Save configuration on supplicant
   2439      *
   2440      * @return {@code true} if the operation succeeds, {@code false} otherwise
   2441      * <p/>
   2442      * TODO: deprecate this
   2443      */
   2444     public boolean syncSaveConfig(AsyncChannel channel) {
   2445         Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
   2446         boolean result = (resultMsg.arg1 != FAILURE);
   2447         resultMsg.recycle();
   2448         return result;
   2449     }
   2450 
   2451     public void updateBatteryWorkSource(WorkSource newSource) {
   2452         synchronized (mRunningWifiUids) {
   2453             try {
   2454                 if (newSource != null) {
   2455                     mRunningWifiUids.set(newSource);
   2456                 }
   2457                 if (mIsRunning) {
   2458                     if (mReportedRunning) {
   2459                         // If the work source has changed since last time, need
   2460                         // to remove old work from battery stats.
   2461                         if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
   2462                             mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
   2463                                     mRunningWifiUids);
   2464                             mLastRunningWifiUids.set(mRunningWifiUids);
   2465                         }
   2466                     } else {
   2467                         // Now being started, report it.
   2468                         mBatteryStats.noteWifiRunning(mRunningWifiUids);
   2469                         mLastRunningWifiUids.set(mRunningWifiUids);
   2470                         mReportedRunning = true;
   2471                     }
   2472                 } else {
   2473                     if (mReportedRunning) {
   2474                         // Last reported we were running, time to stop.
   2475                         mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
   2476                         mLastRunningWifiUids.clear();
   2477                         mReportedRunning = false;
   2478                     }
   2479                 }
   2480                 mWakeLock.setWorkSource(newSource);
   2481             } catch (RemoteException ignore) {
   2482             }
   2483         }
   2484     }
   2485 
   2486     @Override
   2487     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2488         super.dump(fd, pw, args);
   2489         mSupplicantStateTracker.dump(fd, pw, args);
   2490         pw.println("mLinkProperties " + mLinkProperties);
   2491         pw.println("mWifiInfo " + mWifiInfo);
   2492         pw.println("mDhcpResults " + mDhcpResults);
   2493         pw.println("mNetworkInfo " + mNetworkInfo);
   2494         pw.println("mLastSignalLevel " + mLastSignalLevel);
   2495         pw.println("mLastBssid " + mLastBssid);
   2496         pw.println("mLastNetworkId " + mLastNetworkId);
   2497         pw.println("mOperationalMode " + mOperationalMode);
   2498         pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
   2499         pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
   2500         pw.println("Supplicant status " + mWifiNative.status(true));
   2501         pw.println("mLegacyPnoEnabled " + mLegacyPnoEnabled);
   2502         pw.println("mSetCountryCode " + mSetCountryCode);
   2503         pw.println("mDriverSetCountryCode " + mDriverSetCountryCode);
   2504         pw.println("mConnectedModeGScanOffloadStarted " + mConnectedModeGScanOffloadStarted);
   2505         pw.println("mGScanPeriodMilli " + mGScanPeriodMilli);
   2506         if (mWhiteListedSsids != null && mWhiteListedSsids.length > 0) {
   2507             pw.println("SSID whitelist :" );
   2508             for (int i=0; i < mWhiteListedSsids.length; i++) {
   2509                 pw.println("       " + mWhiteListedSsids[i]);
   2510             }
   2511         }
   2512         mNetworkFactory.dump(fd, pw, args);
   2513         mUntrustedNetworkFactory.dump(fd, pw, args);
   2514         pw.println();
   2515         mWifiConfigStore.dump(fd, pw, args);
   2516         pw.println();
   2517         mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_USER_ACTION);
   2518         mWifiLogger.dump(fd, pw, args);
   2519     }
   2520 
   2521     /**
   2522      * ******************************************************
   2523      * Internal private functions
   2524      * ******************************************************
   2525      */
   2526 
   2527     private void logStateAndMessage(Message message, String state) {
   2528         messageHandlingStatus = 0;
   2529         if (mLogMessages) {
   2530             //long now = SystemClock.elapsedRealtimeNanos();
   2531             //String ts = String.format("[%,d us]", now/1000);
   2532 
   2533             logd(" " + state + " " + getLogRecString(message));
   2534         }
   2535     }
   2536 
   2537     /**
   2538      * helper, prints the milli time since boot wi and w/o suspended time
   2539      */
   2540     String printTime() {
   2541         StringBuilder sb = new StringBuilder();
   2542         sb.append(" rt=").append(SystemClock.uptimeMillis());
   2543         sb.append("/").append(SystemClock.elapsedRealtime());
   2544         return sb.toString();
   2545     }
   2546 
   2547     /**
   2548      * Return the additional string to be logged by LogRec, default
   2549      *
   2550      * @param msg that was processed
   2551      * @return information to be logged as a String
   2552      */
   2553     protected String getLogRecString(Message msg) {
   2554         WifiConfiguration config;
   2555         Long now;
   2556         String report;
   2557         String key;
   2558         StringBuilder sb = new StringBuilder();
   2559         if (mScreenOn) {
   2560             sb.append("!");
   2561         }
   2562         if (messageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) {
   2563             sb.append("(").append(messageHandlingStatus).append(")");
   2564         }
   2565         sb.append(smToString(msg));
   2566         if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) {
   2567             sb.append(" uid=" + msg.sendingUid);
   2568         }
   2569         sb.append(" ").append(printTime());
   2570         switch (msg.what) {
   2571             case CMD_STARTED_GSCAN_DBG:
   2572             case CMD_STARTED_PNO_DBG:
   2573                 sb.append(" ");
   2574                 sb.append(Integer.toString(msg.arg1));
   2575                 sb.append(" ");
   2576                 sb.append(Integer.toString(msg.arg2));
   2577                 if (msg.obj != null) {
   2578                     sb.append(" " + (String)msg.obj);
   2579                 }
   2580                 break;
   2581             case CMD_RESTART_AUTOJOIN_OFFLOAD:
   2582                 sb.append(" ");
   2583                 sb.append(Integer.toString(msg.arg1));
   2584                 sb.append(" ");
   2585                 sb.append(Integer.toString(msg.arg2));
   2586                 sb.append("/").append(Integer.toString(mRestartAutoJoinOffloadCounter));
   2587                 if (msg.obj != null) {
   2588                     sb.append(" " + (String)msg.obj);
   2589                 }
   2590                 break;
   2591             case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
   2592                 sb.append(" ");
   2593                 sb.append(Integer.toString(msg.arg1));
   2594                 sb.append(" ");
   2595                 sb.append(Integer.toString(msg.arg2));
   2596                 sb.append(" halAllowed=").append(useHalBasedAutoJoinOffload());
   2597                 sb.append(" scanAllowed=").append(allowFullBandScanAndAssociated());
   2598                 sb.append(" autojoinAllowed=");
   2599                 sb.append(mWifiConfigStore.enableAutoJoinWhenAssociated.get());
   2600                 sb.append(" withTraffic=").append(getAllowScansWithTraffic());
   2601                 sb.append(" tx=").append(mWifiInfo.txSuccessRate);
   2602                 sb.append("/").append(mWifiConfigStore.maxTxPacketForFullScans);
   2603                 sb.append(" rx=").append(mWifiInfo.rxSuccessRate);
   2604                 sb.append("/").append(mWifiConfigStore.maxRxPacketForFullScans);
   2605                 sb.append(" -> ").append(mConnectedModeGScanOffloadStarted);
   2606                 break;
   2607             case CMD_PNO_NETWORK_FOUND:
   2608                 sb.append(" ");
   2609                 sb.append(Integer.toString(msg.arg1));
   2610                 sb.append(" ");
   2611                 sb.append(Integer.toString(msg.arg2));
   2612                 if (msg.obj != null) {
   2613                     ScanResult[] results = (ScanResult[])msg.obj;
   2614                     for (int i = 0; i < results.length; i++) {
   2615                        sb.append(" ").append(results[i].SSID).append(" ");
   2616                        sb.append(results[i].frequency);
   2617                        sb.append(" ").append(results[i].level);
   2618                     }
   2619                 }
   2620                 break;
   2621             case CMD_START_SCAN:
   2622                 now = System.currentTimeMillis();
   2623                 sb.append(" ");
   2624                 sb.append(Integer.toString(msg.arg1));
   2625                 sb.append(" ");
   2626                 sb.append(Integer.toString(msg.arg2));
   2627                 sb.append(" ic=");
   2628                 sb.append(Integer.toString(sScanAlarmIntentCount));
   2629                 if (msg.obj != null) {
   2630                     Bundle bundle = (Bundle) msg.obj;
   2631                     Long request = bundle.getLong(SCAN_REQUEST_TIME, 0);
   2632                     if (request != 0) {
   2633                         sb.append(" proc(ms):").append(now - request);
   2634                     }
   2635                 }
   2636                 if (mIsScanOngoing) sb.append(" onGoing");
   2637                 if (mIsFullScanOngoing) sb.append(" full");
   2638                 if (lastStartScanTimeStamp != 0) {
   2639                     sb.append(" started:").append(lastStartScanTimeStamp);
   2640                     sb.append(",").append(now - lastStartScanTimeStamp);
   2641                 }
   2642                 if (lastScanDuration != 0) {
   2643                     sb.append(" dur:").append(lastScanDuration);
   2644                 }
   2645                 sb.append(" cnt=").append(mDelayedScanCounter);
   2646                 sb.append(" rssi=").append(mWifiInfo.getRssi());
   2647                 sb.append(" f=").append(mWifiInfo.getFrequency());
   2648                 sb.append(" sc=").append(mWifiInfo.score);
   2649                 sb.append(" link=").append(mWifiInfo.getLinkSpeed());
   2650                 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
   2651                 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
   2652                 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
   2653                 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
   2654                 if (lastScanFreqs != null) {
   2655                     sb.append(" list=").append(lastScanFreqs);
   2656                 } else {
   2657                     sb.append(" fiv=").append(fullBandConnectedTimeIntervalMilli);
   2658                 }
   2659                 report = reportOnTime();
   2660                 if (report != null) {
   2661                     sb.append(" ").append(report);
   2662                 }
   2663                 break;
   2664             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   2665                 sb.append(" ");
   2666                 sb.append(Integer.toString(msg.arg1));
   2667                 sb.append(" ");
   2668                 sb.append(Integer.toString(msg.arg2));
   2669                 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
   2670                 if (stateChangeResult != null) {
   2671                     sb.append(stateChangeResult.toString());
   2672                 }
   2673                 break;
   2674             case WifiManager.SAVE_NETWORK:
   2675             case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
   2676                 sb.append(" ");
   2677                 sb.append(Integer.toString(msg.arg1));
   2678                 sb.append(" ");
   2679                 sb.append(Integer.toString(msg.arg2));
   2680                 if (lastSavedConfigurationAttempt != null) {
   2681                     sb.append(" ").append(lastSavedConfigurationAttempt.configKey());
   2682                     sb.append(" nid=").append(lastSavedConfigurationAttempt.networkId);
   2683                     if (lastSavedConfigurationAttempt.hiddenSSID) {
   2684                         sb.append(" hidden");
   2685                     }
   2686                     if (lastSavedConfigurationAttempt.preSharedKey != null
   2687                             && !lastSavedConfigurationAttempt.preSharedKey.equals("*")) {
   2688                         sb.append(" hasPSK");
   2689                     }
   2690                     if (lastSavedConfigurationAttempt.ephemeral) {
   2691                         sb.append(" ephemeral");
   2692                     }
   2693                     if (lastSavedConfigurationAttempt.selfAdded) {
   2694                         sb.append(" selfAdded");
   2695                     }
   2696                     sb.append(" cuid=").append(lastSavedConfigurationAttempt.creatorUid);
   2697                     sb.append(" suid=").append(lastSavedConfigurationAttempt.lastUpdateUid);
   2698                 }
   2699                 break;
   2700             case WifiManager.FORGET_NETWORK:
   2701                 sb.append(" ");
   2702                 sb.append(Integer.toString(msg.arg1));
   2703                 sb.append(" ");
   2704                 sb.append(Integer.toString(msg.arg2));
   2705                 if (lastForgetConfigurationAttempt != null) {
   2706                     sb.append(" ").append(lastForgetConfigurationAttempt.configKey());
   2707                     sb.append(" nid=").append(lastForgetConfigurationAttempt.networkId);
   2708                     if (lastForgetConfigurationAttempt.hiddenSSID) {
   2709                         sb.append(" hidden");
   2710                     }
   2711                     if (lastForgetConfigurationAttempt.preSharedKey != null) {
   2712                         sb.append(" hasPSK");
   2713                     }
   2714                     if (lastForgetConfigurationAttempt.ephemeral) {
   2715                         sb.append(" ephemeral");
   2716                     }
   2717                     if (lastForgetConfigurationAttempt.selfAdded) {
   2718                         sb.append(" selfAdded");
   2719                     }
   2720                     sb.append(" cuid=").append(lastForgetConfigurationAttempt.creatorUid);
   2721                     sb.append(" suid=").append(lastForgetConfigurationAttempt.lastUpdateUid);
   2722                     sb.append(" ajst=").append(lastForgetConfigurationAttempt.autoJoinStatus);
   2723                 }
   2724                 break;
   2725             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   2726                 sb.append(" ");
   2727                 sb.append(Integer.toString(msg.arg1));
   2728                 sb.append(" ");
   2729                 sb.append(Integer.toString(msg.arg2));
   2730                 String bssid = (String) msg.obj;
   2731                 if (bssid != null && bssid.length() > 0) {
   2732                     sb.append(" ");
   2733                     sb.append(bssid);
   2734                 }
   2735                 sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID));
   2736                 break;
   2737             case WifiMonitor.SCAN_RESULTS_EVENT:
   2738                 sb.append(" ");
   2739                 sb.append(Integer.toString(msg.arg1));
   2740                 sb.append(" ");
   2741                 sb.append(Integer.toString(msg.arg2));
   2742                 if (mScanResults != null) {
   2743                     sb.append(" found=");
   2744                     sb.append(mScanResults.size());
   2745                 }
   2746                 sb.append(" known=").append(mNumScanResultsKnown);
   2747                 sb.append(" got=").append(mNumScanResultsReturned);
   2748                 if (lastScanDuration != 0) {
   2749                     sb.append(" dur:").append(lastScanDuration);
   2750                 }
   2751                 if (mOnTime != 0) {
   2752                     sb.append(" on:").append(mOnTimeThisScan).append(",").append(mOnTimeScan);
   2753                     sb.append(",").append(mOnTime);
   2754                 }
   2755                 if (mTxTime != 0) {
   2756                     sb.append(" tx:").append(mTxTimeThisScan).append(",").append(mTxTimeScan);
   2757                     sb.append(",").append(mTxTime);
   2758                 }
   2759                 if (mRxTime != 0) {
   2760                     sb.append(" rx:").append(mRxTimeThisScan).append(",").append(mRxTimeScan);
   2761                     sb.append(",").append(mRxTime);
   2762                 }
   2763                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
   2764                 sb.append(String.format(" con=%d", mConnectionRequests));
   2765                 key = mWifiConfigStore.getLastSelectedConfiguration();
   2766                 if (key != null) {
   2767                     sb.append(" last=").append(key);
   2768                 }
   2769                 break;
   2770             case WifiMonitor.SCAN_FAILED_EVENT:
   2771                 break;
   2772             case WifiMonitor.NETWORK_CONNECTION_EVENT:
   2773                 sb.append(" ");
   2774                 sb.append(Integer.toString(msg.arg1));
   2775                 sb.append(" ");
   2776                 sb.append(Integer.toString(msg.arg2));
   2777                 sb.append(" ").append(mLastBssid);
   2778                 sb.append(" nid=").append(mLastNetworkId);
   2779                 config = getCurrentWifiConfiguration();
   2780                 if (config != null) {
   2781                     sb.append(" ").append(config.configKey());
   2782                 }
   2783                 key = mWifiConfigStore.getLastSelectedConfiguration();
   2784                 if (key != null) {
   2785                     sb.append(" last=").append(key);
   2786                 }
   2787                 break;
   2788             case CMD_TARGET_BSSID:
   2789             case CMD_ASSOCIATED_BSSID:
   2790                 sb.append(" ");
   2791                 sb.append(Integer.toString(msg.arg1));
   2792                 sb.append(" ");
   2793                 sb.append(Integer.toString(msg.arg2));
   2794                 if (msg.obj != null) {
   2795                     sb.append(" BSSID=").append((String) msg.obj);
   2796                 }
   2797                 if (mTargetRoamBSSID != null) {
   2798                     sb.append(" Target=").append(mTargetRoamBSSID);
   2799                 }
   2800                 sb.append(" roam=").append(Integer.toString(mAutoRoaming));
   2801                 break;
   2802             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   2803                 if (msg.obj != null) {
   2804                     sb.append(" ").append((String) msg.obj);
   2805                 }
   2806                 sb.append(" nid=").append(msg.arg1);
   2807                 sb.append(" reason=").append(msg.arg2);
   2808                 if (mLastBssid != null) {
   2809                     sb.append(" lastbssid=").append(mLastBssid);
   2810                 }
   2811                 if (mWifiInfo.getFrequency() != -1) {
   2812                     sb.append(" freq=").append(mWifiInfo.getFrequency());
   2813                     sb.append(" rssi=").append(mWifiInfo.getRssi());
   2814                 }
   2815                 if (linkDebouncing) {
   2816                     sb.append(" debounce");
   2817                 }
   2818                 break;
   2819             case WifiMonitor.SSID_TEMP_DISABLED:
   2820             case WifiMonitor.SSID_REENABLED:
   2821                 sb.append(" nid=").append(msg.arg1);
   2822                 if (msg.obj != null) {
   2823                     sb.append(" ").append((String) msg.obj);
   2824                 }
   2825                 config = getCurrentWifiConfiguration();
   2826                 if (config != null) {
   2827                     sb.append(" cur=").append(config.configKey());
   2828                     sb.append(" ajst=").append(config.autoJoinStatus);
   2829                     if (config.selfAdded) {
   2830                         sb.append(" selfAdded");
   2831                     }
   2832                     if (config.status != 0) {
   2833                         sb.append(" st=").append(config.status);
   2834                         sb.append(" rs=").append(config.disableReason);
   2835                     }
   2836                     if (config.lastConnected != 0) {
   2837                         now = System.currentTimeMillis();
   2838                         sb.append(" lastconn=").append(now - config.lastConnected).append("(ms)");
   2839                     }
   2840                     if (mLastBssid != null) {
   2841                         sb.append(" lastbssid=").append(mLastBssid);
   2842                     }
   2843                     if (mWifiInfo.getFrequency() != -1) {
   2844                         sb.append(" freq=").append(mWifiInfo.getFrequency());
   2845                         sb.append(" rssi=").append(mWifiInfo.getRssi());
   2846                         sb.append(" bssid=").append(mWifiInfo.getBSSID());
   2847                     }
   2848                 }
   2849                 break;
   2850             case CMD_RSSI_POLL:
   2851             case CMD_UNWANTED_NETWORK:
   2852             case WifiManager.RSSI_PKTCNT_FETCH:
   2853                 sb.append(" ");
   2854                 sb.append(Integer.toString(msg.arg1));
   2855                 sb.append(" ");
   2856                 sb.append(Integer.toString(msg.arg2));
   2857                 if (mWifiInfo.getSSID() != null)
   2858                     if (mWifiInfo.getSSID() != null)
   2859                         sb.append(" ").append(mWifiInfo.getSSID());
   2860                 if (mWifiInfo.getBSSID() != null)
   2861                     sb.append(" ").append(mWifiInfo.getBSSID());
   2862                 sb.append(" rssi=").append(mWifiInfo.getRssi());
   2863                 sb.append(" f=").append(mWifiInfo.getFrequency());
   2864                 sb.append(" sc=").append(mWifiInfo.score);
   2865                 sb.append(" link=").append(mWifiInfo.getLinkSpeed());
   2866                 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
   2867                 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
   2868                 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
   2869                 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
   2870                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
   2871                 report = reportOnTime();
   2872                 if (report != null) {
   2873                     sb.append(" ").append(report);
   2874                 }
   2875                 if (wifiScoringReport != null) {
   2876                     sb.append(wifiScoringReport);
   2877                 }
   2878                 if (mConnectedModeGScanOffloadStarted) {
   2879                     sb.append(" offload-started periodMilli " + mGScanPeriodMilli);
   2880                 } else {
   2881                     sb.append(" offload-stopped");
   2882                 }
   2883                 break;
   2884             case CMD_AUTO_CONNECT:
   2885             case WifiManager.CONNECT_NETWORK:
   2886                 sb.append(" ");
   2887                 sb.append(Integer.toString(msg.arg1));
   2888                 sb.append(" ");
   2889                 sb.append(Integer.toString(msg.arg2));
   2890                 config = (WifiConfiguration) msg.obj;
   2891                 if (config != null) {
   2892                     sb.append(" ").append(config.configKey());
   2893                     if (config.visibility != null) {
   2894                         sb.append(" ").append(config.visibility.toString());
   2895                     }
   2896                 }
   2897                 if (mTargetRoamBSSID != null) {
   2898                     sb.append(" ").append(mTargetRoamBSSID);
   2899                 }
   2900                 sb.append(" roam=").append(Integer.toString(mAutoRoaming));
   2901                 config = getCurrentWifiConfiguration();
   2902                 if (config != null) {
   2903                     sb.append(config.configKey());
   2904                     if (config.visibility != null) {
   2905                         sb.append(" ").append(config.visibility.toString());
   2906                     }
   2907                 }
   2908                 break;
   2909             case CMD_AUTO_ROAM:
   2910                 sb.append(" ");
   2911                 sb.append(Integer.toString(msg.arg1));
   2912                 sb.append(" ");
   2913                 sb.append(Integer.toString(msg.arg2));
   2914                 ScanResult result = (ScanResult) msg.obj;
   2915                 if (result != null) {
   2916                     now = System.currentTimeMillis();
   2917                     sb.append(" bssid=").append(result.BSSID);
   2918                     sb.append(" rssi=").append(result.level);
   2919                     sb.append(" freq=").append(result.frequency);
   2920                     if (result.seen > 0 && result.seen < now) {
   2921                         sb.append(" seen=").append(now - result.seen);
   2922                     } else {
   2923                         // Somehow the timestamp for this scan result is inconsistent
   2924                         sb.append(" !seen=").append(result.seen);
   2925                     }
   2926                 }
   2927                 if (mTargetRoamBSSID != null) {
   2928                     sb.append(" ").append(mTargetRoamBSSID);
   2929                 }
   2930                 sb.append(" roam=").append(Integer.toString(mAutoRoaming));
   2931                 sb.append(" fail count=").append(Integer.toString(mRoamFailCount));
   2932                 break;
   2933             case CMD_ADD_OR_UPDATE_NETWORK:
   2934                 sb.append(" ");
   2935                 sb.append(Integer.toString(msg.arg1));
   2936                 sb.append(" ");
   2937                 sb.append(Integer.toString(msg.arg2));
   2938                 if (msg.obj != null) {
   2939                     config = (WifiConfiguration) msg.obj;
   2940                     sb.append(" ").append(config.configKey());
   2941                     sb.append(" prio=").append(config.priority);
   2942                     sb.append(" status=").append(config.status);
   2943                     if (config.BSSID != null) {
   2944                         sb.append(" ").append(config.BSSID);
   2945                     }
   2946                     WifiConfiguration curConfig = getCurrentWifiConfiguration();
   2947                     if (curConfig != null) {
   2948                         if (curConfig.configKey().equals(config.configKey())) {
   2949                             sb.append(" is current");
   2950                         } else {
   2951                             sb.append(" current=").append(curConfig.configKey());
   2952                             sb.append(" prio=").append(curConfig.priority);
   2953                             sb.append(" status=").append(curConfig.status);
   2954                         }
   2955                     }
   2956                 }
   2957                 break;
   2958             case WifiManager.DISABLE_NETWORK:
   2959             case CMD_ENABLE_NETWORK:
   2960                 sb.append(" ");
   2961                 sb.append(Integer.toString(msg.arg1));
   2962                 sb.append(" ");
   2963                 sb.append(Integer.toString(msg.arg2));
   2964                 key = mWifiConfigStore.getLastSelectedConfiguration();
   2965                 if (key != null) {
   2966                     sb.append(" last=").append(key);
   2967                 }
   2968                 config = mWifiConfigStore.getWifiConfiguration(msg.arg1);
   2969                 if (config != null && (key == null || !config.configKey().equals(key))) {
   2970                     sb.append(" target=").append(key);
   2971                 }
   2972                 break;
   2973             case CMD_GET_CONFIGURED_NETWORKS:
   2974                 sb.append(" ");
   2975                 sb.append(Integer.toString(msg.arg1));
   2976                 sb.append(" ");
   2977                 sb.append(Integer.toString(msg.arg2));
   2978                 sb.append(" num=").append(mWifiConfigStore.getConfiguredNetworksSize());
   2979                 break;
   2980             case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   2981                 sb.append(" ");
   2982                 sb.append(Integer.toString(msg.arg1));
   2983                 sb.append(" ");
   2984                 sb.append(Integer.toString(msg.arg2));
   2985                 sb.append(" txpkts=").append(mWifiInfo.txSuccess);
   2986                 sb.append(",").append(mWifiInfo.txBad);
   2987                 sb.append(",").append(mWifiInfo.txRetries);
   2988                 break;
   2989             case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   2990                 sb.append(" ");
   2991                 sb.append(Integer.toString(msg.arg1));
   2992                 sb.append(" ");
   2993                 sb.append(Integer.toString(msg.arg2));
   2994                 if (msg.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
   2995                     sb.append(" OK ");
   2996                 } else if (msg.arg1 == DhcpStateMachine.DHCP_FAILURE) {
   2997                     sb.append(" FAIL ");
   2998                 }
   2999                 if (mLinkProperties != null) {
   3000                     if (mLinkProperties.hasIPv4Address()) {
   3001                         sb.append(" v4");
   3002                     }
   3003                     if (mLinkProperties.hasGlobalIPv6Address()) {
   3004                         sb.append(" v6");
   3005                     }
   3006                     if (mLinkProperties.hasIPv4DefaultRoute()) {
   3007                         sb.append(" v4r");
   3008                     }
   3009                     if (mLinkProperties.hasIPv6DefaultRoute()) {
   3010                         sb.append(" v6r");
   3011                     }
   3012                     if (mLinkProperties.hasIPv4DnsServer()) {
   3013                         sb.append(" v4dns");
   3014                     }
   3015                     if (mLinkProperties.hasIPv6DnsServer()) {
   3016                         sb.append(" v6dns");
   3017                     }
   3018                 }
   3019                 break;
   3020             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
   3021                 sb.append(" ");
   3022                 sb.append(Integer.toString(msg.arg1));
   3023                 sb.append(" ");
   3024                 sb.append(Integer.toString(msg.arg2));
   3025                 if (msg.obj != null) {
   3026                     NetworkInfo info = (NetworkInfo) msg.obj;
   3027                     NetworkInfo.State state = info.getState();
   3028                     NetworkInfo.DetailedState detailedState = info.getDetailedState();
   3029                     if (state != null) {
   3030                         sb.append(" st=").append(state);
   3031                     }
   3032                     if (detailedState != null) {
   3033                         sb.append("/").append(detailedState);
   3034                     }
   3035                 }
   3036                 break;
   3037             case CMD_IP_CONFIGURATION_LOST:
   3038                 int count = -1;
   3039                 WifiConfiguration c = getCurrentWifiConfiguration();
   3040                 if (c != null) count = c.numIpConfigFailures;
   3041                 sb.append(" ");
   3042                 sb.append(Integer.toString(msg.arg1));
   3043                 sb.append(" ");
   3044                 sb.append(Integer.toString(msg.arg2));
   3045                 sb.append(" failures: ");
   3046                 sb.append(Integer.toString(count));
   3047                 sb.append("/");
   3048                 sb.append(Integer.toString(mWifiConfigStore.getMaxDhcpRetries()));
   3049                 if (mWifiInfo.getBSSID() != null) {
   3050                     sb.append(" ").append(mWifiInfo.getBSSID());
   3051                 }
   3052                 if (c != null) {
   3053                     ScanDetailCache scanDetailCache =
   3054                             mWifiConfigStore.getScanDetailCache(c);
   3055                     if (scanDetailCache != null) {
   3056                         for (ScanDetail sd : scanDetailCache.values()) {
   3057                             ScanResult r = sd.getScanResult();
   3058                             if (r.BSSID.equals(mWifiInfo.getBSSID())) {
   3059                                 sb.append(" ipfail=").append(r.numIpConfigFailures);
   3060                                 sb.append(",st=").append(r.autoJoinStatus);
   3061                             }
   3062                         }
   3063                     }
   3064                     sb.append(" -> ajst=").append(c.autoJoinStatus);
   3065                     sb.append(" ").append(c.disableReason);
   3066                     sb.append(" txpkts=").append(mWifiInfo.txSuccess);
   3067                     sb.append(",").append(mWifiInfo.txBad);
   3068                     sb.append(",").append(mWifiInfo.txRetries);
   3069                 }
   3070                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
   3071                 break;
   3072             case CMD_UPDATE_LINKPROPERTIES:
   3073                 sb.append(" ");
   3074                 sb.append(Integer.toString(msg.arg1));
   3075                 sb.append(" ");
   3076                 sb.append(Integer.toString(msg.arg2));
   3077                 if (mLinkProperties != null) {
   3078                     if (mLinkProperties.hasIPv4Address()) {
   3079                         sb.append(" v4");
   3080                     }
   3081                     if (mLinkProperties.hasGlobalIPv6Address()) {
   3082                         sb.append(" v6");
   3083                     }
   3084                     if (mLinkProperties.hasIPv4DefaultRoute()) {
   3085                         sb.append(" v4r");
   3086                     }
   3087                     if (mLinkProperties.hasIPv6DefaultRoute()) {
   3088                         sb.append(" v6r");
   3089                     }
   3090                     if (mLinkProperties.hasIPv4DnsServer()) {
   3091                         sb.append(" v4dns");
   3092                     }
   3093                     if (mLinkProperties.hasIPv6DnsServer()) {
   3094                         sb.append(" v6dns");
   3095                     }
   3096                 }
   3097                 break;
   3098             case CMD_IP_REACHABILITY_LOST:
   3099                 if (msg.obj != null) {
   3100                     sb.append(" ").append((String) msg.obj);
   3101                 }
   3102                 break;
   3103             case CMD_SET_COUNTRY_CODE:
   3104                 sb.append(" ");
   3105                 sb.append(Integer.toString(msg.arg1));
   3106                 sb.append(" ");
   3107                 sb.append(Integer.toString(msg.arg2));
   3108                 if (msg.obj != null) {
   3109                     sb.append(" ").append((String) msg.obj);
   3110                 }
   3111                 break;
   3112             case CMD_ROAM_WATCHDOG_TIMER:
   3113                 sb.append(" ");
   3114                 sb.append(Integer.toString(msg.arg1));
   3115                 sb.append(" ");
   3116                 sb.append(Integer.toString(msg.arg2));
   3117                 sb.append(" cur=").append(roamWatchdogCount);
   3118                 break;
   3119             case CMD_DISCONNECTING_WATCHDOG_TIMER:
   3120                 sb.append(" ");
   3121                 sb.append(Integer.toString(msg.arg1));
   3122                 sb.append(" ");
   3123                 sb.append(Integer.toString(msg.arg2));
   3124                 sb.append(" cur=").append(disconnectingWatchdogCount);
   3125                 break;
   3126             default:
   3127                 sb.append(" ");
   3128                 sb.append(Integer.toString(msg.arg1));
   3129                 sb.append(" ");
   3130                 sb.append(Integer.toString(msg.arg2));
   3131                 break;
   3132         }
   3133 
   3134         return sb.toString();
   3135     }
   3136 
   3137     private void stopPnoOffload() {
   3138 
   3139         // clear the PNO list
   3140         if (!WifiNative.setPnoList(null, WifiStateMachine.this)) {
   3141             Log.e(TAG, "Failed to stop pno");
   3142         }
   3143 
   3144     }
   3145 
   3146 
   3147     private boolean configureSsidWhiteList() {
   3148 
   3149         mWhiteListedSsids = mWifiConfigStore.getWhiteListedSsids(getCurrentWifiConfiguration());
   3150         if (mWhiteListedSsids == null || mWhiteListedSsids.length == 0) {
   3151             return true;
   3152         }
   3153 
   3154        if (!WifiNative.setSsidWhitelist(mWhiteListedSsids)) {
   3155             loge("configureSsidWhiteList couldnt program SSID list, size "
   3156                     + mWhiteListedSsids.length);
   3157             return false;
   3158         }
   3159 
   3160         logd("configureSsidWhiteList success");
   3161         return true;
   3162     }
   3163 
   3164     // In associated more, lazy roam will be looking for 5GHz roam candidate
   3165     private boolean configureLazyRoam() {
   3166         boolean status;
   3167         if (!useHalBasedAutoJoinOffload()) return false;
   3168 
   3169         WifiNative.WifiLazyRoamParams params = mWifiNative.new WifiLazyRoamParams();
   3170         params.A_band_boost_threshold = mWifiConfigStore.bandPreferenceBoostThreshold5.get();
   3171         params.A_band_penalty_threshold = mWifiConfigStore.bandPreferencePenaltyThreshold5.get();
   3172         params.A_band_boost_factor = mWifiConfigStore.bandPreferenceBoostFactor5;
   3173         params.A_band_penalty_factor = mWifiConfigStore.bandPreferencePenaltyFactor5;
   3174         params.A_band_max_boost = 65;
   3175         params.lazy_roam_hysteresis = 25;
   3176         params.alert_roam_rssi_trigger = -75;
   3177 
   3178         if (DBG) {
   3179             Log.e(TAG, "configureLazyRoam " + params.toString());
   3180         }
   3181 
   3182         if (!WifiNative.setLazyRoam(true, params)) {
   3183 
   3184             Log.e(TAG, "configureLazyRoam couldnt program params");
   3185 
   3186             return false;
   3187         }
   3188         if (DBG) {
   3189             Log.e(TAG, "configureLazyRoam success");
   3190         }
   3191         return true;
   3192     }
   3193 
   3194     // In associated more, lazy roam will be looking for 5GHz roam candidate
   3195     private boolean stopLazyRoam() {
   3196         boolean status;
   3197         if (!useHalBasedAutoJoinOffload()) return false;
   3198         if (DBG) {
   3199             Log.e(TAG, "stopLazyRoam");
   3200         }
   3201         return WifiNative.setLazyRoam(false, null);
   3202     }
   3203 
   3204     private boolean startGScanConnectedModeOffload(String reason) {
   3205         if (DBG) {
   3206             if (reason == null) {
   3207                 reason = "";
   3208             }
   3209             logd("startGScanConnectedModeOffload " + reason);
   3210         }
   3211         stopGScan("startGScanConnectedModeOffload " + reason);
   3212         if (!mScreenOn) return false;
   3213 
   3214         if (USE_PAUSE_SCANS) {
   3215             mWifiNative.pauseScan();
   3216         }
   3217         mPnoEnabled = configurePno();
   3218         if (mPnoEnabled == false) {
   3219             if (USE_PAUSE_SCANS) {
   3220                 mWifiNative.restartScan();
   3221             }
   3222             return false;
   3223         }
   3224         mLazyRoamEnabled = configureLazyRoam();
   3225         if (mLazyRoamEnabled == false) {
   3226             if (USE_PAUSE_SCANS) {
   3227                 mWifiNative.restartScan();
   3228             }
   3229             return false;
   3230         }
   3231         if (mWifiConfigStore.getLastSelectedConfiguration() == null) {
   3232             configureSsidWhiteList();
   3233         }
   3234         if (!startConnectedGScan(reason)) {
   3235             if (USE_PAUSE_SCANS) {
   3236                 mWifiNative.restartScan();
   3237             }
   3238             return false;
   3239         }
   3240         if (USE_PAUSE_SCANS) {
   3241             mWifiNative.restartScan();
   3242         }
   3243         mConnectedModeGScanOffloadStarted = true;
   3244         if (DBG) {
   3245             logd("startGScanConnectedModeOffload success");
   3246         }
   3247         return true;
   3248     }
   3249 
   3250     private boolean startGScanDisconnectedModeOffload(String reason) {
   3251         if (DBG) {
   3252             logd("startGScanDisconnectedModeOffload " + reason);
   3253         }
   3254         stopGScan("startGScanDisconnectedModeOffload " + reason);
   3255         if (USE_PAUSE_SCANS) {
   3256             mWifiNative.pauseScan();
   3257         }
   3258         mPnoEnabled = configurePno();
   3259         if (mPnoEnabled == false) {
   3260             if (USE_PAUSE_SCANS) {
   3261                 mWifiNative.restartScan();
   3262             }
   3263             return false;
   3264         }
   3265         if (!startDisconnectedGScan(reason)) {
   3266             if (USE_PAUSE_SCANS) {
   3267                 mWifiNative.restartScan();
   3268             }
   3269             return false;
   3270         }
   3271         if (USE_PAUSE_SCANS) {
   3272             mWifiNative.restartScan();
   3273         }
   3274         return true;
   3275     }
   3276 
   3277     private boolean configurePno() {
   3278         if (!useHalBasedAutoJoinOffload()) return false;
   3279 
   3280         if (mWifiScanner == null) {
   3281             log("configurePno: mWifiScanner is null ");
   3282             return true;
   3283         }
   3284 
   3285         List<WifiNative.WifiPnoNetwork> llist
   3286                 = mWifiAutoJoinController.getPnoList(getCurrentWifiConfiguration());
   3287         if (llist == null || llist.size() == 0) {
   3288             stopPnoOffload();
   3289             log("configurePno: empty PNO list ");
   3290             return true;
   3291         }
   3292         if (DBG) {
   3293             log("configurePno: got llist size " + llist.size());
   3294         }
   3295 
   3296         // first program the network we want to look for thru the pno API
   3297         WifiNative.WifiPnoNetwork list[]
   3298                 = (WifiNative.WifiPnoNetwork[]) llist.toArray(new WifiNative.WifiPnoNetwork[0]);
   3299 
   3300         if (!WifiNative.setPnoList(list, WifiStateMachine.this)) {
   3301             Log.e(TAG, "Failed to set pno, length = " + list.length);
   3302             return false;
   3303         }
   3304 
   3305         if (true) {
   3306             StringBuilder sb = new StringBuilder();
   3307             for (WifiNative.WifiPnoNetwork network : list) {
   3308                 sb.append("[").append(network.SSID).append(" auth=").append(network.auth);
   3309                 sb.append(" flags=");
   3310                 sb.append(network.flags).append(" rssi").append(network.rssi_threshold);
   3311                 sb.append("] ");
   3312 
   3313             }
   3314             sendMessage(CMD_STARTED_PNO_DBG, 1, (int)mGScanPeriodMilli, sb.toString());
   3315         }
   3316         return true;
   3317     }
   3318 
   3319     final static int DISCONNECTED_SHORT_SCANS_DURATION_MILLI = 2 * 60 * 1000;
   3320     final static int CONNECTED_SHORT_SCANS_DURATION_MILLI = 2 * 60 * 1000;
   3321 
   3322     private boolean startConnectedGScan(String reason) {
   3323         // send a scan background request so as to kick firmware
   3324         // 5GHz roaming and autojoin
   3325         // We do this only if screen is on
   3326         WifiScanner.ScanSettings settings;
   3327 
   3328         if (mPnoEnabled || mLazyRoamEnabled) {
   3329             settings = new WifiScanner.ScanSettings();
   3330             settings.band = WifiScanner.WIFI_BAND_BOTH;
   3331             long now = System.currentTimeMillis();
   3332 
   3333             if (!mScreenOn  || (mGScanStartTimeMilli!= 0 && now > mGScanStartTimeMilli
   3334                     && ((now - mGScanStartTimeMilli) > CONNECTED_SHORT_SCANS_DURATION_MILLI))) {
   3335                 settings.periodInMs = mWifiConfigStore.wifiAssociatedLongScanIntervalMilli.get();
   3336             } else {
   3337                 mGScanStartTimeMilli = now;
   3338                 settings.periodInMs = mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get();
   3339                 // if we start offload with short interval, then reconfigure it after a given
   3340                 // duration of time so as to reduce the scan frequency
   3341                 int delay = 30 * 1000 + CONNECTED_SHORT_SCANS_DURATION_MILLI;
   3342                 sendMessageDelayed(CMD_RESTART_AUTOJOIN_OFFLOAD, delay,
   3343                         mRestartAutoJoinOffloadCounter, " startConnectedGScan " + reason,
   3344                         (long)delay);
   3345                 mRestartAutoJoinOffloadCounter++;
   3346             }
   3347             mGScanPeriodMilli = settings.periodInMs;
   3348             settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL;
   3349             if (DBG) {
   3350                 log("startConnectedScan: settings band="+ settings.band
   3351                         + " period=" + settings.periodInMs);
   3352             }
   3353 
   3354             mWifiScanner.startBackgroundScan(settings, mWifiScanListener);
   3355             if (true) {
   3356                 sendMessage(CMD_STARTED_GSCAN_DBG, 1, (int)mGScanPeriodMilli, reason);
   3357             }
   3358         }
   3359         return true;
   3360     }
   3361 
   3362     private boolean startDisconnectedGScan(String reason) {
   3363         // send a scan background request so as to kick firmware
   3364         // PNO
   3365         // This is done in both screen On and screen Off modes
   3366         WifiScanner.ScanSettings settings;
   3367 
   3368         if (mWifiScanner == null) {
   3369             log("startDisconnectedGScan: no wifi scanner");
   3370             return false;
   3371         }
   3372 
   3373         if (mPnoEnabled || mLazyRoamEnabled) {
   3374             settings = new WifiScanner.ScanSettings();
   3375             settings.band = WifiScanner.WIFI_BAND_BOTH;
   3376             long now = System.currentTimeMillis();
   3377 
   3378 
   3379             if (!mScreenOn  || (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
   3380                     && ((now - mGScanStartTimeMilli) > DISCONNECTED_SHORT_SCANS_DURATION_MILLI))) {
   3381                 settings.periodInMs = mWifiConfigStore.wifiDisconnectedLongScanIntervalMilli.get();
   3382             } else {
   3383                 settings.periodInMs = mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get();
   3384                 mGScanStartTimeMilli = now;
   3385                 // if we start offload with short interval, then reconfigure it after a given
   3386                 // duration of time so as to reduce the scan frequency
   3387                 int delay = 30 * 1000 + DISCONNECTED_SHORT_SCANS_DURATION_MILLI;
   3388                 sendMessageDelayed(CMD_RESTART_AUTOJOIN_OFFLOAD, delay,
   3389                         mRestartAutoJoinOffloadCounter, " startDisconnectedGScan " + reason,
   3390                         (long)delay);
   3391                 mRestartAutoJoinOffloadCounter++;
   3392             }
   3393             mGScanPeriodMilli = settings.periodInMs;
   3394             settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL;
   3395             if (DBG) {
   3396                 log("startDisconnectedScan: settings band="+ settings.band
   3397                         + " period=" + settings.periodInMs);
   3398             }
   3399             mWifiScanner.startBackgroundScan(settings, mWifiScanListener);
   3400             if (true) {
   3401                 sendMessage(CMD_STARTED_GSCAN_DBG, 1, (int)mGScanPeriodMilli, reason);
   3402             }
   3403         }
   3404         return true;
   3405     }
   3406 
   3407     private boolean stopGScan(String reason) {
   3408         mGScanStartTimeMilli = 0;
   3409         mGScanPeriodMilli = 0;
   3410         if (mWifiScanner != null) {
   3411             mWifiScanner.stopBackgroundScan(mWifiScanListener);
   3412         }
   3413         mConnectedModeGScanOffloadStarted = false;
   3414         if (true) {
   3415             sendMessage(CMD_STARTED_GSCAN_DBG, 0, 0, reason);
   3416         }
   3417         return true;
   3418     }
   3419 
   3420     private void handleScreenStateChanged(boolean screenOn) {
   3421         mScreenOn = screenOn;
   3422         if (PDBG) {
   3423             logd(" handleScreenStateChanged Enter: screenOn=" + screenOn
   3424                     + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt
   3425                     + " state " + getCurrentState().getName()
   3426                     + " suppState:" + mSupplicantStateTracker.getSupplicantStateName());
   3427         }
   3428         enableRssiPolling(screenOn);
   3429         if (screenOn) enableAllNetworks();
   3430         if (mUserWantsSuspendOpt.get()) {
   3431             if (screenOn) {
   3432                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0);
   3433             } else {
   3434                 // Allow 2s for suspend optimizations to be set
   3435                 mSuspendWakeLock.acquire(2000);
   3436                 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0);
   3437             }
   3438         }
   3439         mScreenBroadcastReceived.set(true);
   3440 
   3441         getWifiLinkLayerStats(false);
   3442         mOnTimeScreenStateChange = mOnTime;
   3443         lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate;
   3444 
   3445         cancelDelayedScan();
   3446 
   3447         if (screenOn) {
   3448             enableBackgroundScan(false);
   3449             setScanAlarm(false);
   3450             clearBlacklist();
   3451 
   3452             fullBandConnectedTimeIntervalMilli
   3453                     = mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get();
   3454             // In either Disconnectedstate or ConnectedState,
   3455             // start the scan alarm so as to enable autojoin
   3456             if (getCurrentState() == mConnectedState
   3457                     && allowFullBandScanAndAssociated()) {
   3458                 if (useHalBasedAutoJoinOffload()) {
   3459                     startGScanConnectedModeOffload("screenOnConnected");
   3460                 } else {
   3461                     // Scan after 500ms
   3462                     startDelayedScan(500, null, null);
   3463                 }
   3464             } else if (getCurrentState() == mDisconnectedState) {
   3465                 if (useHalBasedAutoJoinOffload()) {
   3466                     startGScanDisconnectedModeOffload("screenOnDisconnected");
   3467                 } else {
   3468                     // Scan after 500ms
   3469                     startDelayedScan(500, null, null);
   3470                 }
   3471             }
   3472         } else {
   3473             if (getCurrentState() == mDisconnectedState) {
   3474                 // Screen Off and Disconnected and chipset doesn't support scan offload
   3475                 //              => start scan alarm
   3476                 // Screen Off and Disconnected and chipset does support scan offload
   3477                 //              => will use scan offload (i.e. background scan)
   3478                 if (useHalBasedAutoJoinOffload()) {
   3479                     startGScanDisconnectedModeOffload("screenOffDisconnected");
   3480                 } else {
   3481                     if (!mBackgroundScanSupported) {
   3482                         setScanAlarm(true);
   3483                     } else {
   3484                         if (!mIsScanOngoing) {
   3485                             enableBackgroundScan(true);
   3486                         }
   3487                     }
   3488                 }
   3489             } else {
   3490                 enableBackgroundScan(false);
   3491                 if (useHalBasedAutoJoinOffload()) {
   3492                     // don't try stop Gscan if it is not enabled
   3493                     stopGScan("ScreenOffStop(enableBackground=" + mLegacyPnoEnabled + ") ");
   3494                 }
   3495             }
   3496         }
   3497         if (DBG) logd("backgroundScan enabled=" + mLegacyPnoEnabled);
   3498 
   3499         if (DBG) log("handleScreenStateChanged Exit: " + screenOn);
   3500     }
   3501 
   3502     private void checkAndSetConnectivityInstance() {
   3503         if (mCm == null) {
   3504             mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
   3505         }
   3506     }
   3507 
   3508     private boolean startTethering(ArrayList<String> available) {
   3509 
   3510         boolean wifiAvailable = false;
   3511 
   3512         checkAndSetConnectivityInstance();
   3513 
   3514         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
   3515 
   3516         for (String intf : available) {
   3517             for (String regex : wifiRegexs) {
   3518                 if (intf.matches(regex)) {
   3519 
   3520                     InterfaceConfiguration ifcg = null;
   3521                     try {
   3522                         ifcg = mNwService.getInterfaceConfig(intf);
   3523                         if (ifcg != null) {
   3524                             /* IP/netmask: 192.168.43.1/255.255.255.0 */
   3525                             ifcg.setLinkAddress(new LinkAddress(
   3526                                     NetworkUtils.numericToInetAddress("192.168.43.1"), 24));
   3527                             ifcg.setInterfaceUp();
   3528 
   3529                             mNwService.setInterfaceConfig(intf, ifcg);
   3530                         }
   3531                     } catch (Exception e) {
   3532                         loge("Error configuring interface " + intf + ", :" + e);
   3533                         return false;
   3534                     }
   3535 
   3536                     if (mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
   3537                         loge("Error tethering on " + intf);
   3538                         return false;
   3539                     }
   3540                     mTetherInterfaceName = intf;
   3541                     return true;
   3542                 }
   3543             }
   3544         }
   3545         // We found no interfaces to tether
   3546         return false;
   3547     }
   3548 
   3549     private void stopTethering() {
   3550 
   3551         checkAndSetConnectivityInstance();
   3552 
   3553         /* Clear the interface config to allow dhcp correctly configure new
   3554            ip settings */
   3555         InterfaceConfiguration ifcg = null;
   3556         try {
   3557             ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName);
   3558             if (ifcg != null) {
   3559                 ifcg.setLinkAddress(
   3560                         new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0));
   3561                 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg);
   3562             }
   3563         } catch (Exception e) {
   3564             loge("Error resetting interface " + mTetherInterfaceName + ", :" + e);
   3565         }
   3566 
   3567         if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
   3568             loge("Untether initiate failed!");
   3569         }
   3570     }
   3571 
   3572     private boolean isWifiTethered(ArrayList<String> active) {
   3573 
   3574         checkAndSetConnectivityInstance();
   3575 
   3576         String[] wifiRegexs = mCm.getTetherableWifiRegexs();
   3577         for (String intf : active) {
   3578             for (String regex : wifiRegexs) {
   3579                 if (intf.matches(regex)) {
   3580                     return true;
   3581                 }
   3582             }
   3583         }
   3584         // We found no interfaces that are tethered
   3585         return false;
   3586     }
   3587 
   3588     /**
   3589      * Set the country code from the system setting value, if any.
   3590      */
   3591     private void setCountryCode() {
   3592         String countryCode = Settings.Global.getString(mContext.getContentResolver(),
   3593                 Settings.Global.WIFI_COUNTRY_CODE);
   3594         if (countryCode != null && !countryCode.isEmpty()) {
   3595             setCountryCode(countryCode, false);
   3596         } else {
   3597             //use driver default
   3598         }
   3599     }
   3600 
   3601     /**
   3602      * Set the frequency band from the system setting value, if any.
   3603      */
   3604     private void setFrequencyBand() {
   3605         int band = Settings.Global.getInt(mContext.getContentResolver(),
   3606                 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
   3607 
   3608         if (mWifiNative.setBand(band)) {
   3609             mFrequencyBand.set(band);
   3610             if (PDBG) {
   3611                 logd("done set frequency band " + band);
   3612             }
   3613         } else {
   3614             loge("Failed to set frequency band " + band);
   3615         }
   3616     }
   3617 
   3618 
   3619 
   3620     private void setSuspendOptimizationsNative(int reason, boolean enabled) {
   3621         if (DBG) {
   3622             log("setSuspendOptimizationsNative: " + reason + " " + enabled
   3623                     + " -want " + mUserWantsSuspendOpt.get()
   3624                     + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
   3625                     + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
   3626                     + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
   3627                     + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
   3628         }
   3629         //mWifiNative.setSuspendOptimizations(enabled);
   3630 
   3631         if (enabled) {
   3632             mSuspendOptNeedsDisabled &= ~reason;
   3633             /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
   3634             if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) {
   3635                 if (DBG) {
   3636                     log("setSuspendOptimizationsNative do it " + reason + " " + enabled
   3637                             + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
   3638                             + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
   3639                             + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
   3640                             + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
   3641                 }
   3642                 mWifiNative.setSuspendOptimizations(true);
   3643             }
   3644         } else {
   3645             mSuspendOptNeedsDisabled |= reason;
   3646             mWifiNative.setSuspendOptimizations(false);
   3647         }
   3648     }
   3649 
   3650     private void setSuspendOptimizations(int reason, boolean enabled) {
   3651         if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled);
   3652         if (enabled) {
   3653             mSuspendOptNeedsDisabled &= ~reason;
   3654         } else {
   3655             mSuspendOptNeedsDisabled |= reason;
   3656         }
   3657         if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
   3658     }
   3659 
   3660     private void setWifiState(int wifiState) {
   3661         final int previousWifiState = mWifiState.get();
   3662 
   3663         try {
   3664             if (wifiState == WIFI_STATE_ENABLED) {
   3665                 mBatteryStats.noteWifiOn();
   3666             } else if (wifiState == WIFI_STATE_DISABLED) {
   3667                 mBatteryStats.noteWifiOff();
   3668             }
   3669         } catch (RemoteException e) {
   3670             loge("Failed to note battery stats in wifi");
   3671         }
   3672 
   3673         mWifiState.set(wifiState);
   3674 
   3675         if (DBG) log("setWifiState: " + syncGetWifiStateByName());
   3676 
   3677         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
   3678         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   3679         intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
   3680         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
   3681         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   3682     }
   3683 
   3684     private void setWifiApState(int wifiApState, int reason) {
   3685         final int previousWifiApState = mWifiApState.get();
   3686 
   3687         try {
   3688             if (wifiApState == WIFI_AP_STATE_ENABLED) {
   3689                 mBatteryStats.noteWifiOn();
   3690             } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
   3691                 mBatteryStats.noteWifiOff();
   3692             }
   3693         } catch (RemoteException e) {
   3694             loge("Failed to note battery stats in wifi");
   3695         }
   3696 
   3697         // Update state
   3698         mWifiApState.set(wifiApState);
   3699 
   3700         if (DBG) log("setWifiApState: " + syncGetWifiApStateByName());
   3701 
   3702         final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
   3703         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   3704         intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
   3705         intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
   3706         if (wifiApState == WifiManager.WIFI_AP_STATE_FAILED) {
   3707             //only set reason number when softAP start failed
   3708             intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
   3709         }
   3710 
   3711         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   3712     }
   3713 
   3714     /*
   3715     void ageOutScanResults(int age) {
   3716         synchronized(mScanResultCache) {
   3717             // Trim mScanResults, which prevent WifiStateMachine to return
   3718             // obsolete scan results to queriers
   3719             long now = System.CurrentTimeMillis();
   3720             for (int i = 0; i < mScanResults.size(); i++) {
   3721                 ScanResult result = mScanResults.get(i);
   3722                 if ((result.seen > now || (now - result.seen) > age)) {
   3723                     mScanResults.remove(i);
   3724                 }
   3725             }
   3726         }
   3727     }*/
   3728 
   3729     private static final String IE_STR = "ie=";
   3730     private static final String ID_STR = "id=";
   3731     private static final String BSSID_STR = "bssid=";
   3732     private static final String FREQ_STR = "freq=";
   3733     private static final String LEVEL_STR = "level=";
   3734     private static final String TSF_STR = "tsf=";
   3735     private static final String FLAGS_STR = "flags=";
   3736     private static final String SSID_STR = "ssid=";
   3737     private static final String DELIMITER_STR = "====";
   3738     private static final String END_STR = "####";
   3739 
   3740     int emptyScanResultCount = 0;
   3741 
   3742     // Used for matching BSSID strings, at least one characteer must be a non-zero number
   3743     private static Pattern mNotZero = Pattern.compile("[1-9a-fA-F]");
   3744 
   3745     /**
   3746      * Format:
   3747      * <p/>
   3748      * id=1
   3749      * bssid=68:7f:76:d7:1a:6e
   3750      * freq=2412
   3751      * level=-44
   3752      * tsf=1344626243700342
   3753      * flags=[WPA2-PSK-CCMP][WPS][ESS]
   3754      * ssid=zfdy
   3755      * ====
   3756      * id=2
   3757      * bssid=68:5f:74:d7:1a:6f
   3758      * freq=5180
   3759      * level=-73
   3760      * tsf=1344626243700373
   3761      * flags=[WPA2-PSK-CCMP][WPS][ESS]
   3762      * ssid=zuby
   3763      * ====
   3764      */
   3765     private void setScanResults() {
   3766         mNumScanResultsKnown = 0;
   3767         mNumScanResultsReturned = 0;
   3768         String bssid = "";
   3769         int level = 0;
   3770         int freq = 0;
   3771         long tsf = 0;
   3772         String flags = "";
   3773         WifiSsid wifiSsid = null;
   3774         String scanResults;
   3775         String tmpResults;
   3776         StringBuffer scanResultsBuf = new StringBuffer();
   3777         int sid = 0;
   3778 
   3779         while (true) {
   3780             tmpResults = mWifiNative.scanResults(sid);
   3781             if (TextUtils.isEmpty(tmpResults)) break;
   3782             scanResultsBuf.append(tmpResults);
   3783             scanResultsBuf.append("\n");
   3784             String[] lines = tmpResults.split("\n");
   3785             sid = -1;
   3786             for (int i = lines.length - 1; i >= 0; i--) {
   3787                 if (lines[i].startsWith(END_STR)) {
   3788                     break;
   3789                 } else if (lines[i].startsWith(ID_STR)) {
   3790                     try {
   3791                         sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1;
   3792                     } catch (NumberFormatException e) {
   3793                         // Nothing to do
   3794                     }
   3795                     break;
   3796                 }
   3797             }
   3798             if (sid == -1) break;
   3799         }
   3800 
   3801         // Age out scan results, we return all scan results found in the last 12 seconds,
   3802         // and NOT all scan results since last scan.
   3803         // ageOutScanResults(12000);
   3804 
   3805         scanResults = scanResultsBuf.toString();
   3806         if (TextUtils.isEmpty(scanResults)) {
   3807             emptyScanResultCount++;
   3808             if (emptyScanResultCount > 10) {
   3809                 // If we got too many empty scan results, the current scan cache is stale,
   3810                 // hence clear it.
   3811                 mScanResults = new ArrayList<>();
   3812             }
   3813             return;
   3814         }
   3815 
   3816         emptyScanResultCount = 0;
   3817 
   3818         mWifiConfigStore.trimANQPCache(false);
   3819 
   3820         // note that all these splits and substrings keep references to the original
   3821         // huge string buffer while the amount we really want is generally pretty small
   3822         // so make copies instead (one example b/11087956 wasted 400k of heap here).
   3823         synchronized (mScanResultCache) {
   3824             mScanResults = new ArrayList<>();
   3825             String[] lines = scanResults.split("\n");
   3826             final int bssidStrLen = BSSID_STR.length();
   3827             final int flagLen = FLAGS_STR.length();
   3828             String infoElements = null;
   3829             List<String> anqpLines = null;
   3830 
   3831             for (String line : lines) {
   3832                 if (line.startsWith(BSSID_STR)) {
   3833                     bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen);
   3834                 } else if (line.startsWith(FREQ_STR)) {
   3835                     try {
   3836                         freq = Integer.parseInt(line.substring(FREQ_STR.length()));
   3837                     } catch (NumberFormatException e) {
   3838                         freq = 0;
   3839                     }
   3840                 } else if (line.startsWith(LEVEL_STR)) {
   3841                     try {
   3842                         level = Integer.parseInt(line.substring(LEVEL_STR.length()));
   3843                         /* some implementations avoid negative values by adding 256
   3844                          * so we need to adjust for that here.
   3845                          */
   3846                         if (level > 0) level -= 256;
   3847                     } catch (NumberFormatException e) {
   3848                         level = 0;
   3849                     }
   3850                 } else if (line.startsWith(TSF_STR)) {
   3851                     try {
   3852                         tsf = Long.parseLong(line.substring(TSF_STR.length()));
   3853                     } catch (NumberFormatException e) {
   3854                         tsf = 0;
   3855                     }
   3856                 } else if (line.startsWith(FLAGS_STR)) {
   3857                     flags = new String(line.getBytes(), flagLen, line.length() - flagLen);
   3858                 } else if (line.startsWith(SSID_STR)) {
   3859                     wifiSsid = WifiSsid.createFromAsciiEncoded(
   3860                             line.substring(SSID_STR.length()));
   3861                 } else if (line.startsWith(IE_STR)) {
   3862                     infoElements = line;
   3863                 } else if (SupplicantBridge.isAnqpAttribute(line)) {
   3864                     if (anqpLines == null) {
   3865                         anqpLines = new ArrayList<>();
   3866                     }
   3867                     anqpLines.add(line);
   3868                 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) {
   3869                     if (bssid != null) {
   3870                         try {
   3871                             NetworkDetail networkDetail =
   3872                                     new NetworkDetail(bssid, infoElements, anqpLines, freq);
   3873 
   3874                             String xssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
   3875                             if (!xssid.equals(networkDetail.getTrimmedSSID())) {
   3876                                 logd(String.format(
   3877                                         "Inconsistent SSID on BSSID '%s': '%s' vs '%s': %s",
   3878                                         bssid, xssid, networkDetail.getSSID(), infoElements));
   3879                             }
   3880 
   3881                             if (networkDetail.hasInterworking()) {
   3882                                 Log.d(Utils.hs2LogTag(getClass()), "HSNwk: '" + networkDetail);
   3883                             }
   3884 
   3885                             ScanDetail scanDetail = mScanResultCache.get(networkDetail);
   3886                             if (scanDetail != null) {
   3887                                 scanDetail.updateResults(networkDetail, level, wifiSsid, xssid,
   3888                                         flags, freq, tsf);
   3889                             } else {
   3890                                 scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid,
   3891                                         flags, level, freq, tsf);
   3892                                 mScanResultCache.put(networkDetail, scanDetail);
   3893                             }
   3894 
   3895                             mNumScanResultsReturned++; // Keep track of how many scan results we got
   3896                             // as part of this scan's processing
   3897                             mScanResults.add(scanDetail);
   3898                         } catch (IllegalArgumentException iae) {
   3899                             Log.d(TAG, "Failed to parse information elements: " + iae);
   3900                         }
   3901                     }
   3902                     bssid = null;
   3903                     level = 0;
   3904                     freq = 0;
   3905                     tsf = 0;
   3906                     flags = "";
   3907                     wifiSsid = null;
   3908                     infoElements = null;
   3909                     anqpLines = null;
   3910                 }
   3911             }
   3912         }
   3913 
   3914         /* don't attempt autojoin if last connect attempt was just scheduled */
   3915         boolean attemptAutoJoin =
   3916                 (System.currentTimeMillis() - lastConnectAttemptTimestamp) > CONNECT_TIMEOUT_MSEC;
   3917         SupplicantState state = mWifiInfo.getSupplicantState();
   3918         String selection = mWifiConfigStore.getLastSelectedConfiguration();
   3919         if (getCurrentState() == mRoamingState
   3920                 || getCurrentState() == mObtainingIpState
   3921                 || getCurrentState() == mScanModeState
   3922                 || getCurrentState() == mDisconnectingState
   3923                 || (getCurrentState() == mConnectedState
   3924                 && !getEnableAutoJoinWhenAssociated())
   3925                 || linkDebouncing
   3926                 || state == SupplicantState.ASSOCIATING
   3927                 || state == SupplicantState.AUTHENTICATING
   3928                 || state == SupplicantState.FOUR_WAY_HANDSHAKE
   3929                 || state == SupplicantState.GROUP_HANDSHAKE
   3930                 || (/* keep autojoin enabled if user has manually selected a wifi network,
   3931                         so as to make sure we reliably remain connected to this network */
   3932                 mConnectionRequests == 0 && selection == null)) {
   3933             // Dont attempt auto-joining again while we are already attempting to join
   3934             // and/or obtaining Ip address
   3935             attemptAutoJoin = false;
   3936         }
   3937         if (DBG) {
   3938             if (selection == null) {
   3939                 selection = "<none>";
   3940             }
   3941             logd("wifi setScanResults state" + getCurrentState()
   3942                     + " sup_state=" + state
   3943                     + " debouncing=" + linkDebouncing
   3944                     + " mConnectionRequests=" + mConnectionRequests
   3945                     + " selection=" + selection
   3946                     + " mNumScanResultsReturned " + mNumScanResultsReturned
   3947                      + " mScanResults " + mScanResults.size());
   3948         }
   3949         if (attemptAutoJoin) {
   3950             messageHandlingStatus = MESSAGE_HANDLING_STATUS_PROCESSED;
   3951         }
   3952         // Loose last selected configuration if we have been disconnected for 5 minutes
   3953         if (getDisconnectedTimeMilli() > mWifiConfigStore.wifiConfigLastSelectionHysteresis) {
   3954             mWifiConfigStore.setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
   3955         }
   3956 
   3957         if (attemptAutoJoin) {
   3958             synchronized (mScanResultCache) {
   3959                 // AutoJoincontroller will directly acces the scan result list and update it with
   3960                 // ScanResult status
   3961                 mNumScanResultsKnown = mWifiAutoJoinController.newSupplicantResults(attemptAutoJoin);
   3962             }
   3963         }
   3964         if (linkDebouncing) {
   3965             // If debouncing, we dont re-select a SSID or BSSID hence
   3966             // there is no need to call the network selection code
   3967             // in WifiAutoJoinController, instead,
   3968             // just try to reconnect to the same SSID by triggering a roam
   3969             sendMessage(CMD_AUTO_ROAM, mLastNetworkId, 1, null);
   3970         }
   3971     }
   3972 
   3973     /*
   3974      * Fetch RSSI, linkspeed, and frequency on current connection
   3975      */
   3976     private void fetchRssiLinkSpeedAndFrequencyNative() {
   3977         int newRssi = -1;
   3978         int newLinkSpeed = -1;
   3979         int newFrequency = -1;
   3980 
   3981         String signalPoll = mWifiNative.signalPoll();
   3982 
   3983         if (signalPoll != null) {
   3984             String[] lines = signalPoll.split("\n");
   3985             for (String line : lines) {
   3986                 String[] prop = line.split("=");
   3987                 if (prop.length < 2) continue;
   3988                 try {
   3989                     if (prop[0].equals("RSSI")) {
   3990                         newRssi = Integer.parseInt(prop[1]);
   3991                     } else if (prop[0].equals("LINKSPEED")) {
   3992                         newLinkSpeed = Integer.parseInt(prop[1]);
   3993                     } else if (prop[0].equals("FREQUENCY")) {
   3994                         newFrequency = Integer.parseInt(prop[1]);
   3995                     }
   3996                 } catch (NumberFormatException e) {
   3997                     //Ignore, defaults on rssi and linkspeed are assigned
   3998                 }
   3999             }
   4000         }
   4001 
   4002         if (PDBG) {
   4003             logd("fetchRssiLinkSpeedAndFrequencyNative rssi="
   4004                     + Integer.toString(newRssi) + " linkspeed="
   4005                     + Integer.toString(newLinkSpeed));
   4006         }
   4007 
   4008         if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) {
   4009             // screen out invalid values
   4010             /* some implementations avoid negative values by adding 256
   4011              * so we need to adjust for that here.
   4012              */
   4013             if (newRssi > 0) newRssi -= 256;
   4014             mWifiInfo.setRssi(newRssi);
   4015             /*
   4016              * Rather then sending the raw RSSI out every time it
   4017              * changes, we precalculate the signal level that would
   4018              * be displayed in the status bar, and only send the
   4019              * broadcast if that much more coarse-grained number
   4020              * changes. This cuts down greatly on the number of
   4021              * broadcasts, at the cost of not informing others
   4022              * interested in RSSI of all the changes in signal
   4023              * level.
   4024              */
   4025             int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
   4026             if (newSignalLevel != mLastSignalLevel) {
   4027                 sendRssiChangeBroadcast(newRssi);
   4028             }
   4029             mLastSignalLevel = newSignalLevel;
   4030         } else {
   4031             mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
   4032         }
   4033 
   4034         if (newLinkSpeed != -1) {
   4035             mWifiInfo.setLinkSpeed(newLinkSpeed);
   4036         }
   4037         if (newFrequency > 0) {
   4038             if (ScanResult.is5GHz(newFrequency)) {
   4039                 mWifiConnectionStatistics.num5GhzConnected++;
   4040             }
   4041             if (ScanResult.is24GHz(newFrequency)) {
   4042                 mWifiConnectionStatistics.num24GhzConnected++;
   4043             }
   4044             mWifiInfo.setFrequency(newFrequency);
   4045         }
   4046         mWifiConfigStore.updateConfiguration(mWifiInfo);
   4047     }
   4048 
   4049     /**
   4050      * Determine if we need to switch network:
   4051      * - the delta determine the urgency to switch and/or or the expected evilness of the disruption
   4052      * - match the uregncy of the switch versus the packet usage at the interface
   4053      */
   4054     boolean shouldSwitchNetwork(int networkDelta) {
   4055         int delta;
   4056         if (networkDelta <= 0) {
   4057             return false;
   4058         }
   4059         delta = networkDelta;
   4060         if (mWifiInfo != null) {
   4061             if (!getEnableAutoJoinWhenAssociated()
   4062                     && mWifiInfo.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
   4063                 // If AutoJoin while associated is not enabled,
   4064                 // we should never switch network when already associated
   4065                 delta = -1000;
   4066             } else {
   4067                 // TODO: Look at per AC packet count, do not switch if VO/VI traffic is present
   4068                 // TODO: at the interface. We should also discriminate between ucast and mcast,
   4069                 // TODO: since the rxSuccessRate include all the bonjour and Ipv6
   4070                 // TODO: broadcasts
   4071                 if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) {
   4072                     delta -= 999;
   4073                 } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) {
   4074                     delta -= 6;
   4075                 }
   4076                 logd("shouldSwitchNetwork "
   4077                         + " txSuccessRate=" + String.format("%.2f", mWifiInfo.txSuccessRate)
   4078                         + " rxSuccessRate=" + String.format("%.2f", mWifiInfo.rxSuccessRate)
   4079                         + " delta " + networkDelta + " -> " + delta);
   4080             }
   4081         } else {
   4082             logd("shouldSwitchNetwork "
   4083                     + " delta " + networkDelta + " -> " + delta);
   4084         }
   4085         if (delta > 0) {
   4086             return true;
   4087         }
   4088         return false;
   4089     }
   4090 
   4091     // Polling has completed, hence we wont have a score anymore
   4092     private void cleanWifiScore() {
   4093         mWifiInfo.txBadRate = 0;
   4094         mWifiInfo.txSuccessRate = 0;
   4095         mWifiInfo.txRetriesRate = 0;
   4096         mWifiInfo.rxSuccessRate = 0;
   4097     }
   4098 
   4099     int mBadLinkspeedcount = 0;
   4100 
   4101     // For debug, provide information about the last scoring operation
   4102     String wifiScoringReport = null;
   4103 
   4104     private void calculateWifiScore(WifiLinkLayerStats stats) {
   4105         StringBuilder sb = new StringBuilder();
   4106 
   4107         int score = 56; // Starting score, temporarily hardcoded in between 50 and 60
   4108         boolean isBadLinkspeed = (mWifiInfo.is24GHz()
   4109                 && mWifiInfo.getLinkSpeed() < mWifiConfigStore.badLinkSpeed24)
   4110                 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed()
   4111                 < mWifiConfigStore.badLinkSpeed5);
   4112         boolean isGoodLinkspeed = (mWifiInfo.is24GHz()
   4113                 && mWifiInfo.getLinkSpeed() >= mWifiConfigStore.goodLinkSpeed24)
   4114                 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed()
   4115                 >= mWifiConfigStore.goodLinkSpeed5);
   4116 
   4117         if (isBadLinkspeed) {
   4118             if (mBadLinkspeedcount < 6)
   4119                 mBadLinkspeedcount++;
   4120         } else {
   4121             if (mBadLinkspeedcount > 0)
   4122                 mBadLinkspeedcount--;
   4123         }
   4124 
   4125         if (isBadLinkspeed) sb.append(" bl(").append(mBadLinkspeedcount).append(")");
   4126         if (isGoodLinkspeed) sb.append(" gl");
   4127 
   4128         /**
   4129          * We want to make sure that we use the 24GHz RSSI thresholds if
   4130          * there are 2.4GHz scan results
   4131          * otherwise we end up lowering the score based on 5GHz values
   4132          * which may cause a switch to LTE before roaming has a chance to try 2.4GHz
   4133          * We also might unblacklist the configuation based on 2.4GHz
   4134          * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good
   4135          */
   4136         boolean use24Thresholds = false;
   4137         boolean homeNetworkBoost = false;
   4138         WifiConfiguration currentConfiguration = getCurrentWifiConfiguration();
   4139         ScanDetailCache scanDetailCache =
   4140                 mWifiConfigStore.getScanDetailCache(currentConfiguration);
   4141         if (currentConfiguration != null && scanDetailCache != null) {
   4142             currentConfiguration.setVisibility(scanDetailCache.getVisibility(12000));
   4143             if (currentConfiguration.visibility != null) {
   4144                 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI
   4145                         && currentConfiguration.visibility.rssi24
   4146                         >= (currentConfiguration.visibility.rssi5 - 2)) {
   4147                     use24Thresholds = true;
   4148                 }
   4149             }
   4150             if (scanDetailCache.size() <= 6
   4151                 && currentConfiguration.allowedKeyManagement.cardinality() == 1
   4152                 && currentConfiguration.allowedKeyManagement.
   4153                     get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) {
   4154                 // A PSK network with less than 6 known BSSIDs
   4155                 // This is most likely a home network and thus we want to stick to wifi more
   4156                 homeNetworkBoost = true;
   4157             }
   4158         }
   4159         if (homeNetworkBoost) sb.append(" hn");
   4160         if (use24Thresholds) sb.append(" u24");
   4161 
   4162         int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover
   4163                 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0);
   4164         sb.append(String.format(" rssi=%d ag=%d", rssi, mAggressiveHandover));
   4165 
   4166         boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz();
   4167 
   4168         boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24.get())
   4169                 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5.get());
   4170         boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24.get())
   4171                 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5.get());
   4172         boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24.get())
   4173                 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5.get());
   4174 
   4175         if (isBadRSSI) sb.append(" br");
   4176         if (isLowRSSI) sb.append(" lr");
   4177         if (isHighRSSI) sb.append(" hr");
   4178 
   4179         int penalizedDueToUserTriggeredDisconnect = 0;        // For debug information
   4180         if (currentConfiguration != null &&
   4181                 (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 5)) {
   4182             if (isBadRSSI) {
   4183                 currentConfiguration.numTicksAtBadRSSI++;
   4184                 if (currentConfiguration.numTicksAtBadRSSI > 1000) {
   4185                     // We remained associated for a compound amount of time while passing
   4186                     // traffic, hence loose the corresponding user triggered disabled stats
   4187                     if (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0) {
   4188                         currentConfiguration.numUserTriggeredWifiDisableBadRSSI--;
   4189                     }
   4190                     if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) {
   4191                         currentConfiguration.numUserTriggeredWifiDisableLowRSSI--;
   4192                     }
   4193                     if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
   4194                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
   4195                     }
   4196                     currentConfiguration.numTicksAtBadRSSI = 0;
   4197                 }
   4198                 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment &&
   4199                         (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0
   4200                                 || currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0
   4201                                 || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) {
   4202                     score = score - 5;
   4203                     penalizedDueToUserTriggeredDisconnect = 1;
   4204                     sb.append(" p1");
   4205                 }
   4206             } else if (isLowRSSI) {
   4207                 currentConfiguration.numTicksAtLowRSSI++;
   4208                 if (currentConfiguration.numTicksAtLowRSSI > 1000) {
   4209                     // We remained associated for a compound amount of time while passing
   4210                     // traffic, hence loose the corresponding user triggered disabled stats
   4211                     if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) {
   4212                         currentConfiguration.numUserTriggeredWifiDisableLowRSSI--;
   4213                     }
   4214                     if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
   4215                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
   4216                     }
   4217                     currentConfiguration.numTicksAtLowRSSI = 0;
   4218                 }
   4219                 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment &&
   4220                         (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0
   4221                                 || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) {
   4222                     score = score - 5;
   4223                     penalizedDueToUserTriggeredDisconnect = 2;
   4224                     sb.append(" p2");
   4225                 }
   4226             } else if (!isHighRSSI) {
   4227                 currentConfiguration.numTicksAtNotHighRSSI++;
   4228                 if (currentConfiguration.numTicksAtNotHighRSSI > 1000) {
   4229                     // We remained associated for a compound amount of time while passing
   4230                     // traffic, hence loose the corresponding user triggered disabled stats
   4231                     if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
   4232                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
   4233                     }
   4234                     currentConfiguration.numTicksAtNotHighRSSI = 0;
   4235                 }
   4236                 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment &&
   4237                         currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
   4238                     score = score - 5;
   4239                     penalizedDueToUserTriggeredDisconnect = 3;
   4240                     sb.append(" p3");
   4241                 }
   4242             }
   4243             sb.append(String.format(" ticks %d,%d,%d", currentConfiguration.numTicksAtBadRSSI,
   4244                     currentConfiguration.numTicksAtLowRSSI,
   4245                     currentConfiguration.numTicksAtNotHighRSSI));
   4246         }
   4247 
   4248         if (PDBG) {
   4249             String rssiStatus = "";
   4250             if (isBadRSSI) rssiStatus += " badRSSI ";
   4251             else if (isHighRSSI) rssiStatus += " highRSSI ";
   4252             else if (isLowRSSI) rssiStatus += " lowRSSI ";
   4253             if (isBadLinkspeed) rssiStatus += " lowSpeed ";
   4254             logd("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency())
   4255                     + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed())
   4256                     + " score=" + Integer.toString(mWifiInfo.score)
   4257                     + rssiStatus
   4258                     + " -> txbadrate=" + String.format("%.2f", mWifiInfo.txBadRate)
   4259                     + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate)
   4260                     + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate)
   4261                     + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate)
   4262                     + " userTriggerdPenalty" + penalizedDueToUserTriggeredDisconnect);
   4263         }
   4264 
   4265         if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3)
   4266                 && (isBadRSSI || isLowRSSI)) {
   4267             // Link is stuck
   4268             if (mWifiInfo.linkStuckCount < 5)
   4269                 mWifiInfo.linkStuckCount += 1;
   4270             sb.append(String.format(" ls+=%d", mWifiInfo.linkStuckCount));
   4271             if (PDBG) logd(" bad link -> stuck count ="
   4272                     + Integer.toString(mWifiInfo.linkStuckCount));
   4273         } else if (mWifiInfo.txBadRate < 0.3) {
   4274             if (mWifiInfo.linkStuckCount > 0)
   4275                 mWifiInfo.linkStuckCount -= 1;
   4276             sb.append(String.format(" ls-=%d", mWifiInfo.linkStuckCount));
   4277             if (PDBG) logd(" good link -> stuck count ="
   4278                     + Integer.toString(mWifiInfo.linkStuckCount));
   4279         }
   4280 
   4281         sb.append(String.format(" [%d", score));
   4282 
   4283         if (mWifiInfo.linkStuckCount > 1) {
   4284             // Once link gets stuck for more than 3 seconds, start reducing the score
   4285             score = score - 2 * (mWifiInfo.linkStuckCount - 1);
   4286         }
   4287         sb.append(String.format(",%d", score));
   4288 
   4289         if (isBadLinkspeed) {
   4290             score -= 4;
   4291             if (PDBG) {
   4292                 logd(" isBadLinkspeed   ---> count=" + mBadLinkspeedcount
   4293                         + " score=" + Integer.toString(score));
   4294             }
   4295         } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) {
   4296             score += 4; // So as bad rssi alone dont kill us
   4297         }
   4298         sb.append(String.format(",%d", score));
   4299 
   4300         if (isBadRSSI) {
   4301             if (mWifiInfo.badRssiCount < 7)
   4302                 mWifiInfo.badRssiCount += 1;
   4303         } else if (isLowRSSI) {
   4304             mWifiInfo.lowRssiCount = 1; // Dont increment the lowRssi count above 1
   4305             if (mWifiInfo.badRssiCount > 0) {
   4306                 // Decrement bad Rssi count
   4307                 mWifiInfo.badRssiCount -= 1;
   4308             }
   4309         } else {
   4310             mWifiInfo.badRssiCount = 0;
   4311             mWifiInfo.lowRssiCount = 0;
   4312         }
   4313 
   4314         score -= mWifiInfo.badRssiCount * 2 + mWifiInfo.lowRssiCount;
   4315         sb.append(String.format(",%d", score));
   4316 
   4317         if (PDBG) logd(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount)
   4318                 + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount)
   4319                 + " --> score " + Integer.toString(score));
   4320 
   4321 
   4322         if (isHighRSSI) {
   4323             score += 5;
   4324             if (PDBG) logd(" isHighRSSI       ---> score=" + Integer.toString(score));
   4325         }
   4326         sb.append(String.format(",%d]", score));
   4327 
   4328         sb.append(String.format(" brc=%d lrc=%d", mWifiInfo.badRssiCount, mWifiInfo.lowRssiCount));
   4329 
   4330         //sanitize boundaries
   4331         if (score > NetworkAgent.WIFI_BASE_SCORE)
   4332             score = NetworkAgent.WIFI_BASE_SCORE;
   4333         if (score < 0)
   4334             score = 0;
   4335 
   4336         //report score
   4337         if (score != mWifiInfo.score) {
   4338             if (DBG) {
   4339                 logd("calculateWifiScore() report new score " + Integer.toString(score));
   4340             }
   4341             mWifiInfo.score = score;
   4342             if (mNetworkAgent != null) {
   4343                 mNetworkAgent.sendNetworkScore(score);
   4344             }
   4345         }
   4346         wifiScoringReport = sb.toString();
   4347     }
   4348 
   4349     public double getTxPacketRate() {
   4350         if (mWifiInfo != null) {
   4351             return mWifiInfo.txSuccessRate;
   4352         }
   4353         return -1;
   4354     }
   4355 
   4356     public double getRxPacketRate() {
   4357         if (mWifiInfo != null) {
   4358             return mWifiInfo.rxSuccessRate;
   4359         }
   4360         return -1;
   4361     }
   4362 
   4363     /**
   4364      * Fetch TX packet counters on current connection
   4365      */
   4366     private void fetchPktcntNative(RssiPacketCountInfo info) {
   4367         String pktcntPoll = mWifiNative.pktcntPoll();
   4368 
   4369         if (pktcntPoll != null) {
   4370             String[] lines = pktcntPoll.split("\n");
   4371             for (String line : lines) {
   4372                 String[] prop = line.split("=");
   4373                 if (prop.length < 2) continue;
   4374                 try {
   4375                     if (prop[0].equals("TXGOOD")) {
   4376                         info.txgood = Integer.parseInt(prop[1]);
   4377                     } else if (prop[0].equals("TXBAD")) {
   4378                         info.txbad = Integer.parseInt(prop[1]);
   4379                     }
   4380                 } catch (NumberFormatException e) {
   4381                     // Ignore
   4382                 }
   4383             }
   4384         }
   4385     }
   4386 
   4387     private boolean clearIPv4Address(String iface) {
   4388         try {
   4389             InterfaceConfiguration ifcg = new InterfaceConfiguration();
   4390             ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
   4391             mNwService.setInterfaceConfig(iface, ifcg);
   4392             return true;
   4393         } catch (RemoteException e) {
   4394             return false;
   4395         }
   4396     }
   4397 
   4398     private boolean isProvisioned(LinkProperties lp) {
   4399         return lp.isProvisioned() ||
   4400                 (mWifiConfigStore.isUsingStaticIp(mLastNetworkId) && lp.hasIPv4Address());
   4401     }
   4402 
   4403     /**
   4404      * Creates a new LinkProperties object by merging information from various sources.
   4405      * <p/>
   4406      * This is needed because the information in mLinkProperties comes from multiple sources (DHCP,
   4407      * netlink, static configuration, ...). When one of these sources of information has updated
   4408      * link properties, we can't just assign them to mLinkProperties or we'd lose track of the
   4409      * information that came from other sources. Instead, when one of those sources has new
   4410      * information, we update the object that tracks the information from that source and then
   4411      * call this method to integrate the change into a new LinkProperties object for subsequent
   4412      * comparison with mLinkProperties.
   4413      * <p/>
   4414      * The information used to build LinkProperties is currently obtained as follows:
   4415      *     - Interface name: set in the constructor.
   4416      *     - IPv4 and IPv6 addresses: netlink, passed in by mNetlinkTracker.
   4417      *     - IPv4 routes, DNS servers, and domains: DHCP.
   4418      *     - IPv6 routes and DNS servers: netlink, passed in by mNetlinkTracker.
   4419      *     - HTTP proxy: the wifi config store.
   4420      */
   4421     private LinkProperties makeLinkProperties() {
   4422         LinkProperties newLp = new LinkProperties();
   4423 
   4424         // Interface name, proxy, and TCP buffer sizes are locally configured.
   4425         newLp.setInterfaceName(mInterfaceName);
   4426         newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId));
   4427         if (!TextUtils.isEmpty(mTcpBufferSizes)) {
   4428             newLp.setTcpBufferSizes(mTcpBufferSizes);
   4429         }
   4430 
   4431         // IPv4/v6 addresses, IPv6 routes and IPv6 DNS servers come from netlink.
   4432         LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
   4433         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
   4434         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
   4435             newLp.addRoute(route);
   4436         }
   4437         for (InetAddress dns : netlinkLinkProperties.getDnsServers()) {
   4438             // Only add likely reachable DNS servers.
   4439             // TODO: investigate deleting this.
   4440             if (newLp.isReachable(dns)) {
   4441                 newLp.addDnsServer(dns);
   4442             }
   4443         }
   4444 
   4445         // IPv4 routes, DNS servers and domains come from mDhcpResults.
   4446         synchronized (mDhcpResultsLock) {
   4447             // Even when we're using static configuration, we don't need to look at the config
   4448             // store, because static IP configuration also populates mDhcpResults.
   4449             if ((mDhcpResults != null)) {
   4450                 for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
   4451                     newLp.addRoute(route);
   4452                 }
   4453                 for (InetAddress dns : mDhcpResults.dnsServers) {
   4454                     // Only add likely reachable DNS servers.
   4455                     // TODO: investigate deleting this.
   4456                     if (newLp.isReachable(dns)) {
   4457                         newLp.addDnsServer(dns);
   4458                     }
   4459                 }
   4460                 newLp.setDomains(mDhcpResults.domains);
   4461             }
   4462         }
   4463 
   4464         return newLp;
   4465     }
   4466 
   4467     private void updateLinkProperties(int reason) {
   4468         LinkProperties newLp = makeLinkProperties();
   4469 
   4470         final boolean linkChanged = !newLp.equals(mLinkProperties);
   4471         final boolean wasProvisioned = isProvisioned(mLinkProperties);
   4472         final boolean isProvisioned = isProvisioned(newLp);
   4473         // TODO: Teach LinkProperties how to understand static assignment
   4474         // and simplify all this provisioning change detection logic by
   4475         // unifying it under LinkProperties.compareProvisioning().
   4476         final boolean lostProvisioning =
   4477                 (wasProvisioned && !isProvisioned) ||
   4478                 (mLinkProperties.hasIPv4Address() && !newLp.hasIPv4Address()) ||
   4479                 (mLinkProperties.isIPv6Provisioned() && !newLp.isIPv6Provisioned());
   4480         final DetailedState detailedState = getNetworkDetailedState();
   4481 
   4482         if (linkChanged) {
   4483             if (DBG) {
   4484                 log("Link configuration changed for netId: " + mLastNetworkId
   4485                         + " old: " + mLinkProperties + " new: " + newLp);
   4486             }
   4487             mLinkProperties = newLp;
   4488             if (mIpReachabilityMonitor != null) {
   4489                 mIpReachabilityMonitor.updateLinkProperties(mLinkProperties);
   4490             }
   4491             if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
   4492         }
   4493 
   4494         if (lostProvisioning) {
   4495             log("Lost IP layer provisioning!" +
   4496                     " was: " + mLinkProperties +
   4497                     " now: " + newLp);
   4498         }
   4499 
   4500         if (DBG) {
   4501             StringBuilder sb = new StringBuilder();
   4502             sb.append("updateLinkProperties nid: " + mLastNetworkId);
   4503             sb.append(" state: " + detailedState);
   4504             sb.append(" reason: " + smToString(reason));
   4505 
   4506             if (mLinkProperties != null) {
   4507                 if (mLinkProperties.hasIPv4Address()) {
   4508                     sb.append(" v4");
   4509                 }
   4510                 if (mLinkProperties.hasGlobalIPv6Address()) {
   4511                     sb.append(" v6");
   4512                 }
   4513                 if (mLinkProperties.hasIPv4DefaultRoute()) {
   4514                     sb.append(" v4r");
   4515                 }
   4516                 if (mLinkProperties.hasIPv6DefaultRoute()) {
   4517                     sb.append(" v6r");
   4518                 }
   4519                 if (mLinkProperties.hasIPv4DnsServer()) {
   4520                     sb.append(" v4dns");
   4521                 }
   4522                 if (mLinkProperties.hasIPv6DnsServer()) {
   4523                     sb.append(" v6dns");
   4524                 }
   4525                 if (isProvisioned) {
   4526                     sb.append(" isprov");
   4527                 }
   4528             }
   4529             logd(sb.toString());
   4530         }
   4531 
   4532         // If we just configured or lost IP configuration, do the needful.
   4533         // We don't just call handleSuccessfulIpConfiguration() or handleIpConfigurationLost()
   4534         // here because those should only be called if we're attempting to connect or already
   4535         // connected, whereas updateLinkProperties can be called at any time.
   4536         switch (reason) {
   4537             case DhcpStateMachine.DHCP_SUCCESS:
   4538             case CMD_STATIC_IP_SUCCESS:
   4539                 // IPv4 provisioning succeded. Advance to connected state.
   4540                 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
   4541                 if (!isProvisioned) {
   4542                     // Can never happen unless DHCP reports success but isProvisioned thinks the
   4543                     // resulting configuration is invalid (e.g., no IPv4 address, or the state in
   4544                     // mLinkProperties is out of sync with reality, or there's a bug in this code).
   4545                     // TODO: disconnect here instead. If our configuration is not usable, there's no
   4546                     // point in staying connected, and if mLinkProperties is out of sync with
   4547                     // reality, that will cause problems in the future.
   4548                     logd("IPv4 config succeeded, but not provisioned");
   4549                 }
   4550                 break;
   4551 
   4552             case DhcpStateMachine.DHCP_FAILURE:
   4553                 // DHCP failed. If we're not already provisioned, or we had IPv4 and now lost it,
   4554                 // give up and disconnect.
   4555                 // If we're already provisioned (e.g., IPv6-only network), stay connected.
   4556                 if (!isProvisioned || lostProvisioning) {
   4557                     sendMessage(CMD_IP_CONFIGURATION_LOST);
   4558                 } else {
   4559                     // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network).
   4560                     sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
   4561 
   4562                     // To be sure we don't get stuck with a non-working network if all we had is
   4563                     // IPv4, remove the IPv4 address from the interface (since we're using DHCP,
   4564                     // and DHCP failed). If we had an IPv4 address before, the deletion of the
   4565                     // address  will cause a CMD_UPDATE_LINKPROPERTIES. If the IPv4 address was
   4566                     // necessary for provisioning, its deletion will cause us to disconnect.
   4567                     //
   4568                     // This shouldn't be needed, because on an IPv4-only network a DHCP failure will
   4569                     // have empty DhcpResults and thus empty LinkProperties, and isProvisioned will
   4570                     // not return true if we're using DHCP and don't have an IPv4 default route. So
   4571                     // for now it's only here for extra redundancy. However, it will increase
   4572                     // robustness if we move to getting IPv4 routes from netlink as well.
   4573                     loge("DHCP failure: provisioned, clearing IPv4 address.");
   4574                     if (!clearIPv4Address(mInterfaceName)) {
   4575                         sendMessage(CMD_IP_CONFIGURATION_LOST);
   4576                     }
   4577                 }
   4578                 break;
   4579 
   4580             case CMD_STATIC_IP_FAILURE:
   4581                 // Static configuration was invalid, or an error occurred in applying it. Give up.
   4582                 sendMessage(CMD_IP_CONFIGURATION_LOST);
   4583                 break;
   4584 
   4585             case CMD_UPDATE_LINKPROPERTIES:
   4586                 // IP addresses, DNS servers, etc. changed. Act accordingly.
   4587                 if (lostProvisioning) {
   4588                     // We no longer have a usable network configuration. Disconnect.
   4589                     sendMessage(CMD_IP_CONFIGURATION_LOST);
   4590                 } else if (!wasProvisioned && isProvisioned) {
   4591                     // We have a usable IPv6-only config. Advance to connected state.
   4592                     sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
   4593                 }
   4594                 if (linkChanged && getNetworkDetailedState() == DetailedState.CONNECTED) {
   4595                     // If anything has changed and we're already connected, send out a notification.
   4596                     sendLinkConfigurationChangedBroadcast();
   4597                 }
   4598                 break;
   4599         }
   4600     }
   4601 
   4602     /**
   4603      * Clears all our link properties.
   4604      */
   4605     private void clearLinkProperties() {
   4606         // Clear the link properties obtained from DHCP and netlink.
   4607         synchronized (mDhcpResultsLock) {
   4608             if (mDhcpResults != null) {
   4609                 mDhcpResults.clear();
   4610             }
   4611         }
   4612         mNetlinkTracker.clearLinkProperties();
   4613         if (mIpReachabilityMonitor != null) {
   4614             mIpReachabilityMonitor.clearLinkProperties();
   4615         }
   4616 
   4617         // Now clear the merged link properties.
   4618         mLinkProperties.clear();
   4619         if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
   4620     }
   4621 
   4622     /**
   4623      * try to update default route MAC address.
   4624      */
   4625     private String updateDefaultRouteMacAddress(int timeout) {
   4626         String address = null;
   4627         for (RouteInfo route : mLinkProperties.getRoutes()) {
   4628             if (route.isDefaultRoute() && route.hasGateway()) {
   4629                 InetAddress gateway = route.getGateway();
   4630                 if (gateway instanceof Inet4Address) {
   4631                     if (PDBG) {
   4632                         logd("updateDefaultRouteMacAddress found Ipv4 default :"
   4633                                 + gateway.getHostAddress());
   4634                     }
   4635                     address = macAddressFromRoute(gateway.getHostAddress());
   4636                     /* The gateway's MAC address is known */
   4637                     if ((address == null) && (timeout > 0)) {
   4638                         boolean reachable = false;
   4639                         try {
   4640                             reachable = gateway.isReachable(timeout);
   4641                         } catch (Exception e) {
   4642                             loge("updateDefaultRouteMacAddress exception reaching :"
   4643                                     + gateway.getHostAddress());
   4644 
   4645                         } finally {
   4646                             if (reachable == true) {
   4647 
   4648                                 address = macAddressFromRoute(gateway.getHostAddress());
   4649                                 if (PDBG) {
   4650                                     logd("updateDefaultRouteMacAddress reachable (tried again) :"
   4651                                             + gateway.getHostAddress() + " found " + address);
   4652                                 }
   4653                             }
   4654                         }
   4655                     }
   4656                     if (address != null) {
   4657                         mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address);
   4658                     }
   4659                 }
   4660             }
   4661         }
   4662         return address;
   4663     }
   4664 
   4665     void sendScanResultsAvailableBroadcast(boolean scanSucceeded) {
   4666         Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
   4667         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   4668         intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, scanSucceeded);
   4669         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   4670     }
   4671 
   4672     private void sendRssiChangeBroadcast(final int newRssi) {
   4673         try {
   4674             mBatteryStats.noteWifiRssiChanged(newRssi);
   4675         } catch (RemoteException e) {
   4676             // Won't happen.
   4677         }
   4678         Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
   4679         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   4680         intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
   4681         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   4682     }
   4683 
   4684     private void sendNetworkStateChangeBroadcast(String bssid) {
   4685         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
   4686         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   4687         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
   4688         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
   4689         if (bssid != null)
   4690             intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
   4691         if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK ||
   4692                 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
   4693             // We no longer report MAC address to third-parties and our code does
   4694             // not rely on this broadcast, so just send the default MAC address.
   4695             WifiInfo sentWifiInfo = new WifiInfo(mWifiInfo);
   4696             sentWifiInfo.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
   4697             intent.putExtra(WifiManager.EXTRA_WIFI_INFO, sentWifiInfo);
   4698         }
   4699         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   4700     }
   4701 
   4702     private WifiInfo getWiFiInfoForUid(int uid) {
   4703         if (Binder.getCallingUid() == Process.myUid()) {
   4704             return mWifiInfo;
   4705         }
   4706 
   4707         WifiInfo result = new WifiInfo(mWifiInfo);
   4708         result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
   4709 
   4710         IBinder binder = ServiceManager.getService("package");
   4711         IPackageManager packageManager = IPackageManager.Stub.asInterface(binder);
   4712 
   4713         try {
   4714             if (packageManager.checkUidPermission(Manifest.permission.LOCAL_MAC_ADDRESS,
   4715                     uid) == PackageManager.PERMISSION_GRANTED) {
   4716                 result.setMacAddress(mWifiInfo.getMacAddress());
   4717             }
   4718         } catch (RemoteException e) {
   4719             Log.e(TAG, "Error checking receiver permission", e);
   4720         }
   4721 
   4722         return result;
   4723     }
   4724 
   4725     private void sendLinkConfigurationChangedBroadcast() {
   4726         Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
   4727         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   4728         intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
   4729         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   4730     }
   4731 
   4732     private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
   4733         Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
   4734         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   4735         intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
   4736         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   4737     }
   4738 
   4739     /**
   4740      * Record the detailed state of a network.
   4741      *
   4742      * @param state the new {@code DetailedState}
   4743      */
   4744     private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {
   4745         boolean hidden = false;
   4746 
   4747         if (linkDebouncing || isRoaming()) {
   4748             // There is generally a confusion in the system about colluding
   4749             // WiFi Layer 2 state (as reported by supplicant) and the Network state
   4750             // which leads to multiple confusion.
   4751             //
   4752             // If link is de-bouncing or roaming, we already have an IP address
   4753             // as well we were connected and are doing L2 cycles of
   4754             // reconnecting or renewing IP address to check that we still have it
   4755             // This L2 link flapping should ne be reflected into the Network state
   4756             // which is the state of the WiFi Network visible to Layer 3 and applications
   4757             // Note that once debouncing and roaming are completed, we will
   4758             // set the Network state to where it should be, or leave it as unchanged
   4759             //
   4760             hidden = true;
   4761         }
   4762         if (DBG) {
   4763             log("setDetailed state, old ="
   4764                     + mNetworkInfo.getDetailedState() + " and new state=" + state
   4765                     + " hidden=" + hidden);
   4766         }
   4767         if (mNetworkInfo.getExtraInfo() != null && mWifiInfo.getSSID() != null) {
   4768             // Always indicate that SSID has changed
   4769             if (!mNetworkInfo.getExtraInfo().equals(mWifiInfo.getSSID())) {
   4770                 if (DBG) {
   4771                     log("setDetailed state send new extra info" + mWifiInfo.getSSID());
   4772                 }
   4773                 mNetworkInfo.setExtraInfo(mWifiInfo.getSSID());
   4774                 sendNetworkStateChangeBroadcast(null);
   4775             }
   4776         }
   4777         if (hidden == true) {
   4778             return false;
   4779         }
   4780 
   4781         if (state != mNetworkInfo.getDetailedState()) {
   4782             mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());
   4783             if (mNetworkAgent != null) {
   4784                 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   4785             }
   4786             sendNetworkStateChangeBroadcast(null);
   4787             return true;
   4788         }
   4789         return false;
   4790     }
   4791 
   4792     private DetailedState getNetworkDetailedState() {
   4793         return mNetworkInfo.getDetailedState();
   4794     }
   4795 
   4796     private SupplicantState handleSupplicantStateChange(Message message) {
   4797         StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   4798         SupplicantState state = stateChangeResult.state;
   4799         // Supplicant state change
   4800         // [31-13] Reserved for future use
   4801         // [8 - 0] Supplicant state (as defined in SupplicantState.java)
   4802         // 50023 supplicant_state_changed (custom|1|5)
   4803         mWifiInfo.setSupplicantState(state);
   4804         // Network id is only valid when we start connecting
   4805         if (SupplicantState.isConnecting(state)) {
   4806             mWifiInfo.setNetworkId(stateChangeResult.networkId);
   4807         } else {
   4808             mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
   4809         }
   4810 
   4811         mWifiInfo.setBSSID(stateChangeResult.BSSID);
   4812 
   4813         if (mWhiteListedSsids != null
   4814                 && mWhiteListedSsids.length > 0
   4815                 && stateChangeResult.wifiSsid != null) {
   4816             String SSID = stateChangeResult.wifiSsid.toString();
   4817             String currentSSID = mWifiInfo.getSSID();
   4818             if (SSID != null
   4819                     && currentSSID != null
   4820                     && !SSID.equals(WifiSsid.NONE)) {
   4821                     // Remove quote before comparing
   4822                     if (SSID.length() >= 2 && SSID.charAt(0) == '"'
   4823                             && SSID.charAt(SSID.length() - 1) == '"')
   4824                     {
   4825                         SSID = SSID.substring(1, SSID.length() - 1);
   4826                     }
   4827                     if (currentSSID.length() >= 2 && currentSSID.charAt(0) == '"'
   4828                             && currentSSID.charAt(currentSSID.length() - 1) == '"') {
   4829                         currentSSID = currentSSID.substring(1, currentSSID.length() - 1);
   4830                     }
   4831                     if ((!SSID.equals(currentSSID)) && (getCurrentState() == mConnectedState)) {
   4832                         lastConnectAttemptTimestamp = System.currentTimeMillis();
   4833                         targetWificonfiguration
   4834                             = mWifiConfigStore.getWifiConfiguration(mWifiInfo.getNetworkId());
   4835                         transitionTo(mRoamingState);
   4836                     }
   4837              }
   4838         }
   4839 
   4840         mWifiInfo.setSSID(stateChangeResult.wifiSsid);
   4841         mWifiInfo.setEphemeral(mWifiConfigStore.isEphemeral(mWifiInfo.getNetworkId()));
   4842 
   4843         mSupplicantStateTracker.sendMessage(Message.obtain(message));
   4844 
   4845         return state;
   4846     }
   4847 
   4848     /**
   4849      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
   4850      * using the interface, stopping DHCP & disabling interface
   4851      */
   4852     private void handleNetworkDisconnect() {
   4853         if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP"
   4854                 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
   4855                 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
   4856                 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
   4857                 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
   4858 
   4859 
   4860         clearCurrentConfigBSSID("handleNetworkDisconnect");
   4861 
   4862         stopDhcp();
   4863 
   4864         try {
   4865             mNwService.clearInterfaceAddresses(mInterfaceName);
   4866             mNwService.disableIpv6(mInterfaceName);
   4867         } catch (Exception e) {
   4868             loge("Failed to clear addresses or disable ipv6" + e);
   4869         }
   4870 
   4871         /* Reset data structures */
   4872         mBadLinkspeedcount = 0;
   4873         mWifiInfo.reset();
   4874         linkDebouncing = false;
   4875         /* Reset roaming parameters */
   4876         mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
   4877 
   4878         /**
   4879          *  fullBandConnectedTimeIntervalMilli:
   4880          *  - start scans at mWifiConfigStore.wifiAssociatedShortScanIntervalMilli seconds interval
   4881          *  - exponentially increase to mWifiConfigStore.associatedFullScanMaxIntervalMilli
   4882          *  Initialize to sane value = 20 seconds
   4883          */
   4884         fullBandConnectedTimeIntervalMilli = 20 * 1000;
   4885 
   4886         setNetworkDetailedState(DetailedState.DISCONNECTED);
   4887         if (mNetworkAgent != null) {
   4888             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   4889             mNetworkAgent = null;
   4890         }
   4891         mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
   4892 
   4893         /* Clear network properties */
   4894         clearLinkProperties();
   4895 
   4896         /* Cend event to CM & network change broadcast */
   4897         sendNetworkStateChangeBroadcast(mLastBssid);
   4898 
   4899         /* Cancel auto roam requests */
   4900         autoRoamSetBSSID(mLastNetworkId, "any");
   4901 
   4902         mLastBssid = null;
   4903         registerDisconnected();
   4904         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
   4905     }
   4906 
   4907     private void handleSupplicantConnectionLoss(boolean killSupplicant) {
   4908         /* Socket connection can be lost when we do a graceful shutdown
   4909         * or when the driver is hung. Ensure supplicant is stopped here.
   4910         */
   4911         if (killSupplicant) {
   4912             mWifiMonitor.killSupplicant(mP2pSupported);
   4913         }
   4914         mWifiNative.closeSupplicantConnection();
   4915         sendSupplicantConnectionChangedBroadcast(false);
   4916         setWifiState(WIFI_STATE_DISABLED);
   4917     }
   4918 
   4919     void handlePreDhcpSetup() {
   4920         mDhcpActive = true;
   4921         if (!mBluetoothConnectionActive) {
   4922             /*
   4923              * There are problems setting the Wi-Fi driver's power
   4924              * mode to active when bluetooth coexistence mode is
   4925              * enabled or sense.
   4926              * <p>
   4927              * We set Wi-Fi to active mode when
   4928              * obtaining an IP address because we've found
   4929              * compatibility issues with some routers with low power
   4930              * mode.
   4931              * <p>
   4932              * In order for this active power mode to properly be set,
   4933              * we disable coexistence mode until we're done with
   4934              * obtaining an IP address.  One exception is if we
   4935              * are currently connected to a headset, since disabling
   4936              * coexistence would interrupt that connection.
   4937              */
   4938             // Disable the coexistence mode
   4939             mWifiNative.setBluetoothCoexistenceMode(
   4940                     mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
   4941         }
   4942 
   4943         // Disable power save and suspend optimizations during DHCP
   4944         // Note: The order here is important for now. Brcm driver changes
   4945         // power settings when we control suspend mode optimizations.
   4946         // TODO: Remove this comment when the driver is fixed.
   4947         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
   4948         mWifiNative.setPowerSave(false);
   4949 
   4950         // Update link layer stats
   4951         getWifiLinkLayerStats(false);
   4952 
   4953         /* P2p discovery breaks dhcp, shut it down in order to get through this */
   4954         Message msg = new Message();
   4955         msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY;
   4956         msg.arg1 = WifiP2pServiceImpl.ENABLED;
   4957         msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE;
   4958         msg.obj = mDhcpStateMachine;
   4959         mWifiP2pChannel.sendMessage(msg);
   4960     }
   4961 
   4962 
   4963     private boolean useLegacyDhcpClient() {
   4964         return Settings.Global.getInt(
   4965                 mContext.getContentResolver(),
   4966                 Settings.Global.LEGACY_DHCP_CLIENT, 0) == 1;
   4967     }
   4968 
   4969     private void maybeInitDhcpStateMachine() {
   4970         if (mDhcpStateMachine == null) {
   4971             if (useLegacyDhcpClient()) {
   4972                 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
   4973                         mContext, WifiStateMachine.this, mInterfaceName);
   4974             } else {
   4975                 mDhcpStateMachine = DhcpClient.makeDhcpStateMachine(
   4976                         mContext, WifiStateMachine.this, mInterfaceName);
   4977             }
   4978         }
   4979     }
   4980 
   4981     void startDhcp() {
   4982         maybeInitDhcpStateMachine();
   4983         mDhcpStateMachine.registerForPreDhcpNotification();
   4984         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
   4985     }
   4986 
   4987     void renewDhcp() {
   4988         maybeInitDhcpStateMachine();
   4989         mDhcpStateMachine.registerForPreDhcpNotification();
   4990         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP);
   4991     }
   4992 
   4993     void stopDhcp() {
   4994         if (mDhcpStateMachine != null) {
   4995             /* In case we were in middle of DHCP operation restore back powermode */
   4996             handlePostDhcpSetup();
   4997             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
   4998         }
   4999     }
   5000 
   5001     void handlePostDhcpSetup() {
   5002         /* Restore power save and suspend optimizations */
   5003         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
   5004         mWifiNative.setPowerSave(true);
   5005 
   5006         mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED);
   5007 
   5008         // Set the coexistence mode back to its default value
   5009         mWifiNative.setBluetoothCoexistenceMode(
   5010                 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
   5011 
   5012         mDhcpActive = false;
   5013     }
   5014 
   5015     void connectScanningService() {
   5016 
   5017         if (mWifiScanner == null) {
   5018             mWifiScanner = (WifiScanner) mContext.getSystemService(Context.WIFI_SCANNING_SERVICE);
   5019         }
   5020     }
   5021 
   5022     private void handleIPv4Success(DhcpResults dhcpResults, int reason) {
   5023 
   5024         if (PDBG) {
   5025             logd("handleIPv4Success <" + dhcpResults.toString() + ">");
   5026             logd("link address " + dhcpResults.ipAddress);
   5027         }
   5028 
   5029         Inet4Address addr;
   5030         synchronized (mDhcpResultsLock) {
   5031             mDhcpResults = dhcpResults;
   5032             addr = (Inet4Address) dhcpResults.ipAddress.getAddress();
   5033         }
   5034 
   5035         if (isRoaming()) {
   5036             int previousAddress = mWifiInfo.getIpAddress();
   5037             int newAddress = NetworkUtils.inetAddressToInt(addr);
   5038             if (previousAddress != newAddress) {
   5039                 logd("handleIPv4Success, roaming and address changed" +
   5040                         mWifiInfo + " got: " + addr);
   5041             }
   5042         }
   5043         mWifiInfo.setInetAddress(addr);
   5044         mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
   5045         updateLinkProperties(reason);
   5046     }
   5047 
   5048     private void handleSuccessfulIpConfiguration() {
   5049         mLastSignalLevel = -1; // Force update of signal strength
   5050         WifiConfiguration c = getCurrentWifiConfiguration();
   5051         if (c != null) {
   5052             // Reset IP failure tracking
   5053             c.numConnectionFailures = 0;
   5054 
   5055             // Tell the framework whether the newly connected network is trusted or untrusted.
   5056             updateCapabilities(c);
   5057         }
   5058         if (c != null) {
   5059             ScanResult result = getCurrentScanResult();
   5060             if (result == null) {
   5061                 logd("WifiStateMachine: handleSuccessfulIpConfiguration and no scan results" +
   5062                         c.configKey());
   5063             } else {
   5064                 // Clear the per BSSID failure count
   5065                 result.numIpConfigFailures = 0;
   5066                 // Clear the WHOLE BSSID blacklist, which means supplicant is free to retry
   5067                 // any BSSID, even though it may already have a non zero ip failure count,
   5068                 // this will typically happen if the user walks away and come back to his arrea
   5069                 // TODO: implement blacklisting based on a timer, i.e. keep BSSID blacklisted
   5070                 // in supplicant for a couple of hours or a day
   5071                 mWifiConfigStore.clearBssidBlacklist();
   5072             }
   5073         }
   5074     }
   5075 
   5076     private void handleIPv4Failure(int reason) {
   5077         synchronized(mDhcpResultsLock) {
   5078              if (mDhcpResults != null) {
   5079                  mDhcpResults.clear();
   5080              }
   5081         }
   5082         if (PDBG) {
   5083             logd("handleIPv4Failure");
   5084         }
   5085         updateLinkProperties(reason);
   5086     }
   5087 
   5088     private void handleIpConfigurationLost() {
   5089         mWifiInfo.setInetAddress(null);
   5090         mWifiInfo.setMeteredHint(false);
   5091 
   5092         mWifiConfigStore.handleSSIDStateChange(mLastNetworkId, false,
   5093                 "DHCP FAILURE", mWifiInfo.getBSSID());
   5094 
   5095         /* DHCP times out after about 30 seconds, we do a
   5096          * disconnect thru supplicant, we will let autojoin retry connecting to the network
   5097          */
   5098         mWifiNative.disconnect();
   5099     }
   5100 
   5101     // TODO: De-duplicated this and handleIpConfigurationLost().
   5102     private void handleIpReachabilityLost() {
   5103         // No need to be told about any additional neighbors that might also
   5104         // become unreachable--quiet them now while we start disconnecting.
   5105         if (mIpReachabilityMonitor != null) {
   5106             mIpReachabilityMonitor.clearLinkProperties();
   5107         }
   5108 
   5109         mWifiInfo.setInetAddress(null);
   5110         mWifiInfo.setMeteredHint(false);
   5111 
   5112         // TODO: Determine whether to call some form of mWifiConfigStore.handleSSIDStateChange().
   5113 
   5114         // Disconnect via supplicant, and let autojoin retry connecting to the network.
   5115         mWifiNative.disconnect();
   5116     }
   5117 
   5118     private int convertFrequencyToChannelNumber(int frequency) {
   5119         if (frequency >= 2412 && frequency <= 2484) {
   5120             return (frequency -2412) / 5 + 1;
   5121         } else if (frequency >= 5170  &&  frequency <=5825) {
   5122             //DFS is included
   5123             return (frequency -5170) / 5 + 34;
   5124         } else {
   5125             return 0;
   5126         }
   5127     }
   5128 
   5129     private int chooseApChannel(int apBand) {
   5130         int apChannel;
   5131         int[] channel;
   5132 
   5133         if (apBand == 0)  {
   5134             if (mWifiApConfigStore.allowed2GChannel == null ||
   5135                     mWifiApConfigStore.allowed2GChannel.size() == 0) {
   5136                 //most safe channel to use
   5137                 if(DBG) {
   5138                     Log.d(TAG, "No specified 2G allowed channel list");
   5139                 }
   5140                 apChannel = 6;
   5141             } else {
   5142                 int index = mRandom.nextInt(mWifiApConfigStore.allowed2GChannel.size());
   5143                 apChannel = mWifiApConfigStore.allowed2GChannel.get(index).intValue();
   5144             }
   5145         } else {
   5146             //5G without DFS
   5147             channel = mWifiNative.getChannelsForBand(2);
   5148             if (channel != null && channel.length > 0) {
   5149                 apChannel = channel[mRandom.nextInt(channel.length)];
   5150                 apChannel = convertFrequencyToChannelNumber(apChannel);
   5151             } else {
   5152                 Log.e(TAG, "SoftAp do not get available channel list");
   5153                 apChannel = 0;
   5154             }
   5155         }
   5156 
   5157         if(DBG) {
   5158             Log.d(TAG, "SoftAp set on channel " + apChannel);
   5159         }
   5160 
   5161         return apChannel;
   5162     }
   5163 
   5164     /* SoftAP configuration */
   5165     private boolean enableSoftAp() {
   5166         if (WifiNative.getInterfaces() != 0) {
   5167             if (!mWifiNative.toggleInterface(0)) {
   5168                 if (DBG) Log.e(TAG, "toggleInterface failed");
   5169                 return false;
   5170             }
   5171         } else {
   5172             if (DBG) Log.d(TAG, "No interfaces to toggle");
   5173         }
   5174 
   5175         try {
   5176             mNwService.wifiFirmwareReload(mInterfaceName, "AP");
   5177             if (DBG) Log.d(TAG, "Firmware reloaded in AP mode");
   5178         } catch (Exception e) {
   5179             Log.e(TAG, "Failed to reload AP firmware " + e);
   5180         }
   5181 
   5182         if (WifiNative.startHal() == false) {
   5183             /* starting HAL is optional */
   5184             Log.e(TAG, "Failed to start HAL");
   5185         }
   5186         return true;
   5187     }
   5188 
   5189     /* Current design is to not set the config on a running hostapd but instead
   5190      * stop and start tethering when user changes config on a running access point
   5191      *
   5192      * TODO: Add control channel setup through hostapd that allows changing config
   5193      * on a running daemon
   5194      */
   5195     private void startSoftApWithConfig(final WifiConfiguration configuration) {
   5196         // set channel
   5197         final WifiConfiguration config = new WifiConfiguration(configuration);
   5198 
   5199         if (DBG) {
   5200             Log.d(TAG, "SoftAp config channel is: " + config.apChannel);
   5201         }
   5202 
   5203         //We need HAL support to set country code and get available channel list, if HAL is
   5204         //not available, like razor, we regress to original implementaion (2GHz, channel 6)
   5205         if (mWifiNative.isHalStarted()) {
   5206             //set country code through HAL Here
   5207             if (mSetCountryCode != null) {
   5208                 if (!mWifiNative.setCountryCodeHal(mSetCountryCode.toUpperCase(Locale.ROOT))) {
   5209                     if (config.apBand != 0) {
   5210                         Log.e(TAG, "Fail to set country code. Can not setup Softap on 5GHz");
   5211                         //countrycode is mandatory for 5GHz
   5212                         sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
   5213                         return;
   5214                     }
   5215                 }
   5216             } else {
   5217                 if (config.apBand != 0) {
   5218                     //countrycode is mandatory for 5GHz
   5219                     Log.e(TAG, "Can not setup softAp on 5GHz without country code!");
   5220                     sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
   5221                     return;
   5222                 }
   5223             }
   5224 
   5225             if (config.apChannel == 0) {
   5226                 config.apChannel = chooseApChannel(config.apBand);
   5227                 if (config.apChannel == 0) {
   5228                     if(mWifiNative.isGetChannelsForBandSupported()) {
   5229                         //fail to get available channel
   5230                         sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_NO_CHANNEL);
   5231                         return;
   5232                     } else {
   5233                         //for some old device, wifiHal may not be supportedget valid channels are not
   5234                         //supported
   5235                         config.apBand = 0;
   5236                         config.apChannel = 6;
   5237                     }
   5238                 }
   5239             }
   5240         } else {
   5241             //for some old device, wifiHal may not be supported
   5242             config.apBand = 0;
   5243             config.apChannel = 6;
   5244         }
   5245         // Start hostapd on a separate thread
   5246         new Thread(new Runnable() {
   5247             public void run() {
   5248                 try {
   5249                     mNwService.startAccessPoint(config, mInterfaceName);
   5250                 } catch (Exception e) {
   5251                     loge("Exception in softap start " + e);
   5252                     try {
   5253                         mNwService.stopAccessPoint(mInterfaceName);
   5254                         mNwService.startAccessPoint(config, mInterfaceName);
   5255                     } catch (Exception e1) {
   5256                         loge("Exception in softap re-start " + e1);
   5257                         sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
   5258                         return;
   5259                     }
   5260                 }
   5261                 if (DBG) log("Soft AP start successful");
   5262                 sendMessage(CMD_START_AP_SUCCESS);
   5263             }
   5264         }).start();
   5265     }
   5266 
   5267     /*
   5268      * Read a MAC address in /proc/arp/table, used by WifistateMachine
   5269      * so as to record MAC address of default gateway.
   5270      **/
   5271     private String macAddressFromRoute(String ipAddress) {
   5272         String macAddress = null;
   5273         BufferedReader reader = null;
   5274         try {
   5275             reader = new BufferedReader(new FileReader("/proc/net/arp"));
   5276 
   5277             // Skip over the line bearing colum titles
   5278             String line = reader.readLine();
   5279 
   5280             while ((line = reader.readLine()) != null) {
   5281                 String[] tokens = line.split("[ ]+");
   5282                 if (tokens.length < 6) {
   5283                     continue;
   5284                 }
   5285 
   5286                 // ARP column format is
   5287                 // Address HWType HWAddress Flags Mask IFace
   5288                 String ip = tokens[0];
   5289                 String mac = tokens[3];
   5290 
   5291                 if (ipAddress.equals(ip)) {
   5292                     macAddress = mac;
   5293                     break;
   5294                 }
   5295             }
   5296 
   5297             if (macAddress == null) {
   5298                 loge("Did not find remoteAddress {" + ipAddress + "} in " +
   5299                         "/proc/net/arp");
   5300             }
   5301 
   5302         } catch (FileNotFoundException e) {
   5303             loge("Could not open /proc/net/arp to lookup mac address");
   5304         } catch (IOException e) {
   5305             loge("Could not read /proc/net/arp to lookup mac address");
   5306         } finally {
   5307             try {
   5308                 if (reader != null) {
   5309                     reader.close();
   5310                 }
   5311             } catch (IOException e) {
   5312                 // Do nothing
   5313             }
   5314         }
   5315         return macAddress;
   5316 
   5317     }
   5318 
   5319     private class WifiNetworkFactory extends NetworkFactory {
   5320         public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) {
   5321             super(l, c, TAG, f);
   5322         }
   5323 
   5324         @Override
   5325         protected void needNetworkFor(NetworkRequest networkRequest, int score) {
   5326             ++mConnectionRequests;
   5327         }
   5328 
   5329         @Override
   5330         protected void releaseNetworkFor(NetworkRequest networkRequest) {
   5331             --mConnectionRequests;
   5332         }
   5333 
   5334         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   5335             pw.println("mConnectionRequests " + mConnectionRequests);
   5336         }
   5337 
   5338     }
   5339 
   5340     private class UntrustedWifiNetworkFactory extends NetworkFactory {
   5341         private int mUntrustedReqCount;
   5342 
   5343         public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) {
   5344             super(l, c, tag, f);
   5345         }
   5346 
   5347         @Override
   5348         protected void needNetworkFor(NetworkRequest networkRequest, int score) {
   5349             if (!networkRequest.networkCapabilities.hasCapability(
   5350                     NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
   5351                 if (++mUntrustedReqCount == 1) {
   5352                     mWifiAutoJoinController.setAllowUntrustedConnections(true);
   5353                 }
   5354             }
   5355         }
   5356 
   5357         @Override
   5358         protected void releaseNetworkFor(NetworkRequest networkRequest) {
   5359             if (!networkRequest.networkCapabilities.hasCapability(
   5360                     NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
   5361                 if (--mUntrustedReqCount == 0) {
   5362                     mWifiAutoJoinController.setAllowUntrustedConnections(false);
   5363                 }
   5364             }
   5365         }
   5366 
   5367         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   5368             pw.println("mUntrustedReqCount " + mUntrustedReqCount);
   5369         }
   5370     }
   5371 
   5372     void maybeRegisterNetworkFactory() {
   5373         if (mNetworkFactory == null) {
   5374             checkAndSetConnectivityInstance();
   5375             if (mCm != null) {
   5376                 mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext,
   5377                         NETWORKTYPE, mNetworkCapabilitiesFilter);
   5378                 mNetworkFactory.setScoreFilter(60);
   5379                 mNetworkFactory.register();
   5380 
   5381                 // We can't filter untrusted network in the capabilities filter because a trusted
   5382                 // network would still satisfy a request that accepts untrusted ones.
   5383                 mUntrustedNetworkFactory = new UntrustedWifiNetworkFactory(getHandler().getLooper(),
   5384                         mContext, NETWORKTYPE_UNTRUSTED, mNetworkCapabilitiesFilter);
   5385                 mUntrustedNetworkFactory.setScoreFilter(Integer.MAX_VALUE);
   5386                 mUntrustedNetworkFactory.register();
   5387             }
   5388         }
   5389     }
   5390 
   5391     /********************************************************
   5392      * HSM states
   5393      *******************************************************/
   5394 
   5395     class DefaultState extends State {
   5396         @Override
   5397         public boolean processMessage(Message message) {
   5398             logStateAndMessage(message, getClass().getSimpleName());
   5399 
   5400             switch (message.what) {
   5401                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
   5402                     AsyncChannel ac = (AsyncChannel) message.obj;
   5403                     if (ac == mWifiP2pChannel) {
   5404                         if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
   5405                             mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
   5406                         } else {
   5407                             loge("WifiP2pService connection failure, error=" + message.arg1);
   5408                         }
   5409                     } else {
   5410                         loge("got HALF_CONNECTED for unknown channel");
   5411                     }
   5412                     break;
   5413                 }
   5414                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
   5415                     AsyncChannel ac = (AsyncChannel) message.obj;
   5416                     if (ac == mWifiP2pChannel) {
   5417                         loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
   5418                         //TODO: Re-establish connection to state machine after a delay
   5419                         // mWifiP2pChannel.connect(mContext, getHandler(),
   5420                         // mWifiP2pManager.getMessenger());
   5421                     }
   5422                     break;
   5423                 }
   5424                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
   5425                     mBluetoothConnectionActive = (message.arg1 !=
   5426                             BluetoothAdapter.STATE_DISCONNECTED);
   5427                     break;
   5428                     /* Synchronous call returns */
   5429                 case CMD_PING_SUPPLICANT:
   5430                 case CMD_ENABLE_NETWORK:
   5431                 case CMD_ADD_OR_UPDATE_NETWORK:
   5432                 case CMD_REMOVE_NETWORK:
   5433                 case CMD_SAVE_CONFIG:
   5434                     replyToMessage(message, message.what, FAILURE);
   5435                     break;
   5436                 case CMD_GET_CAPABILITY_FREQ:
   5437                     replyToMessage(message, message.what, null);
   5438                     break;
   5439                 case CMD_GET_CONFIGURED_NETWORKS:
   5440                     replyToMessage(message, message.what, (List<WifiConfiguration>) null);
   5441                     break;
   5442                 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
   5443                     replyToMessage(message, message.what, (List<WifiConfiguration>) null);
   5444                     break;
   5445                 case CMD_ENABLE_RSSI_POLL:
   5446                     mEnableRssiPolling = (message.arg1 == 1);
   5447                     break;
   5448                 case CMD_SET_HIGH_PERF_MODE:
   5449                     if (message.arg1 == 1) {
   5450                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);
   5451                     } else {
   5452                         setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);
   5453                     }
   5454                     break;
   5455                 case CMD_BOOT_COMPLETED:
   5456                     maybeRegisterNetworkFactory();
   5457                     break;
   5458                 case CMD_SCREEN_STATE_CHANGED:
   5459                     handleScreenStateChanged(message.arg1 != 0);
   5460                     break;
   5461                     /* Discard */
   5462                 case CMD_START_SCAN:
   5463                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   5464                     break;
   5465                 case CMD_START_SUPPLICANT:
   5466                 case CMD_STOP_SUPPLICANT:
   5467                 case CMD_STOP_SUPPLICANT_FAILED:
   5468                 case CMD_START_DRIVER:
   5469                 case CMD_STOP_DRIVER:
   5470                 case CMD_DELAYED_STOP_DRIVER:
   5471                 case CMD_DRIVER_START_TIMED_OUT:
   5472                 case CMD_START_AP:
   5473                 case CMD_START_AP_SUCCESS:
   5474                 case CMD_START_AP_FAILURE:
   5475                 case CMD_STOP_AP:
   5476                 case CMD_TETHER_STATE_CHANGE:
   5477                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   5478                 case CMD_DISCONNECT:
   5479                 case CMD_RECONNECT:
   5480                 case CMD_REASSOCIATE:
   5481                 case CMD_RELOAD_TLS_AND_RECONNECT:
   5482                 case WifiMonitor.SUP_CONNECTION_EVENT:
   5483                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   5484                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   5485                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   5486                 case WifiMonitor.SCAN_RESULTS_EVENT:
   5487                 case WifiMonitor.SCAN_FAILED_EVENT:
   5488                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   5489                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   5490                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   5491                 case WifiMonitor.WPS_OVERLAP_EVENT:
   5492                 case CMD_BLACKLIST_NETWORK:
   5493                 case CMD_CLEAR_BLACKLIST:
   5494                 case CMD_SET_OPERATIONAL_MODE:
   5495                 case CMD_SET_COUNTRY_CODE:
   5496                 case CMD_SET_FREQUENCY_BAND:
   5497                 case CMD_RSSI_POLL:
   5498                 case CMD_ENABLE_ALL_NETWORKS:
   5499                 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   5500                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   5501                 /* Handled by WifiApConfigStore */
   5502                 case CMD_SET_AP_CONFIG:
   5503                 case CMD_SET_AP_CONFIG_COMPLETED:
   5504                 case CMD_REQUEST_AP_CONFIG:
   5505                 case CMD_RESPONSE_AP_CONFIG:
   5506                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
   5507                 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
   5508                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
   5509                 case CMD_DISABLE_P2P_RSP:
   5510                 case WifiMonitor.SUP_REQUEST_IDENTITY:
   5511                 case CMD_TEST_NETWORK_DISCONNECT:
   5512                 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
   5513                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
   5514                 case CMD_TARGET_BSSID:
   5515                 case CMD_AUTO_CONNECT:
   5516                 case CMD_AUTO_ROAM:
   5517                 case CMD_AUTO_SAVE_NETWORK:
   5518                 case CMD_ASSOCIATED_BSSID:
   5519                 case CMD_UNWANTED_NETWORK:
   5520                 case CMD_DISCONNECTING_WATCHDOG_TIMER:
   5521                 case CMD_ROAM_WATCHDOG_TIMER:
   5522                 case CMD_DISABLE_EPHEMERAL_NETWORK:
   5523                 case CMD_RESTART_AUTOJOIN_OFFLOAD:
   5524                 case CMD_STARTED_PNO_DBG:
   5525                 case CMD_STARTED_GSCAN_DBG:
   5526                 case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
   5527                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   5528                     break;
   5529                 case DhcpStateMachine.CMD_ON_QUIT:
   5530                     mDhcpStateMachine = null;
   5531                     break;
   5532                 case CMD_SET_SUSPEND_OPT_ENABLED:
   5533                     if (message.arg1 == 1) {
   5534                         mSuspendWakeLock.release();
   5535                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true);
   5536                     } else {
   5537                         setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false);
   5538                     }
   5539                     break;
   5540                 case WifiMonitor.DRIVER_HUNG_EVENT:
   5541                     setSupplicantRunning(false);
   5542                     setSupplicantRunning(true);
   5543                     break;
   5544                 case WifiManager.CONNECT_NETWORK:
   5545                     replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   5546                             WifiManager.BUSY);
   5547                     break;
   5548                 case WifiManager.FORGET_NETWORK:
   5549                     replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
   5550                             WifiManager.BUSY);
   5551                     break;
   5552                 case WifiManager.SAVE_NETWORK:
   5553                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   5554                     replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
   5555                             WifiManager.BUSY);
   5556                     break;
   5557                 case WifiManager.START_WPS:
   5558                     replyToMessage(message, WifiManager.WPS_FAILED,
   5559                             WifiManager.BUSY);
   5560                     break;
   5561                 case WifiManager.CANCEL_WPS:
   5562                     replyToMessage(message, WifiManager.CANCEL_WPS_FAILED,
   5563                             WifiManager.BUSY);
   5564                     break;
   5565                 case WifiManager.DISABLE_NETWORK:
   5566                     replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
   5567                             WifiManager.BUSY);
   5568                     break;
   5569                 case WifiManager.RSSI_PKTCNT_FETCH:
   5570                     replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED,
   5571                             WifiManager.BUSY);
   5572                     break;
   5573                 case CMD_GET_SUPPORTED_FEATURES:
   5574                     int featureSet = WifiNative.getSupportedFeatureSet();
   5575                     replyToMessage(message, message.what, featureSet);
   5576                     break;
   5577                 case CMD_FIRMWARE_ALERT:
   5578                     if (mWifiLogger != null) {
   5579                         byte[] buffer = (byte[])message.obj;
   5580                         mWifiLogger.captureAlertData(message.arg1, buffer);
   5581                     }
   5582                     break;
   5583                 case CMD_GET_LINK_LAYER_STATS:
   5584                     // Not supported hence reply with error message
   5585                     replyToMessage(message, message.what, null);
   5586                     break;
   5587                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
   5588                     NetworkInfo info = (NetworkInfo) message.obj;
   5589                     mP2pConnected.set(info.isConnected());
   5590                     break;
   5591                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
   5592                     mTemporarilyDisconnectWifi = (message.arg1 == 1);
   5593                     replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
   5594                     break;
   5595                 /* Link configuration (IP address, DNS, ...) changes notified via netlink */
   5596                 case CMD_UPDATE_LINKPROPERTIES:
   5597                     updateLinkProperties(CMD_UPDATE_LINKPROPERTIES);
   5598                     break;
   5599                 case CMD_GET_MATCHING_CONFIG:
   5600                     replyToMessage(message, message.what);
   5601                     break;
   5602                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
   5603                 case CMD_IP_CONFIGURATION_LOST:
   5604                 case CMD_IP_REACHABILITY_LOST:
   5605                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   5606                     break;
   5607                 case CMD_GET_CONNECTION_STATISTICS:
   5608                     replyToMessage(message, message.what, mWifiConnectionStatistics);
   5609                     break;
   5610                 case CMD_REMOVE_APP_CONFIGURATIONS:
   5611                     deferMessage(message);
   5612                     break;
   5613                 case CMD_REMOVE_USER_CONFIGURATIONS:
   5614                     deferMessage(message);
   5615                     break;
   5616                 default:
   5617                     loge("Error! unhandled message" + message);
   5618                     break;
   5619             }
   5620             return HANDLED;
   5621         }
   5622     }
   5623 
   5624     class InitialState extends State {
   5625         @Override
   5626         public void enter() {
   5627             WifiNative.stopHal();
   5628             mWifiNative.unloadDriver();
   5629             if (mWifiP2pChannel == null) {
   5630                 mWifiP2pChannel = new AsyncChannel();
   5631                 mWifiP2pChannel.connect(mContext, getHandler(),
   5632                     mWifiP2pServiceImpl.getP2pStateMachineMessenger());
   5633             }
   5634 
   5635             if (mWifiApConfigChannel == null) {
   5636                 mWifiApConfigChannel = new AsyncChannel();
   5637                 mWifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
   5638                         mContext, getHandler());
   5639                 mWifiApConfigStore.loadApConfiguration();
   5640                 mWifiApConfigChannel.connectSync(mContext, getHandler(),
   5641                         mWifiApConfigStore.getMessenger());
   5642             }
   5643 
   5644             if (mWifiConfigStore.enableHalBasedPno.get()) {
   5645                 // make sure developer Settings are in sync with the config option
   5646                 mHalBasedPnoEnableInDevSettings = true;
   5647             }
   5648         }
   5649         @Override
   5650         public boolean processMessage(Message message) {
   5651             logStateAndMessage(message, getClass().getSimpleName());
   5652             switch (message.what) {
   5653                 case CMD_START_SUPPLICANT:
   5654                     if (mWifiNative.loadDriver()) {
   5655                         try {
   5656                             mNwService.wifiFirmwareReload(mInterfaceName, "STA");
   5657                         } catch (Exception e) {
   5658                             loge("Failed to reload STA firmware " + e);
   5659                             // Continue
   5660                         }
   5661 
   5662                         try {
   5663                             // A runtime crash can leave the interface up and
   5664                             // IP addresses configured, and this affects
   5665                             // connectivity when supplicant starts up.
   5666                             // Ensure interface is down and we have no IP
   5667                             // addresses before a supplicant start.
   5668                             mNwService.setInterfaceDown(mInterfaceName);
   5669                             mNwService.clearInterfaceAddresses(mInterfaceName);
   5670 
   5671                             // Set privacy extensions
   5672                             mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
   5673 
   5674                             // IPv6 is enabled only as long as access point is connected since:
   5675                             // - IPv6 addresses and routes stick around after disconnection
   5676                             // - kernel is unaware when connected and fails to start IPv6 negotiation
   5677                             // - kernel can start autoconfiguration when 802.1x is not complete
   5678                             mNwService.disableIpv6(mInterfaceName);
   5679                         } catch (RemoteException re) {
   5680                             loge("Unable to change interface settings: " + re);
   5681                         } catch (IllegalStateException ie) {
   5682                             loge("Unable to change interface settings: " + ie);
   5683                         }
   5684 
   5685                        /* Stop a running supplicant after a runtime restart
   5686                         * Avoids issues with drivers that do not handle interface down
   5687                         * on a running supplicant properly.
   5688                         */
   5689                         mWifiMonitor.killSupplicant(mP2pSupported);
   5690 
   5691                         if (WifiNative.startHal() == false) {
   5692                             /* starting HAL is optional */
   5693                             loge("Failed to start HAL");
   5694                         }
   5695 
   5696                         if (mWifiNative.startSupplicant(mP2pSupported)) {
   5697                             setWifiState(WIFI_STATE_ENABLING);
   5698                             if (DBG) log("Supplicant start successful");
   5699                             mWifiMonitor.startMonitoring();
   5700                             transitionTo(mSupplicantStartingState);
   5701                         } else {
   5702                             loge("Failed to start supplicant!");
   5703                         }
   5704                     } else {
   5705                         loge("Failed to load driver");
   5706                     }
   5707                     break;
   5708                 case CMD_START_AP:
   5709                     if (mWifiNative.loadDriver() == false) {
   5710                         loge("Failed to load driver for softap");
   5711                     } else {
   5712                         if (enableSoftAp() == true) {
   5713                             setWifiApState(WIFI_AP_STATE_ENABLING, 0);
   5714                             transitionTo(mSoftApStartingState);
   5715                         } else {
   5716                             setWifiApState(WIFI_AP_STATE_FAILED,
   5717                                     WifiManager.SAP_START_FAILURE_GENERAL);
   5718                             transitionTo(mInitialState);
   5719                         }
   5720                     }
   5721                     break;
   5722                 default:
   5723                     return NOT_HANDLED;
   5724             }
   5725             return HANDLED;
   5726         }
   5727     }
   5728 
   5729     class SupplicantStartingState extends State {
   5730         private void initializeWpsDetails() {
   5731             String detail;
   5732             detail = SystemProperties.get("ro.product.name", "");
   5733             if (!mWifiNative.setDeviceName(detail)) {
   5734                 loge("Failed to set device name " +  detail);
   5735             }
   5736             detail = SystemProperties.get("ro.product.manufacturer", "");
   5737             if (!mWifiNative.setManufacturer(detail)) {
   5738                 loge("Failed to set manufacturer " + detail);
   5739             }
   5740             detail = SystemProperties.get("ro.product.model", "");
   5741             if (!mWifiNative.setModelName(detail)) {
   5742                 loge("Failed to set model name " + detail);
   5743             }
   5744             detail = SystemProperties.get("ro.product.model", "");
   5745             if (!mWifiNative.setModelNumber(detail)) {
   5746                 loge("Failed to set model number " + detail);
   5747             }
   5748             detail = SystemProperties.get("ro.serialno", "");
   5749             if (!mWifiNative.setSerialNumber(detail)) {
   5750                 loge("Failed to set serial number " + detail);
   5751             }
   5752             if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) {
   5753                 loge("Failed to set WPS config methods");
   5754             }
   5755             if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
   5756                 loge("Failed to set primary device type " + mPrimaryDeviceType);
   5757             }
   5758         }
   5759 
   5760         @Override
   5761         public boolean processMessage(Message message) {
   5762             logStateAndMessage(message, getClass().getSimpleName());
   5763 
   5764             switch(message.what) {
   5765                 case WifiMonitor.SUP_CONNECTION_EVENT:
   5766                     if (DBG) log("Supplicant connection established");
   5767                     setWifiState(WIFI_STATE_ENABLED);
   5768                     mSupplicantRestartCount = 0;
   5769                     /* Reset the supplicant state to indicate the supplicant
   5770                      * state is not known at this time */
   5771                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
   5772                     /* Initialize data structures */
   5773                     mLastBssid = null;
   5774                     mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
   5775                     mLastSignalLevel = -1;
   5776 
   5777                     mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
   5778                     /* set frequency band of operation */
   5779                     setFrequencyBand();
   5780                     mWifiNative.enableSaveConfig();
   5781                     mWifiConfigStore.loadAndEnableAllNetworks();
   5782                     if (mWifiConfigStore.enableVerboseLogging.get() > 0) {
   5783                         enableVerboseLogging(mWifiConfigStore.enableVerboseLogging.get());
   5784                     }
   5785                     initializeWpsDetails();
   5786 
   5787                     sendSupplicantConnectionChangedBroadcast(true);
   5788                     transitionTo(mDriverStartedState);
   5789                     break;
   5790                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   5791                     if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
   5792                         loge("Failed to setup control channel, restart supplicant");
   5793                         mWifiMonitor.killSupplicant(mP2pSupported);
   5794                         transitionTo(mInitialState);
   5795                         sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
   5796                     } else {
   5797                         loge("Failed " + mSupplicantRestartCount +
   5798                                 " times to start supplicant, unload driver");
   5799                         mSupplicantRestartCount = 0;
   5800                         setWifiState(WIFI_STATE_UNKNOWN);
   5801                         transitionTo(mInitialState);
   5802                     }
   5803                     break;
   5804                 case CMD_START_SUPPLICANT:
   5805                 case CMD_STOP_SUPPLICANT:
   5806                 case CMD_START_AP:
   5807                 case CMD_STOP_AP:
   5808                 case CMD_START_DRIVER:
   5809                 case CMD_STOP_DRIVER:
   5810                 case CMD_SET_OPERATIONAL_MODE:
   5811                 case CMD_SET_COUNTRY_CODE:
   5812                 case CMD_SET_FREQUENCY_BAND:
   5813                 case CMD_START_PACKET_FILTERING:
   5814                 case CMD_STOP_PACKET_FILTERING:
   5815                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   5816                     deferMessage(message);
   5817                     break;
   5818                 default:
   5819                     return NOT_HANDLED;
   5820             }
   5821             return HANDLED;
   5822         }
   5823     }
   5824 
   5825     class SupplicantStartedState extends State {
   5826         @Override
   5827         public void enter() {
   5828             /* Wifi is available as long as we have a connection to supplicant */
   5829             mNetworkInfo.setIsAvailable(true);
   5830             if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   5831 
   5832             int defaultInterval = mContext.getResources().getInteger(
   5833                     R.integer.config_wifi_supplicant_scan_interval);
   5834 
   5835             mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
   5836                     Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
   5837                     defaultInterval);
   5838 
   5839             mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
   5840             mWifiNative.setExternalSim(true);
   5841 
   5842             /* turn on use of DFS channels */
   5843             WifiNative.setDfsFlag(true);
   5844 
   5845             /* set country code */
   5846             setCountryCode();
   5847 
   5848             setRandomMacOui();
   5849             mWifiNative.enableAutoConnect(false);
   5850         }
   5851 
   5852         @Override
   5853         public boolean processMessage(Message message) {
   5854             logStateAndMessage(message, getClass().getSimpleName());
   5855 
   5856             switch(message.what) {
   5857                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
   5858                     if (mP2pSupported) {
   5859                         transitionTo(mWaitForP2pDisableState);
   5860                     } else {
   5861                         transitionTo(mSupplicantStoppingState);
   5862                     }
   5863                     break;
   5864                 case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
   5865                     loge("Connection lost, restart supplicant");
   5866                     handleSupplicantConnectionLoss(true);
   5867                     handleNetworkDisconnect();
   5868                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
   5869                     if (mP2pSupported) {
   5870                         transitionTo(mWaitForP2pDisableState);
   5871                     } else {
   5872                         transitionTo(mInitialState);
   5873                     }
   5874                     sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
   5875                     break;
   5876                 case WifiMonitor.SCAN_RESULTS_EVENT:
   5877                 case WifiMonitor.SCAN_FAILED_EVENT:
   5878                     maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered
   5879                     closeRadioScanStats();
   5880                     noteScanEnd();
   5881                     setScanResults();
   5882                     if (mIsFullScanOngoing || mSendScanResultsBroadcast) {
   5883                         /* Just updated results from full scan, let apps know about this */
   5884                         boolean scanSucceeded = message.what == WifiMonitor.SCAN_RESULTS_EVENT;
   5885                         sendScanResultsAvailableBroadcast(scanSucceeded);
   5886                     }
   5887                     mSendScanResultsBroadcast = false;
   5888                     mIsScanOngoing = false;
   5889                     mIsFullScanOngoing = false;
   5890                     if (mBufferedScanMsg.size() > 0)
   5891                         sendMessage(mBufferedScanMsg.remove());
   5892                     break;
   5893                 case CMD_PING_SUPPLICANT:
   5894                     boolean ok = mWifiNative.ping();
   5895                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
   5896                     break;
   5897                 case CMD_GET_CAPABILITY_FREQ:
   5898                     String freqs = mWifiNative.getFreqCapability();
   5899                     replyToMessage(message, message.what, freqs);
   5900                     break;
   5901                 case CMD_START_AP:
   5902                     /* Cannot start soft AP while in client mode */
   5903                     loge("Failed to start soft AP with a running supplicant");
   5904                     setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL);
   5905                     break;
   5906                 case CMD_SET_OPERATIONAL_MODE:
   5907                     mOperationalMode = message.arg1;
   5908                     mWifiConfigStore.
   5909                             setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
   5910                     break;
   5911                 case CMD_TARGET_BSSID:
   5912                     // Trying to associate to this BSSID
   5913                     if (message.obj != null) {
   5914                         mTargetRoamBSSID = (String) message.obj;
   5915                     }
   5916                     break;
   5917                 case CMD_GET_LINK_LAYER_STATS:
   5918                     WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG);
   5919                     if (stats == null) {
   5920                         // When firmware doesnt support link layer stats, return an empty object
   5921                         stats = new WifiLinkLayerStats();
   5922                     }
   5923                     replyToMessage(message, message.what, stats);
   5924                     break;
   5925                 case CMD_SET_COUNTRY_CODE:
   5926                     String country = (String) message.obj;
   5927 
   5928                     final boolean persist = (message.arg2 == 1);
   5929                     final int sequence = message.arg1;
   5930 
   5931                     if (sequence != mCountryCodeSequence.get()) {
   5932                         if (DBG) log("set country code ignored due to sequnce num");
   5933                         break;
   5934                     }
   5935                     if (DBG) log("set country code " + country);
   5936                     country = country.toUpperCase(Locale.ROOT);
   5937 
   5938                     if (mDriverSetCountryCode == null || !mDriverSetCountryCode.equals(country)) {
   5939                         if (mWifiNative.setCountryCode(country)) {
   5940                             mDriverSetCountryCode = country;
   5941                         } else {
   5942                             loge("Failed to set country code " + country);
   5943                         }
   5944                     }
   5945 
   5946                     mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country);
   5947                     break;
   5948                 default:
   5949                     return NOT_HANDLED;
   5950             }
   5951             return HANDLED;
   5952         }
   5953 
   5954         @Override
   5955         public void exit() {
   5956             mNetworkInfo.setIsAvailable(false);
   5957             if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   5958         }
   5959     }
   5960 
   5961     class SupplicantStoppingState extends State {
   5962         @Override
   5963         public void enter() {
   5964             /* Send any reset commands to supplicant before shutting it down */
   5965             handleNetworkDisconnect();
   5966             if (mDhcpStateMachine != null) {
   5967                 mDhcpStateMachine.doQuit();
   5968             }
   5969 
   5970             String suppState = System.getProperty("init.svc.wpa_supplicant");
   5971             if (suppState == null) suppState = "unknown";
   5972             String p2pSuppState = System.getProperty("init.svc.p2p_supplicant");
   5973             if (p2pSuppState == null) p2pSuppState = "unknown";
   5974 
   5975             logd("SupplicantStoppingState: stopSupplicant "
   5976                     + " init.svc.wpa_supplicant=" + suppState
   5977                     + " init.svc.p2p_supplicant=" + p2pSuppState);
   5978             mWifiMonitor.stopSupplicant();
   5979 
   5980             /* Send ourselves a delayed message to indicate failure after a wait time */
   5981             sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
   5982                     ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
   5983             setWifiState(WIFI_STATE_DISABLING);
   5984             mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
   5985         }
   5986         @Override
   5987         public boolean processMessage(Message message) {
   5988             logStateAndMessage(message, getClass().getSimpleName());
   5989 
   5990             switch(message.what) {
   5991                 case WifiMonitor.SUP_CONNECTION_EVENT:
   5992                     loge("Supplicant connection received while stopping");
   5993                     break;
   5994                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   5995                     if (DBG) log("Supplicant connection lost");
   5996                     handleSupplicantConnectionLoss(false);
   5997                     transitionTo(mInitialState);
   5998                     break;
   5999                 case CMD_STOP_SUPPLICANT_FAILED:
   6000                     if (message.arg1 == mSupplicantStopFailureToken) {
   6001                         loge("Timed out on a supplicant stop, kill and proceed");
   6002                         handleSupplicantConnectionLoss(true);
   6003                         transitionTo(mInitialState);
   6004                     }
   6005                     break;
   6006                 case CMD_START_SUPPLICANT:
   6007                 case CMD_STOP_SUPPLICANT:
   6008                 case CMD_START_AP:
   6009                 case CMD_STOP_AP:
   6010                 case CMD_START_DRIVER:
   6011                 case CMD_STOP_DRIVER:
   6012                 case CMD_SET_OPERATIONAL_MODE:
   6013                 case CMD_SET_COUNTRY_CODE:
   6014                 case CMD_SET_FREQUENCY_BAND:
   6015                 case CMD_START_PACKET_FILTERING:
   6016                 case CMD_STOP_PACKET_FILTERING:
   6017                     deferMessage(message);
   6018                     break;
   6019                 default:
   6020                     return NOT_HANDLED;
   6021             }
   6022             return HANDLED;
   6023         }
   6024     }
   6025 
   6026     class DriverStartingState extends State {
   6027         private int mTries;
   6028         @Override
   6029         public void enter() {
   6030             mTries = 1;
   6031             /* Send ourselves a delayed message to start driver a second time */
   6032             sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
   6033                         ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
   6034         }
   6035         @Override
   6036         public boolean processMessage(Message message) {
   6037             logStateAndMessage(message, getClass().getSimpleName());
   6038 
   6039             switch(message.what) {
   6040                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   6041                     SupplicantState state = handleSupplicantStateChange(message);
   6042                     /* If suplicant is exiting out of INTERFACE_DISABLED state into
   6043                      * a state that indicates driver has started, it is ready to
   6044                      * receive driver commands
   6045                      */
   6046                     if (SupplicantState.isDriverActive(state)) {
   6047                         transitionTo(mDriverStartedState);
   6048                     }
   6049                     break;
   6050                 case CMD_DRIVER_START_TIMED_OUT:
   6051                     if (message.arg1 == mDriverStartToken) {
   6052                         if (mTries >= 2) {
   6053                             loge("Failed to start driver after " + mTries);
   6054                             transitionTo(mDriverStoppedState);
   6055                         } else {
   6056                             loge("Driver start failed, retrying");
   6057                             mWakeLock.acquire();
   6058                             mWifiNative.startDriver();
   6059                             mWakeLock.release();
   6060 
   6061                             ++mTries;
   6062                             /* Send ourselves a delayed message to start driver again */
   6063                             sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
   6064                                         ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
   6065                         }
   6066                     }
   6067                     break;
   6068                     /* Queue driver commands & connection events */
   6069                 case CMD_START_DRIVER:
   6070                 case CMD_STOP_DRIVER:
   6071                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   6072                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   6073                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   6074                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   6075                 case WifiMonitor.WPS_OVERLAP_EVENT:
   6076                 case CMD_SET_COUNTRY_CODE:
   6077                 case CMD_SET_FREQUENCY_BAND:
   6078                 case CMD_START_PACKET_FILTERING:
   6079                 case CMD_STOP_PACKET_FILTERING:
   6080                 case CMD_START_SCAN:
   6081                 case CMD_DISCONNECT:
   6082                 case CMD_REASSOCIATE:
   6083                 case CMD_RECONNECT:
   6084                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   6085                     deferMessage(message);
   6086                     break;
   6087                 case WifiMonitor.SCAN_RESULTS_EVENT:
   6088                 case WifiMonitor.SCAN_FAILED_EVENT:
   6089                     // Loose scan results obtained in Driver Starting state, they can only confuse
   6090                     // the state machine
   6091                     break;
   6092                 default:
   6093                     return NOT_HANDLED;
   6094             }
   6095             return HANDLED;
   6096         }
   6097     }
   6098 
   6099     class DriverStartedState extends State {
   6100         @Override
   6101         public void enter() {
   6102 
   6103             if (PDBG) {
   6104                 logd("DriverStartedState enter");
   6105             }
   6106 
   6107             mWifiLogger.startLogging(mVerboseLoggingLevel > 0);
   6108             mIsRunning = true;
   6109             mInDelayedStop = false;
   6110             mDelayedStopCounter++;
   6111             updateBatteryWorkSource(null);
   6112             /**
   6113              * Enable bluetooth coexistence scan mode when bluetooth connection is active.
   6114              * When this mode is on, some of the low-level scan parameters used by the
   6115              * driver are changed to reduce interference with bluetooth
   6116              */
   6117             mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
   6118             /* initialize network state */
   6119             setNetworkDetailedState(DetailedState.DISCONNECTED);
   6120 
   6121             /* Remove any filtering on Multicast v6 at start */
   6122             mWifiNative.stopFilteringMulticastV6Packets();
   6123 
   6124             /* Reset Multicast v4 filtering state */
   6125             if (mFilteringMulticastV4Packets.get()) {
   6126                 mWifiNative.startFilteringMulticastV4Packets();
   6127             } else {
   6128                 mWifiNative.stopFilteringMulticastV4Packets();
   6129             }
   6130 
   6131             mDhcpActive = false;
   6132 
   6133             if (mOperationalMode != CONNECT_MODE) {
   6134                 mWifiNative.disconnect();
   6135                 mWifiConfigStore.disableAllNetworks();
   6136                 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
   6137                     setWifiState(WIFI_STATE_DISABLED);
   6138                 }
   6139                 transitionTo(mScanModeState);
   6140             } else {
   6141 
   6142                 // Status pulls in the current supplicant state and network connection state
   6143                 // events over the monitor connection. This helps framework sync up with
   6144                 // current supplicant state
   6145                 // TODO: actually check th supplicant status string and make sure the supplicant
   6146                 // is in disconnecte4d state.
   6147                 mWifiNative.status();
   6148                 // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin
   6149                 transitionTo(mDisconnectedState);
   6150                 transitionTo(mDisconnectedState);
   6151             }
   6152 
   6153             // We may have missed screen update at boot
   6154             if (mScreenBroadcastReceived.get() == false) {
   6155                 PowerManager powerManager = (PowerManager)mContext.getSystemService(
   6156                         Context.POWER_SERVICE);
   6157                 handleScreenStateChanged(powerManager.isScreenOn());
   6158             } else {
   6159                 // Set the right suspend mode settings
   6160                 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
   6161                         && mUserWantsSuspendOpt.get());
   6162             }
   6163             mWifiNative.setPowerSave(true);
   6164 
   6165             if (mP2pSupported) {
   6166                 if (mOperationalMode == CONNECT_MODE) {
   6167                     mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
   6168                 } else {
   6169                     // P2P statemachine starts in disabled state, and is not enabled until
   6170                     // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
   6171                     // keep it disabled.
   6172                 }
   6173             }
   6174 
   6175             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
   6176             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   6177             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
   6178             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   6179 
   6180             mHalFeatureSet = WifiNative.getSupportedFeatureSet();
   6181             if ((mHalFeatureSet & WifiManager.WIFI_FEATURE_HAL_EPNO)
   6182                     == WifiManager.WIFI_FEATURE_HAL_EPNO) {
   6183                 mHalBasedPnoDriverSupported = true;
   6184             }
   6185 
   6186             // Enable link layer stats gathering
   6187             mWifiNative.setWifiLinkLayerStats("wlan0", 1);
   6188 
   6189             if (PDBG) {
   6190                 logd("Driverstarted State enter done, epno=" + mHalBasedPnoDriverSupported
   6191                      + " feature=" + mHalFeatureSet);
   6192             }
   6193         }
   6194 
   6195         @Override
   6196         public boolean processMessage(Message message) {
   6197             logStateAndMessage(message, getClass().getSimpleName());
   6198 
   6199             switch(message.what) {
   6200                 case CMD_START_SCAN:
   6201                     handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
   6202                     break;
   6203                 case CMD_SET_FREQUENCY_BAND:
   6204                     int band =  message.arg1;
   6205                     if (DBG) log("set frequency band " + band);
   6206                     if (mWifiNative.setBand(band)) {
   6207 
   6208                         if (PDBG)  logd("did set frequency band " + band);
   6209 
   6210                         mFrequencyBand.set(band);
   6211                         // Flush old data - like scan results
   6212                         mWifiNative.bssFlush();
   6213                         // Fetch the latest scan results when frequency band is set
   6214 //                        startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null);
   6215 
   6216                         if (PDBG)  logd("done set frequency band " + band);
   6217 
   6218                     } else {
   6219                         loge("Failed to set frequency band " + band);
   6220                     }
   6221                     break;
   6222                 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
   6223                     mBluetoothConnectionActive = (message.arg1 !=
   6224                             BluetoothAdapter.STATE_DISCONNECTED);
   6225                     mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
   6226                     break;
   6227                 case CMD_STOP_DRIVER:
   6228                     int mode = message.arg1;
   6229 
   6230                     /* Already doing a delayed stop */
   6231                     if (mInDelayedStop) {
   6232                         if (DBG) log("Already in delayed stop");
   6233                         break;
   6234                     }
   6235                     /* disconnect right now, but leave the driver running for a bit */
   6236                     mWifiConfigStore.disableAllNetworks();
   6237 
   6238                     mInDelayedStop = true;
   6239                     mDelayedStopCounter++;
   6240                     if (DBG) log("Delayed stop message " + mDelayedStopCounter);
   6241 
   6242                     /* send regular delayed shut down */
   6243                     Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
   6244                     driverStopIntent.setPackage(this.getClass().getPackage().getName());
   6245                     driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
   6246                     mDriverStopIntent = PendingIntent.getBroadcast(mContext,
   6247                             DRIVER_STOP_REQUEST, driverStopIntent,
   6248                             PendingIntent.FLAG_UPDATE_CURRENT);
   6249 
   6250                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
   6251                             + mDriverStopDelayMs, mDriverStopIntent);
   6252                     break;
   6253                 case CMD_START_DRIVER:
   6254                     if (mInDelayedStop) {
   6255                         mInDelayedStop = false;
   6256                         mDelayedStopCounter++;
   6257                         mAlarmManager.cancel(mDriverStopIntent);
   6258                         if (DBG) log("Delayed stop ignored due to start");
   6259                         if (mOperationalMode == CONNECT_MODE) {
   6260                             mWifiConfigStore.enableAllNetworks();
   6261                         }
   6262                     }
   6263                     break;
   6264                 case CMD_DELAYED_STOP_DRIVER:
   6265                     if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter);
   6266                     if (message.arg1 != mDelayedStopCounter) break;
   6267                     if (getCurrentState() != mDisconnectedState) {
   6268                         mWifiNative.disconnect();
   6269                         handleNetworkDisconnect();
   6270                     }
   6271                     mWakeLock.acquire();
   6272                     mWifiNative.stopDriver();
   6273                     mWakeLock.release();
   6274                     if (mP2pSupported) {
   6275                         transitionTo(mWaitForP2pDisableState);
   6276                     } else {
   6277                         transitionTo(mDriverStoppingState);
   6278                     }
   6279                     break;
   6280                 case CMD_START_PACKET_FILTERING:
   6281                     if (message.arg1 == MULTICAST_V6) {
   6282                         mWifiNative.startFilteringMulticastV6Packets();
   6283                     } else if (message.arg1 == MULTICAST_V4) {
   6284                         mWifiNative.startFilteringMulticastV4Packets();
   6285                     } else {
   6286                         loge("Illegal arugments to CMD_START_PACKET_FILTERING");
   6287                     }
   6288                     break;
   6289                 case CMD_STOP_PACKET_FILTERING:
   6290                     if (message.arg1 == MULTICAST_V6) {
   6291                         mWifiNative.stopFilteringMulticastV6Packets();
   6292                     } else if (message.arg1 == MULTICAST_V4) {
   6293                         mWifiNative.stopFilteringMulticastV4Packets();
   6294                     } else {
   6295                         loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
   6296                     }
   6297                     break;
   6298                 case CMD_SET_SUSPEND_OPT_ENABLED:
   6299                     if (message.arg1 == 1) {
   6300                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
   6301                         mSuspendWakeLock.release();
   6302                     } else {
   6303                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
   6304                     }
   6305                     break;
   6306                 case CMD_SET_HIGH_PERF_MODE:
   6307                     if (message.arg1 == 1) {
   6308                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
   6309                     } else {
   6310                         setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
   6311                     }
   6312                     break;
   6313                 case CMD_ENABLE_TDLS:
   6314                     if (message.obj != null) {
   6315                         String remoteAddress = (String) message.obj;
   6316                         boolean enable = (message.arg1 == 1);
   6317                         mWifiNative.startTdls(remoteAddress, enable);
   6318                     }
   6319                     break;
   6320                 case WifiMonitor.ANQP_DONE_EVENT:
   6321                     mWifiConfigStore.notifyANQPDone((Long) message.obj, message.arg1 != 0);
   6322                     break;
   6323                 default:
   6324                     return NOT_HANDLED;
   6325             }
   6326             return HANDLED;
   6327         }
   6328         @Override
   6329         public void exit() {
   6330 
   6331             mWifiLogger.stopLogging();
   6332 
   6333             mIsRunning = false;
   6334             updateBatteryWorkSource(null);
   6335             mScanResults = new ArrayList<>();
   6336 
   6337             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
   6338             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   6339             intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
   6340             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   6341             noteScanEnd(); // wrap up any pending request.
   6342             mBufferedScanMsg.clear();
   6343         }
   6344     }
   6345 
   6346     class WaitForP2pDisableState extends State {
   6347         private State mTransitionToState;
   6348         @Override
   6349         public void enter() {
   6350             switch (getCurrentMessage().what) {
   6351                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
   6352                     mTransitionToState = mInitialState;
   6353                     break;
   6354                 case CMD_DELAYED_STOP_DRIVER:
   6355                     mTransitionToState = mDriverStoppingState;
   6356                     break;
   6357                 case CMD_STOP_SUPPLICANT:
   6358                     mTransitionToState = mSupplicantStoppingState;
   6359                     break;
   6360                 default:
   6361                     mTransitionToState = mDriverStoppingState;
   6362                     break;
   6363             }
   6364             mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
   6365         }
   6366         @Override
   6367         public boolean processMessage(Message message) {
   6368             logStateAndMessage(message, getClass().getSimpleName());
   6369 
   6370             switch(message.what) {
   6371                 case WifiStateMachine.CMD_DISABLE_P2P_RSP:
   6372                     transitionTo(mTransitionToState);
   6373                     break;
   6374                 /* Defer wifi start/shut and driver commands */
   6375                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   6376                 case CMD_START_SUPPLICANT:
   6377                 case CMD_STOP_SUPPLICANT:
   6378                 case CMD_START_AP:
   6379                 case CMD_STOP_AP:
   6380                 case CMD_START_DRIVER:
   6381                 case CMD_STOP_DRIVER:
   6382                 case CMD_SET_OPERATIONAL_MODE:
   6383                 case CMD_SET_COUNTRY_CODE:
   6384                 case CMD_SET_FREQUENCY_BAND:
   6385                 case CMD_START_PACKET_FILTERING:
   6386                 case CMD_STOP_PACKET_FILTERING:
   6387                 case CMD_START_SCAN:
   6388                 case CMD_DISCONNECT:
   6389                 case CMD_REASSOCIATE:
   6390                 case CMD_RECONNECT:
   6391                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   6392                     deferMessage(message);
   6393                     break;
   6394                 default:
   6395                     return NOT_HANDLED;
   6396             }
   6397             return HANDLED;
   6398         }
   6399     }
   6400 
   6401     class DriverStoppingState extends State {
   6402         @Override
   6403         public boolean processMessage(Message message) {
   6404             logStateAndMessage(message, getClass().getSimpleName());
   6405 
   6406             switch(message.what) {
   6407                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   6408                     SupplicantState state = handleSupplicantStateChange(message);
   6409                     if (state == SupplicantState.INTERFACE_DISABLED) {
   6410                         transitionTo(mDriverStoppedState);
   6411                     }
   6412                     break;
   6413                     /* Queue driver commands */
   6414                 case CMD_START_DRIVER:
   6415                 case CMD_STOP_DRIVER:
   6416                 case CMD_SET_COUNTRY_CODE:
   6417                 case CMD_SET_FREQUENCY_BAND:
   6418                 case CMD_START_PACKET_FILTERING:
   6419                 case CMD_STOP_PACKET_FILTERING:
   6420                 case CMD_START_SCAN:
   6421                 case CMD_DISCONNECT:
   6422                 case CMD_REASSOCIATE:
   6423                 case CMD_RECONNECT:
   6424                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   6425                     deferMessage(message);
   6426                     break;
   6427                 default:
   6428                     return NOT_HANDLED;
   6429             }
   6430             return HANDLED;
   6431         }
   6432     }
   6433 
   6434     class DriverStoppedState extends State {
   6435         @Override
   6436         public boolean processMessage(Message message) {
   6437             logStateAndMessage(message, getClass().getSimpleName());
   6438             switch (message.what) {
   6439                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   6440                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   6441                     SupplicantState state = stateChangeResult.state;
   6442                     // A WEXT bug means that we can be back to driver started state
   6443                     // unexpectedly
   6444                     if (SupplicantState.isDriverActive(state)) {
   6445                         transitionTo(mDriverStartedState);
   6446                     }
   6447                     break;
   6448                 case CMD_START_DRIVER:
   6449                     mWakeLock.acquire();
   6450                     mWifiNative.startDriver();
   6451                     mWakeLock.release();
   6452                     transitionTo(mDriverStartingState);
   6453                     break;
   6454                 default:
   6455                     return NOT_HANDLED;
   6456             }
   6457             return HANDLED;
   6458         }
   6459     }
   6460 
   6461     class ScanModeState extends State {
   6462         private int mLastOperationMode;
   6463         @Override
   6464         public void enter() {
   6465             mLastOperationMode = mOperationalMode;
   6466         }
   6467         @Override
   6468         public boolean processMessage(Message message) {
   6469             logStateAndMessage(message, getClass().getSimpleName());
   6470 
   6471             switch(message.what) {
   6472                 case CMD_SET_OPERATIONAL_MODE:
   6473                     if (message.arg1 == CONNECT_MODE) {
   6474 
   6475                         if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
   6476                             setWifiState(WIFI_STATE_ENABLED);
   6477                             // Load and re-enable networks when going back to enabled state
   6478                             // This is essential for networks to show up after restore
   6479                             mWifiConfigStore.loadAndEnableAllNetworks();
   6480                             mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
   6481                         } else {
   6482                             mWifiConfigStore.enableAllNetworks();
   6483                         }
   6484 
   6485                         // Try autojoining with recent network already present in the cache
   6486                         // If none are found then trigger a scan which will trigger autojoin
   6487                         // upon reception of scan results event
   6488                         if (!mWifiAutoJoinController.attemptAutoJoin()) {
   6489                             startScan(ENABLE_WIFI, 0, null, null);
   6490                         }
   6491 
   6492                         // Loose last selection choice since user toggled WiFi
   6493                         mWifiConfigStore.
   6494                                 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
   6495 
   6496                         mOperationalMode = CONNECT_MODE;
   6497                         transitionTo(mDisconnectedState);
   6498                     } else {
   6499                         // Nothing to do
   6500                         return HANDLED;
   6501                     }
   6502                     break;
   6503                 // Handle scan. All the connection related commands are
   6504                 // handled only in ConnectModeState
   6505                 case CMD_START_SCAN:
   6506                     handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
   6507                     break;
   6508                 default:
   6509                     return NOT_HANDLED;
   6510             }
   6511             return HANDLED;
   6512         }
   6513     }
   6514 
   6515 
   6516     String smToString(Message message) {
   6517         return smToString(message.what);
   6518     }
   6519 
   6520     String smToString(int what) {
   6521         String s = "unknown";
   6522         switch (what) {
   6523             case WifiMonitor.DRIVER_HUNG_EVENT:
   6524                 s = "DRIVER_HUNG_EVENT";
   6525                 break;
   6526             case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
   6527                 s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED";
   6528                 break;
   6529             case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
   6530                 s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED";
   6531                 break;
   6532             case CMD_SET_FREQUENCY_BAND:
   6533                 s = "CMD_SET_FREQUENCY_BAND";
   6534                 break;
   6535             case CMD_DELAYED_NETWORK_DISCONNECT:
   6536                 s = "CMD_DELAYED_NETWORK_DISCONNECT";
   6537                 break;
   6538             case CMD_TEST_NETWORK_DISCONNECT:
   6539                 s = "CMD_TEST_NETWORK_DISCONNECT";
   6540                 break;
   6541             case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
   6542                 s = "CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER";
   6543                 break;
   6544             case CMD_DISABLE_EPHEMERAL_NETWORK:
   6545                 s = "CMD_DISABLE_EPHEMERAL_NETWORK";
   6546                 break;
   6547             case CMD_START_DRIVER:
   6548                 s = "CMD_START_DRIVER";
   6549                 break;
   6550             case CMD_STOP_DRIVER:
   6551                 s = "CMD_STOP_DRIVER";
   6552                 break;
   6553             case CMD_STOP_SUPPLICANT:
   6554                 s = "CMD_STOP_SUPPLICANT";
   6555                 break;
   6556             case CMD_STOP_SUPPLICANT_FAILED:
   6557                 s = "CMD_STOP_SUPPLICANT_FAILED";
   6558                 break;
   6559             case CMD_START_SUPPLICANT:
   6560                 s = "CMD_START_SUPPLICANT";
   6561                 break;
   6562             case CMD_REQUEST_AP_CONFIG:
   6563                 s = "CMD_REQUEST_AP_CONFIG";
   6564                 break;
   6565             case CMD_RESPONSE_AP_CONFIG:
   6566                 s = "CMD_RESPONSE_AP_CONFIG";
   6567                 break;
   6568             case CMD_TETHER_STATE_CHANGE:
   6569                 s = "CMD_TETHER_STATE_CHANGE";
   6570                 break;
   6571             case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   6572                 s = "CMD_TETHER_NOTIFICATION_TIMED_OUT";
   6573                 break;
   6574             case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
   6575                 s = "CMD_BLUETOOTH_ADAPTER_STATE_CHANGE";
   6576                 break;
   6577             case CMD_ADD_OR_UPDATE_NETWORK:
   6578                 s = "CMD_ADD_OR_UPDATE_NETWORK";
   6579                 break;
   6580             case CMD_REMOVE_NETWORK:
   6581                 s = "CMD_REMOVE_NETWORK";
   6582                 break;
   6583             case CMD_ENABLE_NETWORK:
   6584                 s = "CMD_ENABLE_NETWORK";
   6585                 break;
   6586             case CMD_ENABLE_ALL_NETWORKS:
   6587                 s = "CMD_ENABLE_ALL_NETWORKS";
   6588                 break;
   6589             case CMD_AUTO_CONNECT:
   6590                 s = "CMD_AUTO_CONNECT";
   6591                 break;
   6592             case CMD_AUTO_ROAM:
   6593                 s = "CMD_AUTO_ROAM";
   6594                 break;
   6595             case CMD_AUTO_SAVE_NETWORK:
   6596                 s = "CMD_AUTO_SAVE_NETWORK";
   6597                 break;
   6598             case CMD_BOOT_COMPLETED:
   6599                 s = "CMD_BOOT_COMPLETED";
   6600                 break;
   6601             case DhcpStateMachine.CMD_START_DHCP:
   6602                 s = "CMD_START_DHCP";
   6603                 break;
   6604             case DhcpStateMachine.CMD_STOP_DHCP:
   6605                 s = "CMD_STOP_DHCP";
   6606                 break;
   6607             case DhcpStateMachine.CMD_RENEW_DHCP:
   6608                 s = "CMD_RENEW_DHCP";
   6609                 break;
   6610             case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   6611                 s = "CMD_PRE_DHCP_ACTION";
   6612                 break;
   6613             case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   6614                 s = "CMD_POST_DHCP_ACTION";
   6615                 break;
   6616             case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
   6617                 s = "CMD_PRE_DHCP_ACTION_COMPLETE";
   6618                 break;
   6619             case DhcpStateMachine.CMD_ON_QUIT:
   6620                 s = "CMD_ON_QUIT";
   6621                 break;
   6622             case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
   6623                 s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST";
   6624                 break;
   6625             case WifiManager.DISABLE_NETWORK:
   6626                 s = "WifiManager.DISABLE_NETWORK";
   6627                 break;
   6628             case CMD_BLACKLIST_NETWORK:
   6629                 s = "CMD_BLACKLIST_NETWORK";
   6630                 break;
   6631             case CMD_CLEAR_BLACKLIST:
   6632                 s = "CMD_CLEAR_BLACKLIST";
   6633                 break;
   6634             case CMD_SAVE_CONFIG:
   6635                 s = "CMD_SAVE_CONFIG";
   6636                 break;
   6637             case CMD_GET_CONFIGURED_NETWORKS:
   6638                 s = "CMD_GET_CONFIGURED_NETWORKS";
   6639                 break;
   6640             case CMD_GET_SUPPORTED_FEATURES:
   6641                 s = "CMD_GET_SUPPORTED_FEATURES";
   6642                 break;
   6643             case CMD_UNWANTED_NETWORK:
   6644                 s = "CMD_UNWANTED_NETWORK";
   6645                 break;
   6646             case CMD_NETWORK_STATUS:
   6647                 s = "CMD_NETWORK_STATUS";
   6648                 break;
   6649             case CMD_GET_LINK_LAYER_STATS:
   6650                 s = "CMD_GET_LINK_LAYER_STATS";
   6651                 break;
   6652             case CMD_GET_MATCHING_CONFIG:
   6653                 s = "CMD_GET_MATCHING_CONFIG";
   6654                 break;
   6655             case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
   6656                 s = "CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS";
   6657                 break;
   6658             case CMD_DISCONNECT:
   6659                 s = "CMD_DISCONNECT";
   6660                 break;
   6661             case CMD_RECONNECT:
   6662                 s = "CMD_RECONNECT";
   6663                 break;
   6664             case CMD_REASSOCIATE:
   6665                 s = "CMD_REASSOCIATE";
   6666                 break;
   6667             case CMD_GET_CONNECTION_STATISTICS:
   6668                 s = "CMD_GET_CONNECTION_STATISTICS";
   6669                 break;
   6670             case CMD_SET_HIGH_PERF_MODE:
   6671                 s = "CMD_SET_HIGH_PERF_MODE";
   6672                 break;
   6673             case CMD_SET_COUNTRY_CODE:
   6674                 s = "CMD_SET_COUNTRY_CODE";
   6675                 break;
   6676             case CMD_ENABLE_RSSI_POLL:
   6677                 s = "CMD_ENABLE_RSSI_POLL";
   6678                 break;
   6679             case CMD_RSSI_POLL:
   6680                 s = "CMD_RSSI_POLL";
   6681                 break;
   6682             case CMD_START_PACKET_FILTERING:
   6683                 s = "CMD_START_PACKET_FILTERING";
   6684                 break;
   6685             case CMD_STOP_PACKET_FILTERING:
   6686                 s = "CMD_STOP_PACKET_FILTERING";
   6687                 break;
   6688             case CMD_SET_SUSPEND_OPT_ENABLED:
   6689                 s = "CMD_SET_SUSPEND_OPT_ENABLED";
   6690                 break;
   6691             case CMD_NO_NETWORKS_PERIODIC_SCAN:
   6692                 s = "CMD_NO_NETWORKS_PERIODIC_SCAN";
   6693                 break;
   6694             case CMD_UPDATE_LINKPROPERTIES:
   6695                 s = "CMD_UPDATE_LINKPROPERTIES";
   6696                 break;
   6697             case CMD_RELOAD_TLS_AND_RECONNECT:
   6698                 s = "CMD_RELOAD_TLS_AND_RECONNECT";
   6699                 break;
   6700             case WifiManager.CONNECT_NETWORK:
   6701                 s = "CONNECT_NETWORK";
   6702                 break;
   6703             case WifiManager.SAVE_NETWORK:
   6704                 s = "SAVE_NETWORK";
   6705                 break;
   6706             case WifiManager.FORGET_NETWORK:
   6707                 s = "FORGET_NETWORK";
   6708                 break;
   6709             case WifiMonitor.SUP_CONNECTION_EVENT:
   6710                 s = "SUP_CONNECTION_EVENT";
   6711                 break;
   6712             case WifiMonitor.SUP_DISCONNECTION_EVENT:
   6713                 s = "SUP_DISCONNECTION_EVENT";
   6714                 break;
   6715             case WifiMonitor.SCAN_RESULTS_EVENT:
   6716                 s = "SCAN_RESULTS_EVENT";
   6717                 break;
   6718             case WifiMonitor.SCAN_FAILED_EVENT:
   6719                 s = "SCAN_FAILED_EVENT";
   6720                 break;
   6721             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   6722                 s = "SUPPLICANT_STATE_CHANGE_EVENT";
   6723                 break;
   6724             case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   6725                 s = "AUTHENTICATION_FAILURE_EVENT";
   6726                 break;
   6727             case WifiMonitor.SSID_TEMP_DISABLED:
   6728                 s = "SSID_TEMP_DISABLED";
   6729                 break;
   6730             case WifiMonitor.SSID_REENABLED:
   6731                 s = "SSID_REENABLED";
   6732                 break;
   6733             case WifiMonitor.WPS_SUCCESS_EVENT:
   6734                 s = "WPS_SUCCESS_EVENT";
   6735                 break;
   6736             case WifiMonitor.WPS_FAIL_EVENT:
   6737                 s = "WPS_FAIL_EVENT";
   6738                 break;
   6739             case WifiMonitor.SUP_REQUEST_IDENTITY:
   6740                 s = "SUP_REQUEST_IDENTITY";
   6741                 break;
   6742             case WifiMonitor.NETWORK_CONNECTION_EVENT:
   6743                 s = "NETWORK_CONNECTION_EVENT";
   6744                 break;
   6745             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   6746                 s = "NETWORK_DISCONNECTION_EVENT";
   6747                 break;
   6748             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   6749                 s = "ASSOCIATION_REJECTION_EVENT";
   6750                 break;
   6751             case WifiMonitor.ANQP_DONE_EVENT:
   6752                 s = "WifiMonitor.ANQP_DONE_EVENT";
   6753                 break;
   6754             case WifiMonitor.GAS_QUERY_DONE_EVENT:
   6755                 s = "WifiMonitor.GAS_QUERY_DONE_EVENT";
   6756                 break;
   6757             case WifiMonitor.HS20_DEAUTH_EVENT:
   6758                 s = "WifiMonitor.HS20_DEAUTH_EVENT";
   6759                 break;
   6760             case WifiMonitor.GAS_QUERY_START_EVENT:
   6761                 s = "WifiMonitor.GAS_QUERY_START_EVENT";
   6762                 break;
   6763             case CMD_SET_OPERATIONAL_MODE:
   6764                 s = "CMD_SET_OPERATIONAL_MODE";
   6765                 break;
   6766             case CMD_START_SCAN:
   6767                 s = "CMD_START_SCAN";
   6768                 break;
   6769             case CMD_DISABLE_P2P_RSP:
   6770                 s = "CMD_DISABLE_P2P_RSP";
   6771                 break;
   6772             case CMD_DISABLE_P2P_REQ:
   6773                 s = "CMD_DISABLE_P2P_REQ";
   6774                 break;
   6775             case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
   6776                 s = "GOOD_LINK_DETECTED";
   6777                 break;
   6778             case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
   6779                 s = "POOR_LINK_DETECTED";
   6780                 break;
   6781             case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT:
   6782                 s = "GROUP_CREATING_TIMED_OUT";
   6783                 break;
   6784             case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
   6785                 s = "P2P_CONNECTION_CHANGED";
   6786                 break;
   6787             case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE:
   6788                 s = "P2P.DISCONNECT_WIFI_RESPONSE";
   6789                 break;
   6790             case WifiP2pServiceImpl.SET_MIRACAST_MODE:
   6791                 s = "P2P.SET_MIRACAST_MODE";
   6792                 break;
   6793             case WifiP2pServiceImpl.BLOCK_DISCOVERY:
   6794                 s = "P2P.BLOCK_DISCOVERY";
   6795                 break;
   6796             case WifiP2pServiceImpl.SET_COUNTRY_CODE:
   6797                 s = "P2P.SET_COUNTRY_CODE";
   6798                 break;
   6799             case WifiManager.CANCEL_WPS:
   6800                 s = "CANCEL_WPS";
   6801                 break;
   6802             case WifiManager.CANCEL_WPS_FAILED:
   6803                 s = "CANCEL_WPS_FAILED";
   6804                 break;
   6805             case WifiManager.CANCEL_WPS_SUCCEDED:
   6806                 s = "CANCEL_WPS_SUCCEDED";
   6807                 break;
   6808             case WifiManager.START_WPS:
   6809                 s = "START_WPS";
   6810                 break;
   6811             case WifiManager.START_WPS_SUCCEEDED:
   6812                 s = "START_WPS_SUCCEEDED";
   6813                 break;
   6814             case WifiManager.WPS_FAILED:
   6815                 s = "WPS_FAILED";
   6816                 break;
   6817             case WifiManager.WPS_COMPLETED:
   6818                 s = "WPS_COMPLETED";
   6819                 break;
   6820             case WifiManager.RSSI_PKTCNT_FETCH:
   6821                 s = "RSSI_PKTCNT_FETCH";
   6822                 break;
   6823             case CMD_IP_CONFIGURATION_LOST:
   6824                 s = "CMD_IP_CONFIGURATION_LOST";
   6825                 break;
   6826             case CMD_IP_CONFIGURATION_SUCCESSFUL:
   6827                 s = "CMD_IP_CONFIGURATION_SUCCESSFUL";
   6828                 break;
   6829             case CMD_IP_REACHABILITY_LOST:
   6830                 s = "CMD_IP_REACHABILITY_LOST";
   6831                 break;
   6832             case CMD_STATIC_IP_SUCCESS:
   6833                 s = "CMD_STATIC_IP_SUCCESSFUL";
   6834                 break;
   6835             case CMD_STATIC_IP_FAILURE:
   6836                 s = "CMD_STATIC_IP_FAILURE";
   6837                 break;
   6838             case DhcpStateMachine.DHCP_SUCCESS:
   6839                 s = "DHCP_SUCCESS";
   6840                 break;
   6841             case DhcpStateMachine.DHCP_FAILURE:
   6842                 s = "DHCP_FAILURE";
   6843                 break;
   6844             case CMD_TARGET_BSSID:
   6845                 s = "CMD_TARGET_BSSID";
   6846                 break;
   6847             case CMD_ASSOCIATED_BSSID:
   6848                 s = "CMD_ASSOCIATED_BSSID";
   6849                 break;
   6850             case CMD_REMOVE_APP_CONFIGURATIONS:
   6851                 s = "CMD_REMOVE_APP_CONFIGURATIONS";
   6852                 break;
   6853             case CMD_REMOVE_USER_CONFIGURATIONS:
   6854                 s = "CMD_REMOVE_USER_CONFIGURATIONS";
   6855                 break;
   6856             case CMD_ROAM_WATCHDOG_TIMER:
   6857                 s = "CMD_ROAM_WATCHDOG_TIMER";
   6858                 break;
   6859             case CMD_SCREEN_STATE_CHANGED:
   6860                 s = "CMD_SCREEN_STATE_CHANGED";
   6861                 break;
   6862             case CMD_DISCONNECTING_WATCHDOG_TIMER:
   6863                 s = "CMD_DISCONNECTING_WATCHDOG_TIMER";
   6864                 break;
   6865             case CMD_RESTART_AUTOJOIN_OFFLOAD:
   6866                 s = "CMD_RESTART_AUTOJOIN_OFFLOAD";
   6867                 break;
   6868             case CMD_STARTED_PNO_DBG:
   6869                 s = "CMD_STARTED_PNO_DBG";
   6870                 break;
   6871             case CMD_STARTED_GSCAN_DBG:
   6872                 s = "CMD_STARTED_GSCAN_DBG";
   6873                 break;
   6874             case CMD_PNO_NETWORK_FOUND:
   6875                 s = "CMD_PNO_NETWORK_FOUND";
   6876                 break;
   6877             case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
   6878                 s = "CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION";
   6879                 break;
   6880             default:
   6881                 s = "what:" + Integer.toString(what);
   6882                 break;
   6883         }
   6884         return s;
   6885     }
   6886 
   6887     void registerConnected() {
   6888        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
   6889            long now_ms = System.currentTimeMillis();
   6890            // We are switching away from this configuration,
   6891            // hence record the time we were connected last
   6892            WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId);
   6893            if (config != null) {
   6894                config.lastConnected = System.currentTimeMillis();
   6895                config.autoJoinBailedDueToLowRssi = false;
   6896                config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
   6897                config.numConnectionFailures = 0;
   6898                config.numIpConfigFailures = 0;
   6899                config.numAuthFailures = 0;
   6900                config.numAssociation++;
   6901            }
   6902            mBadLinkspeedcount = 0;
   6903        }
   6904     }
   6905 
   6906     void registerDisconnected() {
   6907         if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
   6908             long now_ms = System.currentTimeMillis();
   6909             // We are switching away from this configuration,
   6910             // hence record the time we were connected last
   6911             WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId);
   6912             if (config != null) {
   6913                 config.lastDisconnected = System.currentTimeMillis();
   6914                 if (config.ephemeral) {
   6915                     // Remove ephemeral WifiConfigurations from file
   6916                     mWifiConfigStore.forgetNetwork(mLastNetworkId);
   6917                 }
   6918             }
   6919         }
   6920     }
   6921 
   6922     void noteWifiDisabledWhileAssociated() {
   6923         // We got disabled by user while we were associated, make note of it
   6924         int rssi = mWifiInfo.getRssi();
   6925         WifiConfiguration config = getCurrentWifiConfiguration();
   6926         if (getCurrentState() == mConnectedState
   6927                 && rssi != WifiInfo.INVALID_RSSI
   6928                 && config != null) {
   6929             boolean is24GHz = mWifiInfo.is24GHz();
   6930             boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24.get())
   6931                     || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5.get());
   6932             boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24.get())
   6933                     || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5.get());
   6934             boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24.get())
   6935                     || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5.get());
   6936             if (isBadRSSI) {
   6937                 // Take note that we got disabled while RSSI was Bad
   6938                 config.numUserTriggeredWifiDisableLowRSSI++;
   6939             } else if (isLowRSSI) {
   6940                 // Take note that we got disabled while RSSI was Low
   6941                 config.numUserTriggeredWifiDisableBadRSSI++;
   6942             } else if (!isHighRSSI) {
   6943                 // Take note that we got disabled while RSSI was Not high
   6944                 config.numUserTriggeredWifiDisableNotHighRSSI++;
   6945             }
   6946         }
   6947     }
   6948 
   6949     WifiConfiguration getCurrentWifiConfiguration() {
   6950         if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
   6951             return null;
   6952         }
   6953         return mWifiConfigStore.getWifiConfiguration(mLastNetworkId);
   6954     }
   6955 
   6956     ScanResult getCurrentScanResult() {
   6957         WifiConfiguration config = getCurrentWifiConfiguration();
   6958         if (config == null) {
   6959             return null;
   6960         }
   6961         String BSSID = mWifiInfo.getBSSID();
   6962         if (BSSID == null) {
   6963             BSSID = mTargetRoamBSSID;
   6964         }
   6965         ScanDetailCache scanDetailCache =
   6966                 mWifiConfigStore.getScanDetailCache(config);
   6967 
   6968         if (scanDetailCache == null) {
   6969             return null;
   6970         }
   6971 
   6972         return scanDetailCache.get(BSSID);
   6973     }
   6974 
   6975     String getCurrentBSSID() {
   6976         if (linkDebouncing) {
   6977             return null;
   6978         }
   6979         return mLastBssid;
   6980     }
   6981 
   6982     class ConnectModeState extends State {
   6983 
   6984         @Override
   6985         public void enter() {
   6986             connectScanningService();
   6987         }
   6988 
   6989         @Override
   6990         public boolean processMessage(Message message) {
   6991             WifiConfiguration config;
   6992             int netId;
   6993             boolean ok;
   6994             boolean didDisconnect;
   6995             String bssid;
   6996             String ssid;
   6997             NetworkUpdateResult result;
   6998             logStateAndMessage(message, getClass().getSimpleName());
   6999 
   7000             switch (message.what) {
   7001                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   7002                     mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_ASSOC_FAILURE);
   7003                     didBlackListBSSID = false;
   7004                     bssid = (String) message.obj;
   7005                     if (bssid == null || TextUtils.isEmpty(bssid)) {
   7006                         // If BSSID is null, use the target roam BSSID
   7007                         bssid = mTargetRoamBSSID;
   7008                     }
   7009                     if (bssid != null) {
   7010                         // If we have a BSSID, tell configStore to black list it
   7011                         synchronized(mScanResultCache) {
   7012                             didBlackListBSSID = mWifiConfigStore.handleBSSIDBlackList
   7013                                     (mLastNetworkId, bssid, false);
   7014                         }
   7015                     }
   7016                     mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
   7017                     break;
   7018                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   7019                     mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTH_FAILURE);
   7020                     mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
   7021                     break;
   7022                 case WifiMonitor.SSID_TEMP_DISABLED:
   7023                 case WifiMonitor.SSID_REENABLED:
   7024                     String substr = (String) message.obj;
   7025                     String en = message.what == WifiMonitor.SSID_TEMP_DISABLED ?
   7026                             "temp-disabled" : "re-enabled";
   7027                     logd("ConnectModeState SSID state=" + en + " nid="
   7028                             + Integer.toString(message.arg1) + " [" + substr + "]");
   7029                     synchronized(mScanResultCache) {
   7030                         mWifiConfigStore.handleSSIDStateChange(message.arg1, message.what ==
   7031                                 WifiMonitor.SSID_REENABLED, substr, mWifiInfo.getBSSID());
   7032                     }
   7033                     break;
   7034                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   7035                     SupplicantState state = handleSupplicantStateChange(message);
   7036                     // A driver/firmware hang can now put the interface in a down state.
   7037                     // We detect the interface going down and recover from it
   7038                     if (!SupplicantState.isDriverActive(state)) {
   7039                         if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
   7040                             handleNetworkDisconnect();
   7041                         }
   7042                         log("Detected an interface down, restart driver");
   7043                         transitionTo(mDriverStoppedState);
   7044                         sendMessage(CMD_START_DRIVER);
   7045                         break;
   7046                     }
   7047 
   7048                     // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
   7049                     // when authentication times out after a successful connection,
   7050                     // we can figure this from the supplicant state. If supplicant
   7051                     // state is DISCONNECTED, but the mNetworkInfo says we are not
   7052                     // disconnected, we need to handle a disconnection
   7053                     if (!linkDebouncing && state == SupplicantState.DISCONNECTED &&
   7054                             mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
   7055                         if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
   7056                         handleNetworkDisconnect();
   7057                         transitionTo(mDisconnectedState);
   7058                     }
   7059 
   7060                     // If we have COMPLETED a connection to a BSSID, start doing
   7061                     // DNAv4/DNAv6 -style probing for on-link neighbors of
   7062                     // interest (e.g. routers); harmless if none are configured.
   7063                     if (state == SupplicantState.COMPLETED) {
   7064                         if (mIpReachabilityMonitor != null) {
   7065                             mIpReachabilityMonitor.probeAll();
   7066                         }
   7067                     }
   7068                     break;
   7069                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
   7070                     if (message.arg1 == 1) {
   7071                         mWifiNative.disconnect();
   7072                         mTemporarilyDisconnectWifi = true;
   7073                     } else {
   7074                         mWifiNative.reconnect();
   7075                         mTemporarilyDisconnectWifi = false;
   7076                     }
   7077                     break;
   7078                 case CMD_ADD_OR_UPDATE_NETWORK:
   7079                     config = (WifiConfiguration) message.obj;
   7080 
   7081                     if (!recordUidIfAuthorized(config, message.sendingUid,
   7082                             /* onlyAnnotate */ false)) {
   7083                         logw("Not authorized to update network "
   7084                              + " config=" + config.SSID
   7085                              + " cnid=" + config.networkId
   7086                              + " uid=" + message.sendingUid);
   7087                         replyToMessage(message, message.what, FAILURE);
   7088                         break;
   7089                     }
   7090 
   7091                     int res = mWifiConfigStore.addOrUpdateNetwork(config, message.sendingUid);
   7092                     if (res < 0) {
   7093                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   7094                     } else {
   7095                         WifiConfiguration curConfig = getCurrentWifiConfiguration();
   7096                         if (curConfig != null && config != null) {
   7097                             if (curConfig.priority < config.priority
   7098                                     && config.status == WifiConfiguration.Status.ENABLED) {
   7099                                 // Interpret this as a connect attempt
   7100                                 // Set the last selected configuration so as to allow the system to
   7101                                 // stick the last user choice without persisting the choice
   7102                                 mWifiConfigStore.setLastSelectedConfiguration(res);
   7103                                 mWifiConfigStore.updateLastConnectUid(config, message.sendingUid);
   7104                                 mWifiConfigStore.writeKnownNetworkHistory(false);
   7105 
   7106                                 // Remember time of last connection attempt
   7107                                 lastConnectAttemptTimestamp = System.currentTimeMillis();
   7108 
   7109                                 mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
   7110 
   7111                                 // As a courtesy to the caller, trigger a scan now
   7112                                 startScan(ADD_OR_UPDATE_SOURCE, 0, null, null);
   7113                             }
   7114                         }
   7115                     }
   7116                     replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res);
   7117                     break;
   7118                 case CMD_REMOVE_NETWORK:
   7119                     netId = message.arg1;
   7120                     if (!mWifiConfigStore.canModifyNetwork(message.sendingUid, netId,
   7121                             /* onlyAnnotate */ false)) {
   7122                         logw("Not authorized to remove network "
   7123                              + " cnid=" + netId
   7124                              + " uid=" + message.sendingUid);
   7125                         replyToMessage(message, message.what, FAILURE);
   7126                         break;
   7127                     }
   7128 
   7129                     ok = mWifiConfigStore.removeNetwork(message.arg1);
   7130                     if (!ok) {
   7131                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   7132                     }
   7133                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
   7134                     break;
   7135                 case CMD_ENABLE_NETWORK:
   7136                     boolean disableOthers = message.arg2 == 1;
   7137                     netId = message.arg1;
   7138                     config = mWifiConfigStore.getWifiConfiguration(netId);
   7139                     if (config == null) {
   7140                         loge("No network with id = " + netId);
   7141                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   7142                         break;
   7143                     }
   7144 
   7145                     // Tell autojoin the user did try to select to that network
   7146                     // However, do NOT persist the choice by bumping the priority of the network
   7147                     if (disableOthers) {
   7148                         mWifiAutoJoinController.
   7149                                 updateConfigurationHistory(netId, true, false);
   7150                         // Set the last selected configuration so as to allow the system to
   7151                         // stick the last user choice without persisting the choice
   7152                         mWifiConfigStore.setLastSelectedConfiguration(netId);
   7153 
   7154                         // Remember time of last connection attempt
   7155                         lastConnectAttemptTimestamp = System.currentTimeMillis();
   7156 
   7157                         mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
   7158                     }
   7159                     // Cancel auto roam requests
   7160                     autoRoamSetBSSID(netId, "any");
   7161 
   7162                     int uid = message.sendingUid;
   7163                     ok = mWifiConfigStore.enableNetwork(netId, disableOthers, uid);
   7164                     if (!ok) {
   7165                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   7166                     }
   7167 
   7168                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
   7169                     break;
   7170                 case CMD_ENABLE_ALL_NETWORKS:
   7171                     long time = android.os.SystemClock.elapsedRealtime();
   7172                     if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
   7173                         mWifiConfigStore.enableAllNetworks();
   7174                         mLastEnableAllNetworksTime = time;
   7175                     }
   7176                     break;
   7177                 case WifiManager.DISABLE_NETWORK:
   7178                     if (mWifiConfigStore.disableNetwork(message.arg1,
   7179                             WifiConfiguration.DISABLED_BY_WIFI_MANAGER) == true) {
   7180                         replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
   7181                     } else {
   7182                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   7183                         replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
   7184                                 WifiManager.ERROR);
   7185                     }
   7186                     break;
   7187                 case CMD_DISABLE_EPHEMERAL_NETWORK:
   7188                     config = mWifiConfigStore.disableEphemeralNetwork((String)message.obj);
   7189                     if (config != null) {
   7190                         if (config.networkId == mLastNetworkId) {
   7191                             // Disconnect and let autojoin reselect a new network
   7192                             sendMessage(CMD_DISCONNECT);
   7193                         }
   7194                     }
   7195                     break;
   7196                 case CMD_BLACKLIST_NETWORK:
   7197                     mWifiConfigStore.blackListBssid((String) message.obj);
   7198                     break;
   7199                 case CMD_CLEAR_BLACKLIST:
   7200                     mWifiConfigStore.clearBssidBlacklist();
   7201                     break;
   7202                 case CMD_SAVE_CONFIG:
   7203                     ok = mWifiConfigStore.saveConfig();
   7204 
   7205                     if (DBG) logd("did save config " + ok);
   7206                     replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
   7207 
   7208                     // Inform the backup manager about a data change
   7209                     IBackupManager ibm = IBackupManager.Stub.asInterface(
   7210                             ServiceManager.getService(Context.BACKUP_SERVICE));
   7211                     if (ibm != null) {
   7212                         try {
   7213                             ibm.dataChanged("com.android.providers.settings");
   7214                         } catch (Exception e) {
   7215                             // Try again later
   7216                         }
   7217                     }
   7218                     break;
   7219                 case CMD_GET_CONFIGURED_NETWORKS:
   7220                     replyToMessage(message, message.what,
   7221                             mWifiConfigStore.getConfiguredNetworks());
   7222                     break;
   7223                 case WifiMonitor.SUP_REQUEST_IDENTITY:
   7224                     int networkId = message.arg2;
   7225                     boolean identitySent = false;
   7226                     int eapMethod = WifiEnterpriseConfig.Eap.NONE;
   7227 
   7228                     if (targetWificonfiguration != null
   7229                             && targetWificonfiguration.enterpriseConfig != null) {
   7230                         eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod();
   7231                     }
   7232 
   7233                     // For SIM & AKA/AKA' EAP method Only, get identity from ICC
   7234                     if (targetWificonfiguration != null
   7235                             && targetWificonfiguration.networkId == networkId
   7236                             && targetWificonfiguration.allowedKeyManagement
   7237                                     .get(WifiConfiguration.KeyMgmt.IEEE8021X)
   7238                             &&  (eapMethod == WifiEnterpriseConfig.Eap.SIM
   7239                             || eapMethod == WifiEnterpriseConfig.Eap.AKA
   7240                             || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)) {
   7241                         TelephonyManager tm = (TelephonyManager)
   7242                                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
   7243                         if (tm != null) {
   7244                             String imsi = tm.getSubscriberId();
   7245                             String mccMnc = "";
   7246 
   7247                             if (tm.getSimState() == TelephonyManager.SIM_STATE_READY)
   7248                                  mccMnc = tm.getSimOperator();
   7249 
   7250                             String identity = buildIdentity(eapMethod, imsi, mccMnc);
   7251 
   7252                             if (!identity.isEmpty()) {
   7253                                 mWifiNative.simIdentityResponse(networkId, identity);
   7254                                 identitySent = true;
   7255                             }
   7256                         }
   7257                     }
   7258                     if (!identitySent) {
   7259                         // Supplicant lacks credentials to connect to that network, hence black list
   7260                         ssid = (String) message.obj;
   7261                         if (targetWificonfiguration != null && ssid != null
   7262                                 && targetWificonfiguration.SSID != null
   7263                                 && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
   7264                             mWifiConfigStore.handleSSIDStateChange(
   7265                                     targetWificonfiguration.networkId, false,
   7266                                     "AUTH_FAILED no identity", null);
   7267                         }
   7268                         // Disconnect now, as we don't have any way to fullfill
   7269                         // the  supplicant request.
   7270                         mWifiConfigStore.setLastSelectedConfiguration(
   7271                                 WifiConfiguration.INVALID_NETWORK_ID);
   7272                         mWifiNative.disconnect();
   7273                     }
   7274                     break;
   7275                 case WifiMonitor.SUP_REQUEST_SIM_AUTH:
   7276                     logd("Received SUP_REQUEST_SIM_AUTH");
   7277                     SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
   7278                     if (requestData != null) {
   7279                         if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
   7280                             handleGsmAuthRequest(requestData);
   7281                         } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
   7282                             || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
   7283                             handle3GAuthRequest(requestData);
   7284                         }
   7285                     } else {
   7286                         loge("Invalid sim auth request");
   7287                     }
   7288                     break;
   7289                 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
   7290                     replyToMessage(message, message.what,
   7291                             mWifiConfigStore.getPrivilegedConfiguredNetworks());
   7292                     break;
   7293                 case CMD_GET_MATCHING_CONFIG:
   7294                     replyToMessage(message, message.what,
   7295                             mWifiConfigStore.getMatchingConfig((ScanResult)message.obj));
   7296                     break;
   7297                 /* Do a redundant disconnect without transition */
   7298                 case CMD_DISCONNECT:
   7299                     mWifiConfigStore.setLastSelectedConfiguration
   7300                             (WifiConfiguration.INVALID_NETWORK_ID);
   7301                     mWifiNative.disconnect();
   7302                     break;
   7303                 case CMD_RECONNECT:
   7304                     mWifiAutoJoinController.attemptAutoJoin();
   7305                     break;
   7306                 case CMD_REASSOCIATE:
   7307                     lastConnectAttemptTimestamp = System.currentTimeMillis();
   7308                     mWifiNative.reassociate();
   7309                     break;
   7310                 case CMD_RELOAD_TLS_AND_RECONNECT:
   7311                     if (mWifiConfigStore.needsUnlockedKeyStore()) {
   7312                         logd("Reconnecting to give a chance to un-connected TLS networks");
   7313                         mWifiNative.disconnect();
   7314                         lastConnectAttemptTimestamp = System.currentTimeMillis();
   7315                         mWifiNative.reconnect();
   7316                     }
   7317                     break;
   7318                 case CMD_AUTO_ROAM:
   7319                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   7320                     return HANDLED;
   7321                 case CMD_AUTO_CONNECT:
   7322                     /* Work Around: wpa_supplicant can get in a bad state where it returns a non
   7323                      * associated status to the STATUS command but somehow-someplace still thinks
   7324                      * it is associated and thus will ignore select/reconnect command with
   7325                      * following message:
   7326                      * "Already associated with the selected network - do nothing"
   7327                      *
   7328                      * Hence, sends a disconnect to supplicant first.
   7329                      */
   7330                     didDisconnect = false;
   7331                     if (getCurrentState() != mDisconnectedState) {
   7332                         /** Supplicant will ignore the reconnect if we are currently associated,
   7333                          * hence trigger a disconnect
   7334                          */
   7335                         didDisconnect = true;
   7336                         mWifiNative.disconnect();
   7337                     }
   7338 
   7339                     /* connect command coming from auto-join */
   7340                     config = (WifiConfiguration) message.obj;
   7341                     netId = message.arg1;
   7342                     int roam = message.arg2;
   7343                     logd("CMD_AUTO_CONNECT sup state "
   7344                             + mSupplicantStateTracker.getSupplicantStateName()
   7345                             + " my state " + getCurrentState().getName()
   7346                             + " nid=" + Integer.toString(netId)
   7347                             + " roam=" + Integer.toString(roam));
   7348                     if (config == null) {
   7349                         loge("AUTO_CONNECT and no config, bail out...");
   7350                         break;
   7351                     }
   7352 
   7353                     /* Make sure we cancel any previous roam request */
   7354                     autoRoamSetBSSID(netId, config.BSSID);
   7355 
   7356                     /* Save the network config */
   7357                     logd("CMD_AUTO_CONNECT will save config -> " + config.SSID
   7358                             + " nid=" + Integer.toString(netId));
   7359                     result = mWifiConfigStore.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
   7360                     netId = result.getNetworkId();
   7361                     logd("CMD_AUTO_CONNECT did save config -> "
   7362                             + " nid=" + Integer.toString(netId));
   7363 
   7364                     // Since we updated the config,read it back from config store:
   7365                     config = mWifiConfigStore.getWifiConfiguration(netId);
   7366                     if (config == null) {
   7367                         loge("CMD_AUTO_CONNECT couldn't update the config, got null config");
   7368                         break;
   7369                     }
   7370                     if (netId != config.networkId) {
   7371                         loge("CMD_AUTO_CONNECT couldn't update the config, want"
   7372                                 + " nid=" + Integer.toString(netId) + " but got" + config.networkId);
   7373                         break;
   7374                     }
   7375 
   7376                     if (deferForUserInput(message, netId, false)) {
   7377                         break;
   7378                     } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved ==
   7379                                                                    WifiConfiguration.USER_BANNED) {
   7380                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   7381                                 WifiManager.NOT_AUTHORIZED);
   7382                         break;
   7383                     }
   7384 
   7385                     // Make sure the network is enabled, since supplicant will not reenable it
   7386                     mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
   7387 
   7388                     // If we're autojoining a network that the user or an app explicitly selected,
   7389                     // keep track of the UID that selected it.
   7390                     int lastConnectUid = mWifiConfigStore.isLastSelectedConfiguration(config) ?
   7391                             config.lastConnectUid : WifiConfiguration.UNKNOWN_UID;
   7392 
   7393                     if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false,
   7394                             lastConnectUid) && mWifiNative.reconnect()) {
   7395                         lastConnectAttemptTimestamp = System.currentTimeMillis();
   7396                         targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
   7397                         config = mWifiConfigStore.getWifiConfiguration(netId);
   7398                         if (config != null
   7399                                 && !mWifiConfigStore.isLastSelectedConfiguration(config)) {
   7400                             // If we autojoined a different config than the user selected one,
   7401                             // it means we could not see the last user selection,
   7402                             // or that the last user selection was faulty and ended up blacklisted
   7403                             // for some reason (in which case the user is notified with an error
   7404                             // message in the Wifi picker), and thus we managed to auto-join away
   7405                             // from the selected  config. -> in that case we need to forget
   7406                             // the selection because we don't want to abruptly switch back to it.
   7407                             //
   7408                             // Note that the user selection is also forgotten after a period of time
   7409                             // during which the device has been disconnected.
   7410                             // The default value is 30 minutes : see the code path at bottom of
   7411                             // setScanResults() function.
   7412                             mWifiConfigStore.
   7413                                  setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
   7414                         }
   7415                         mAutoRoaming = roam;
   7416                         if (isRoaming() || linkDebouncing) {
   7417                             transitionTo(mRoamingState);
   7418                         } else if (didDisconnect) {
   7419                             transitionTo(mDisconnectingState);
   7420                         } else {
   7421                             /* Already in disconnected state, nothing to change */
   7422                             if (!mScreenOn && mLegacyPnoEnabled && mBackgroundScanSupported) {
   7423                                 int delay = 60 * 1000;
   7424                                 if (VDBG) {
   7425                                     logd("Starting PNO alarm: " + delay);
   7426                                 }
   7427                                 mAlarmManager.set(AlarmManager.RTC_WAKEUP,
   7428                                        System.currentTimeMillis() + delay,
   7429                                        mPnoIntent);
   7430                             }
   7431                             mRestartAutoJoinOffloadCounter++;
   7432                         }
   7433                     } else {
   7434                         loge("Failed to connect config: " + config + " netId: " + netId);
   7435                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   7436                                 WifiManager.ERROR);
   7437                         break;
   7438                     }
   7439                     break;
   7440                 case CMD_REMOVE_APP_CONFIGURATIONS:
   7441                     mWifiConfigStore.removeNetworksForApp((ApplicationInfo) message.obj);
   7442                     break;
   7443                 case CMD_REMOVE_USER_CONFIGURATIONS:
   7444                     mWifiConfigStore.removeNetworksForUser(message.arg1);
   7445                     break;
   7446                 case WifiManager.CONNECT_NETWORK:
   7447                     /**
   7448                      *  The connect message can contain a network id passed as arg1 on message or
   7449                      * or a config passed as obj on message.
   7450                      * For a new network, a config is passed to create and connect.
   7451                      * For an existing network, a network id is passed
   7452                      */
   7453                     netId = message.arg1;
   7454                     config = (WifiConfiguration) message.obj;
   7455                     mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
   7456                     boolean updatedExisting = false;
   7457 
   7458                     /* Save the network config */
   7459                     if (config != null) {
   7460                         // When connecting to an access point, WifiStateMachine wants to update the
   7461                         // relevant config with administrative data. This update should not be
   7462                         // considered a 'real' update, therefore lockdown by Device Owner must be
   7463                         // disregarded.
   7464                         if (!recordUidIfAuthorized(config, message.sendingUid,
   7465                                 /* onlyAnnotate */ true)) {
   7466                             logw("Not authorized to update network "
   7467                                  + " config=" + config.SSID
   7468                                  + " cnid=" + config.networkId
   7469                                  + " uid=" + message.sendingUid);
   7470                             replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   7471                                            WifiManager.NOT_AUTHORIZED);
   7472                             break;
   7473                         }
   7474 
   7475                         String configKey = config.configKey(true /* allowCached */);
   7476                         WifiConfiguration savedConfig =
   7477                                 mWifiConfigStore.getWifiConfiguration(configKey);
   7478                         if (savedConfig != null) {
   7479                             // There is an existing config with this netId, but it wasn't exposed
   7480                             // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigStore#
   7481                             // getConfiguredNetworks). Remove those bits and update the config.
   7482                             config = savedConfig;
   7483                             logd("CONNECT_NETWORK updating existing config with id=" +
   7484                                     config.networkId + " configKey=" + configKey);
   7485                             config.ephemeral = false;
   7486                             config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_ENABLED;
   7487                             updatedExisting = true;
   7488                         }
   7489 
   7490                         result = mWifiConfigStore.saveNetwork(config, message.sendingUid);
   7491                         netId = result.getNetworkId();
   7492                     }
   7493                     config = mWifiConfigStore.getWifiConfiguration(netId);
   7494 
   7495                     if (config == null) {
   7496                         logd("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " "
   7497                                 + mSupplicantStateTracker.getSupplicantStateName() + " my state "
   7498                                 + getCurrentState().getName());
   7499                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   7500                                 WifiManager.ERROR);
   7501                         break;
   7502                     } else {
   7503                         String wasSkipped = config.autoJoinBailedDueToLowRssi ? " skipped" : "";
   7504                         logd("CONNECT_NETWORK id=" + Integer.toString(netId)
   7505                                 + " config=" + config.SSID
   7506                                 + " cnid=" + config.networkId
   7507                                 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
   7508                                 + " my state " + getCurrentState().getName()
   7509                                 + " uid = " + message.sendingUid
   7510                                 + wasSkipped);
   7511                     }
   7512 
   7513                     autoRoamSetBSSID(netId, "any");
   7514 
   7515                     if (message.sendingUid == Process.WIFI_UID
   7516                         || message.sendingUid == Process.SYSTEM_UID) {
   7517                         // As a sanity measure, clear the BSSID in the supplicant network block.
   7518                         // If system or Wifi Settings want to connect, they will not
   7519                         // specify the BSSID.
   7520                         // If an app however had added a BSSID to this configuration, and the BSSID
   7521                         // was wrong, Then we would forever fail to connect until that BSSID
   7522                         // is cleaned up.
   7523                         clearConfigBSSID(config, "CONNECT_NETWORK");
   7524                     }
   7525 
   7526                     if (deferForUserInput(message, netId, true)) {
   7527                         break;
   7528                     } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved ==
   7529                                                                     WifiConfiguration.USER_BANNED) {
   7530                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   7531                                 WifiManager.NOT_AUTHORIZED);
   7532                         break;
   7533                     }
   7534 
   7535                     mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
   7536 
   7537                     /* Tell autojoin the user did try to connect to that network if from settings */
   7538                     boolean persist =
   7539                         mWifiConfigStore.checkConfigOverridePermission(message.sendingUid);
   7540                     mWifiAutoJoinController.updateConfigurationHistory(netId, true, persist);
   7541 
   7542                     mWifiConfigStore.setLastSelectedConfiguration(netId);
   7543 
   7544                     didDisconnect = false;
   7545                     if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
   7546                             && mLastNetworkId != netId) {
   7547                         /** Supplicant will ignore the reconnect if we are currently associated,
   7548                          * hence trigger a disconnect
   7549                          */
   7550                         didDisconnect = true;
   7551                         mWifiNative.disconnect();
   7552                     }
   7553 
   7554                     // Make sure the network is enabled, since supplicant will not reenable it
   7555                     mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
   7556 
   7557                     if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ true,
   7558                             message.sendingUid) && mWifiNative.reconnect()) {
   7559                         lastConnectAttemptTimestamp = System.currentTimeMillis();
   7560                         targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
   7561 
   7562                         /* The state tracker handles enabling networks upon completion/failure */
   7563                         mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
   7564                         replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
   7565                         if (didDisconnect) {
   7566                             /* Expect a disconnection from the old connection */
   7567                             transitionTo(mDisconnectingState);
   7568                         } else if (updatedExisting && getCurrentState() == mConnectedState &&
   7569                                 getCurrentWifiConfiguration().networkId == netId) {
   7570                             // Update the current set of network capabilities, but stay in the
   7571                             // current state.
   7572                             updateCapabilities(config);
   7573                         } else {
   7574                             /**
   7575                              *  Directly go to disconnected state where we
   7576                              * process the connection events from supplicant
   7577                              **/
   7578                             transitionTo(mDisconnectedState);
   7579                         }
   7580                     } else {
   7581                         loge("Failed to connect config: " + config + " netId: " + netId);
   7582                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   7583                                 WifiManager.ERROR);
   7584                         break;
   7585                     }
   7586                     break;
   7587                 case WifiManager.SAVE_NETWORK:
   7588                     mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
   7589                     // Fall thru
   7590                 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
   7591                     lastSavedConfigurationAttempt = null; // Used for debug
   7592                     config = (WifiConfiguration) message.obj;
   7593                     if (config == null) {
   7594                         loge("ERROR: SAVE_NETWORK with null configuration"
   7595                                 + mSupplicantStateTracker.getSupplicantStateName()
   7596                                 + " my state " + getCurrentState().getName());
   7597                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   7598                         replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
   7599                                 WifiManager.ERROR);
   7600                         break;
   7601                     }
   7602                     lastSavedConfigurationAttempt = new WifiConfiguration(config);
   7603                     int nid = config.networkId;
   7604                     logd("SAVE_NETWORK id=" + Integer.toString(nid)
   7605                                 + " config=" + config.SSID
   7606                                 + " nid=" + config.networkId
   7607                                 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
   7608                                 + " my state " + getCurrentState().getName());
   7609 
   7610                     // Only record the uid if this is user initiated
   7611                     boolean checkUid = (message.what == WifiManager.SAVE_NETWORK);
   7612                     if (checkUid && !recordUidIfAuthorized(config, message.sendingUid,
   7613                             /* onlyAnnotate */ false)) {
   7614                         logw("Not authorized to update network "
   7615                              + " config=" + config.SSID
   7616                              + " cnid=" + config.networkId
   7617                              + " uid=" + message.sendingUid);
   7618                         replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
   7619                                        WifiManager.NOT_AUTHORIZED);
   7620                         break;
   7621                     }
   7622 
   7623                     result = mWifiConfigStore.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
   7624                     if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
   7625                         if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
   7626                             if (result.hasIpChanged()) {
   7627                                 // The currently connection configuration was changed
   7628                                 // We switched from DHCP to static or from static to DHCP, or the
   7629                                 // static IP address has changed.
   7630                                 log("Reconfiguring IP on connection");
   7631                                 // TODO: clear addresses and disable IPv6
   7632                                 // to simplify obtainingIpState.
   7633                                 transitionTo(mObtainingIpState);
   7634                             }
   7635                             if (result.hasProxyChanged()) {
   7636                                 log("Reconfiguring proxy on connection");
   7637                                 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES);
   7638                             }
   7639                         }
   7640                         replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
   7641                         broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
   7642 
   7643                         if (VDBG) {
   7644                            logd("Success save network nid="
   7645                                     + Integer.toString(result.getNetworkId()));
   7646                         }
   7647 
   7648                         synchronized(mScanResultCache) {
   7649                             /**
   7650                              * If the command comes from WifiManager, then
   7651                              * tell autojoin the user did try to modify and save that network,
   7652                              * and interpret the SAVE_NETWORK as a request to connect
   7653                              */
   7654                             boolean user = message.what == WifiManager.SAVE_NETWORK;
   7655 
   7656                             // Did this connect come from settings
   7657                             boolean persistConnect =
   7658                                 mWifiConfigStore.checkConfigOverridePermission(message.sendingUid);
   7659 
   7660                             if (user) {
   7661                                 mWifiConfigStore.updateLastConnectUid(config, message.sendingUid);
   7662                                 mWifiConfigStore.writeKnownNetworkHistory(false);
   7663                             }
   7664 
   7665                             mWifiAutoJoinController.updateConfigurationHistory(result.getNetworkId()
   7666                                     , user, persistConnect);
   7667                             mWifiAutoJoinController.attemptAutoJoin();
   7668                         }
   7669                     } else {
   7670                         loge("Failed to save network");
   7671                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   7672                         replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
   7673                                 WifiManager.ERROR);
   7674                     }
   7675                     break;
   7676                 case WifiManager.FORGET_NETWORK:
   7677                     // Debug only, remember last configuration that was forgotten
   7678                     WifiConfiguration toRemove
   7679                             = mWifiConfigStore.getWifiConfiguration(message.arg1);
   7680                     if (toRemove == null) {
   7681                         lastForgetConfigurationAttempt = null;
   7682                     } else {
   7683                         lastForgetConfigurationAttempt = new WifiConfiguration(toRemove);
   7684                     }
   7685                     // check that the caller owns this network
   7686                     netId = message.arg1;
   7687 
   7688                     if (!mWifiConfigStore.canModifyNetwork(message.sendingUid, netId,
   7689                             /* onlyAnnotate */ false)) {
   7690                         logw("Not authorized to forget network "
   7691                              + " cnid=" + netId
   7692                              + " uid=" + message.sendingUid);
   7693                         replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
   7694                                 WifiManager.NOT_AUTHORIZED);
   7695                         break;
   7696                     }
   7697 
   7698                     if (mWifiConfigStore.forgetNetwork(message.arg1)) {
   7699                         replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
   7700                         broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT,
   7701                                 (WifiConfiguration) message.obj);
   7702                     } else {
   7703                         loge("Failed to forget network");
   7704                         replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
   7705                                 WifiManager.ERROR);
   7706                     }
   7707                     break;
   7708                 case WifiManager.START_WPS:
   7709                     WpsInfo wpsInfo = (WpsInfo) message.obj;
   7710                     WpsResult wpsResult;
   7711                     switch (wpsInfo.setup) {
   7712                         case WpsInfo.PBC:
   7713                             wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo);
   7714                             break;
   7715                         case WpsInfo.KEYPAD:
   7716                             wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo);
   7717                             break;
   7718                         case WpsInfo.DISPLAY:
   7719                             wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo);
   7720                             break;
   7721                         default:
   7722                             wpsResult = new WpsResult(Status.FAILURE);
   7723                             loge("Invalid setup for WPS");
   7724                             break;
   7725                     }
   7726                     mWifiConfigStore.setLastSelectedConfiguration
   7727                             (WifiConfiguration.INVALID_NETWORK_ID);
   7728                     if (wpsResult.status == Status.SUCCESS) {
   7729                         replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
   7730                         transitionTo(mWpsRunningState);
   7731                     } else {
   7732                         loge("Failed to start WPS with config " + wpsInfo.toString());
   7733                         replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
   7734                     }
   7735                     break;
   7736                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   7737                     if (DBG) log("Network connection established");
   7738                     mLastNetworkId = message.arg1;
   7739                     mLastBssid = (String) message.obj;
   7740 
   7741                     mWifiInfo.setBSSID(mLastBssid);
   7742                     mWifiInfo.setNetworkId(mLastNetworkId);
   7743 
   7744                     sendNetworkStateChangeBroadcast(mLastBssid);
   7745                     transitionTo(mObtainingIpState);
   7746                     break;
   7747                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   7748                     // Calling handleNetworkDisconnect here is redundant because we might already
   7749                     // have called it when leaving L2ConnectedState to go to disconnecting state
   7750                     // or thru other path
   7751                     // We should normally check the mWifiInfo or mLastNetworkId so as to check
   7752                     // if they are valid, and only in this case call handleNEtworkDisconnect,
   7753                     // TODO: this should be fixed for a L MR release
   7754                     // The side effect of calling handleNetworkDisconnect twice is that a bunch of
   7755                     // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
   7756                     // at the chip etc...
   7757                     if (DBG) log("ConnectModeState: Network connection lost ");
   7758                     handleNetworkDisconnect();
   7759                     transitionTo(mDisconnectedState);
   7760                     break;
   7761                 case CMD_PNO_NETWORK_FOUND:
   7762                     processPnoNetworkFound((ScanResult[])message.obj);
   7763                     break;
   7764                 default:
   7765                     return NOT_HANDLED;
   7766             }
   7767             return HANDLED;
   7768         }
   7769     }
   7770 
   7771     private void updateCapabilities(WifiConfiguration config) {
   7772         if (config.ephemeral) {
   7773             mNetworkCapabilities.removeCapability(
   7774                     NetworkCapabilities.NET_CAPABILITY_TRUSTED);
   7775         } else {
   7776             mNetworkCapabilities.addCapability(
   7777                     NetworkCapabilities.NET_CAPABILITY_TRUSTED);
   7778         }
   7779         mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
   7780     }
   7781 
   7782     private class WifiNetworkAgent extends NetworkAgent {
   7783         public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
   7784                 NetworkCapabilities nc, LinkProperties lp, int score) {
   7785             super(l, c, TAG, ni, nc, lp, score);
   7786         }
   7787         protected void unwanted() {
   7788             // Ignore if we're not the current networkAgent.
   7789             if (this != mNetworkAgent) return;
   7790             if (DBG) log("WifiNetworkAgent -> Wifi unwanted score "
   7791                     + Integer.toString(mWifiInfo.score));
   7792             unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
   7793         }
   7794 
   7795         @Override
   7796         protected void networkStatus(int status) {
   7797             if (this != mNetworkAgent) return;
   7798             if (status == NetworkAgent.INVALID_NETWORK) {
   7799                 if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid, score="
   7800                         + Integer.toString(mWifiInfo.score));
   7801                 unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
   7802             } else if (status == NetworkAgent.VALID_NETWORK) {
   7803                 if (DBG && mWifiInfo != null) log("WifiNetworkAgent -> Wifi networkStatus valid, score= "
   7804                         + Integer.toString(mWifiInfo.score));
   7805                 doNetworkStatus(status);
   7806             }
   7807         }
   7808 
   7809         @Override
   7810         protected void saveAcceptUnvalidated(boolean accept) {
   7811             if (this != mNetworkAgent) return;
   7812             WifiStateMachine.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
   7813         }
   7814 
   7815         @Override
   7816         protected void preventAutomaticReconnect() {
   7817             if (this != mNetworkAgent) return;
   7818             unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
   7819         }
   7820     }
   7821 
   7822     void unwantedNetwork(int reason) {
   7823         sendMessage(CMD_UNWANTED_NETWORK, reason);
   7824     }
   7825 
   7826     void doNetworkStatus(int status) {
   7827         sendMessage(CMD_NETWORK_STATUS, status);
   7828     }
   7829 
   7830     // rfc4186 & rfc4187:
   7831     // create Permanent Identity base on IMSI,
   7832     // identity = usernam@realm
   7833     // with username = prefix | IMSI
   7834     // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
   7835     private String buildIdentity(int eapMethod, String imsi, String mccMnc) {
   7836         String mcc;
   7837         String mnc;
   7838         String prefix;
   7839 
   7840         if (imsi == null || imsi.isEmpty())
   7841             return "";
   7842 
   7843         if (eapMethod == WifiEnterpriseConfig.Eap.SIM)
   7844             prefix = "1";
   7845         else if (eapMethod == WifiEnterpriseConfig.Eap.AKA)
   7846             prefix = "0";
   7847         else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)
   7848             prefix = "6";
   7849         else  // not a valide EapMethod
   7850             return "";
   7851 
   7852         /* extract mcc & mnc from mccMnc */
   7853         if (mccMnc != null && !mccMnc.isEmpty()) {
   7854             mcc = mccMnc.substring(0, 3);
   7855             mnc = mccMnc.substring(3);
   7856             if (mnc.length() == 2)
   7857                 mnc = "0" + mnc;
   7858         } else {
   7859             // extract mcc & mnc from IMSI, assume mnc size is 3
   7860             mcc = imsi.substring(0, 3);
   7861             mnc = imsi.substring(3, 6);
   7862         }
   7863 
   7864         return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
   7865     }
   7866 
   7867     boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) {
   7868         if (config == null)
   7869             return false;
   7870 
   7871         // We are still seeing a fairly high power consumption triggered by autojoin scans
   7872         // Hence do partial scans only for PSK configuration that are roamable since the
   7873         // primary purpose of the partial scans is roaming.
   7874         // Full badn scans with exponential backoff for the purpose or extended roaming and
   7875         // network switching are performed unconditionally.
   7876         ScanDetailCache scanDetailCache =
   7877                 mWifiConfigStore.getScanDetailCache(config);
   7878         if (scanDetailCache == null
   7879                 || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
   7880                 || scanDetailCache.size() > 6) {
   7881             //return true but to not trigger the scan
   7882             return true;
   7883         }
   7884         HashSet<Integer> channels = mWifiConfigStore.makeChannelList(config,
   7885                 ONE_HOUR_MILLI, restrictChannelList);
   7886         if (channels != null && channels.size() != 0) {
   7887             StringBuilder freqs = new StringBuilder();
   7888             boolean first = true;
   7889             for (Integer channel : channels) {
   7890                 if (!first)
   7891                     freqs.append(",");
   7892                 freqs.append(channel.toString());
   7893                 first = false;
   7894             }
   7895             //if (DBG) {
   7896             logd("starting scan for " + config.configKey() + " with " + freqs);
   7897             //}
   7898             // Call wifi native to start the scan
   7899             if (startScanNative(
   7900                     WifiNative.SCAN_WITHOUT_CONNECTION_SETUP,
   7901                     freqs.toString())) {
   7902                 // Only count battery consumption if scan request is accepted
   7903                 noteScanStart(SCAN_ALARM_SOURCE, null);
   7904                 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
   7905             } else {
   7906                 // used for debug only, mark scan as failed
   7907                 messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
   7908             }
   7909             return true;
   7910         } else {
   7911             if (DBG) logd("no channels for " + config.configKey());
   7912             return false;
   7913         }
   7914     }
   7915 
   7916     void clearCurrentConfigBSSID(String dbg) {
   7917         // Clear the bssid in the current config's network block
   7918         WifiConfiguration config = getCurrentWifiConfiguration();
   7919         if (config == null)
   7920             return;
   7921         clearConfigBSSID(config, dbg);
   7922     }
   7923     void clearConfigBSSID(WifiConfiguration config, String dbg) {
   7924         if (config == null)
   7925             return;
   7926         if (DBG) {
   7927             logd(dbg + " " + mTargetRoamBSSID + " config " + config.configKey()
   7928                     + " config.bssid " + config.BSSID);
   7929         }
   7930         config.autoJoinBSSID = "any";
   7931         config.BSSID = "any";
   7932         if (DBG) {
   7933            logd(dbg + " " + config.SSID
   7934                     + " nid=" + Integer.toString(config.networkId));
   7935         }
   7936         mWifiConfigStore.saveWifiConfigBSSID(config);
   7937     }
   7938 
   7939     class L2ConnectedState extends State {
   7940         @Override
   7941         public void enter() {
   7942             mRssiPollToken++;
   7943             if (mEnableRssiPolling) {
   7944                 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
   7945             }
   7946             if (mNetworkAgent != null) {
   7947                 loge("Have NetworkAgent when entering L2Connected");
   7948                 setNetworkDetailedState(DetailedState.DISCONNECTED);
   7949             }
   7950             setNetworkDetailedState(DetailedState.CONNECTING);
   7951 
   7952             if (!TextUtils.isEmpty(mTcpBufferSizes)) {
   7953                 mLinkProperties.setTcpBufferSizes(mTcpBufferSizes);
   7954             }
   7955             mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
   7956                     "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
   7957                     mLinkProperties, 60);
   7958 
   7959             // We must clear the config BSSID, as the wifi chipset may decide to roam
   7960             // from this point on and having the BSSID specified in the network block would
   7961             // cause the roam to faile and the device to disconnect
   7962             clearCurrentConfigBSSID("L2ConnectedState");
   7963 
   7964             try {
   7965                 mIpReachabilityMonitor = new IpReachabilityMonitor(
   7966                         mInterfaceName,
   7967                         new IpReachabilityMonitor.Callback() {
   7968                             @Override
   7969                             public void notifyLost(InetAddress ip, String logMsg) {
   7970                                 sendMessage(CMD_IP_REACHABILITY_LOST, logMsg);
   7971                             }
   7972                         });
   7973             } catch (IllegalArgumentException e) {
   7974                 Log.wtf("Failed to create IpReachabilityMonitor", e);
   7975             }
   7976         }
   7977 
   7978         @Override
   7979         public void exit() {
   7980             if (mIpReachabilityMonitor != null) {
   7981                 mIpReachabilityMonitor.stop();
   7982                 mIpReachabilityMonitor = null;
   7983             }
   7984 
   7985             // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
   7986             // Bug: 15347363
   7987             // For paranoia's sake, call handleNetworkDisconnect
   7988             // only if BSSID is null or last networkId
   7989             // is not invalid.
   7990             if (DBG) {
   7991                 StringBuilder sb = new StringBuilder();
   7992                 sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
   7993                 if (mLastBssid !=null) {
   7994                     sb.append(" ").append(mLastBssid);
   7995                 }
   7996             }
   7997             if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
   7998                 handleNetworkDisconnect();
   7999             }
   8000         }
   8001 
   8002         @Override
   8003         public boolean processMessage(Message message) {
   8004             logStateAndMessage(message, getClass().getSimpleName());
   8005 
   8006             switch (message.what) {
   8007               case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
   8008                   handlePreDhcpSetup();
   8009                   break;
   8010               case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   8011                   handlePostDhcpSetup();
   8012                   if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
   8013                       if (DBG) log("DHCP successful");
   8014                       handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS);
   8015                       // We advance to mConnectedState because handleIPv4Success will call
   8016                       // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL.
   8017                   } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
   8018                       mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_DHCP_FAILURE);
   8019                       if (DBG) {
   8020                           int count = -1;
   8021                           WifiConfiguration config = getCurrentWifiConfiguration();
   8022                           if (config != null) {
   8023                               count = config.numConnectionFailures;
   8024                           }
   8025                           log("DHCP failure count=" + count);
   8026                       }
   8027                       handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE);
   8028                       // As above, we transition to mDisconnectingState via updateLinkProperties.
   8029                   }
   8030                   break;
   8031                 case CMD_IP_CONFIGURATION_SUCCESSFUL:
   8032                     handleSuccessfulIpConfiguration();
   8033                     sendConnectedState();
   8034                     transitionTo(mConnectedState);
   8035                     break;
   8036                 case CMD_IP_CONFIGURATION_LOST:
   8037                     // Get Link layer stats so that we get fresh tx packet counters.
   8038                     getWifiLinkLayerStats(true);
   8039                     handleIpConfigurationLost();
   8040                     transitionTo(mDisconnectingState);
   8041                     break;
   8042                 case CMD_IP_REACHABILITY_LOST:
   8043                     if (DBG && message.obj != null) log((String) message.obj);
   8044                     handleIpReachabilityLost();
   8045                     transitionTo(mDisconnectingState);
   8046                     break;
   8047                 case CMD_DISCONNECT:
   8048                     mWifiNative.disconnect();
   8049                     transitionTo(mDisconnectingState);
   8050                     break;
   8051                 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
   8052                     if (message.arg1 == 1) {
   8053                         mWifiNative.disconnect();
   8054                         mTemporarilyDisconnectWifi = true;
   8055                         transitionTo(mDisconnectingState);
   8056                     }
   8057                     break;
   8058                 case CMD_SET_OPERATIONAL_MODE:
   8059                     if (message.arg1 != CONNECT_MODE) {
   8060                         sendMessage(CMD_DISCONNECT);
   8061                         deferMessage(message);
   8062                         if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
   8063                             noteWifiDisabledWhileAssociated();
   8064                         }
   8065                     }
   8066                     mWifiConfigStore.
   8067                                 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
   8068                     break;
   8069                 case CMD_SET_COUNTRY_CODE:
   8070                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   8071                     deferMessage(message);
   8072                     break;
   8073                 case CMD_START_SCAN:
   8074                     if (DBG) {
   8075                         logd("CMD_START_SCAN source " + message.arg1
   8076                               + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate)
   8077                               + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate)
   8078                               + " targetRoamBSSID=" + mTargetRoamBSSID
   8079                               + " RSSI=" + mWifiInfo.getRssi());
   8080                     }
   8081                     if (message.arg1 == SCAN_ALARM_SOURCE) {
   8082                         // Check if the CMD_START_SCAN message is obsolete (and thus if it should
   8083                         // not be processed) and restart the scan if neede
   8084                         if (!getEnableAutoJoinWhenAssociated()) {
   8085                             return HANDLED;
   8086                         }
   8087                         boolean shouldScan = mScreenOn;
   8088 
   8089                         if (!checkAndRestartDelayedScan(message.arg2,
   8090                                 shouldScan,
   8091                                 mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get(),
   8092                                 null, null)) {
   8093                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
   8094                             logd("L2Connected CMD_START_SCAN source "
   8095                                     + message.arg1
   8096                                     + " " + message.arg2 + ", " + mDelayedScanCounter
   8097                                     + " -> obsolete");
   8098                             return HANDLED;
   8099                         }
   8100                         if (mP2pConnected.get()) {
   8101                             logd("L2Connected CMD_START_SCAN source "
   8102                                     + message.arg1
   8103                                     + " " + message.arg2 + ", " + mDelayedScanCounter
   8104                                     + " ignore because P2P is connected");
   8105                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   8106                             return HANDLED;
   8107                         }
   8108                         boolean tryFullBandScan = false;
   8109                         boolean restrictChannelList = false;
   8110                         long now_ms = System.currentTimeMillis();
   8111                         if (DBG) {
   8112                             logd("CMD_START_SCAN with age="
   8113                                     + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
   8114                                     + " interval=" + fullBandConnectedTimeIntervalMilli
   8115                                     + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
   8116                         }
   8117                         if (mWifiInfo != null) {
   8118                             if (mWifiConfigStore.enableFullBandScanWhenAssociated.get() &&
   8119                                     (now_ms - lastFullBandConnectedTimeMilli)
   8120                                     > fullBandConnectedTimeIntervalMilli) {
   8121                                 if (DBG) {
   8122                                     logd("CMD_START_SCAN try full band scan age="
   8123                                          + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
   8124                                          + " interval=" + fullBandConnectedTimeIntervalMilli
   8125                                          + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
   8126                                 }
   8127                                 tryFullBandScan = true;
   8128                             }
   8129 
   8130                             if (mWifiInfo.txSuccessRate >
   8131                                     mWifiConfigStore.maxTxPacketForFullScans
   8132                                     || mWifiInfo.rxSuccessRate >
   8133                                     mWifiConfigStore.maxRxPacketForFullScans) {
   8134                                 // Too much traffic at the interface, hence no full band scan
   8135                                 if (DBG) {
   8136                                     logd("CMD_START_SCAN " +
   8137                                             "prevent full band scan due to pkt rate");
   8138                                 }
   8139                                 tryFullBandScan = false;
   8140                             }
   8141 
   8142                             if (mWifiInfo.txSuccessRate >
   8143                                     mWifiConfigStore.maxTxPacketForPartialScans
   8144                                     || mWifiInfo.rxSuccessRate >
   8145                                     mWifiConfigStore.maxRxPacketForPartialScans) {
   8146                                 // Don't scan if lots of packets are being sent
   8147                                 restrictChannelList = true;
   8148                                 if (mWifiConfigStore.alwaysEnableScansWhileAssociated.get() == 0) {
   8149                                     if (DBG) {
   8150                                      logd("CMD_START_SCAN source " + message.arg1
   8151                                         + " ...and ignore scans"
   8152                                         + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate)
   8153                                         + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate));
   8154                                     }
   8155                                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
   8156                                     return HANDLED;
   8157                                 }
   8158                             }
   8159                         }
   8160 
   8161                         WifiConfiguration currentConfiguration = getCurrentWifiConfiguration();
   8162                         if (DBG) {
   8163                             logd("CMD_START_SCAN full=" +
   8164                                     tryFullBandScan);
   8165                         }
   8166                         if (currentConfiguration != null) {
   8167                             if (fullBandConnectedTimeIntervalMilli
   8168                                     < mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get()) {
   8169                                 // Sanity
   8170                                 fullBandConnectedTimeIntervalMilli
   8171                                         = mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get();
   8172                             }
   8173                             if (tryFullBandScan) {
   8174                                 lastFullBandConnectedTimeMilli = now_ms;
   8175                                 if (fullBandConnectedTimeIntervalMilli
   8176                                         < mWifiConfigStore.associatedFullScanMaxIntervalMilli) {
   8177                                     // Increase the interval
   8178                                     fullBandConnectedTimeIntervalMilli
   8179                                             = fullBandConnectedTimeIntervalMilli
   8180                                             * mWifiConfigStore.associatedFullScanBackoff.get() / 8;
   8181 
   8182                                     if (DBG) {
   8183                                         logd("CMD_START_SCAN bump interval ="
   8184                                         + fullBandConnectedTimeIntervalMilli);
   8185                                     }
   8186                                 }
   8187                                 handleScanRequest(
   8188                                         WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
   8189                             } else {
   8190                                 if (!startScanForConfiguration(
   8191                                         currentConfiguration, restrictChannelList)) {
   8192                                     if (DBG) {
   8193                                         logd("starting scan, " +
   8194                                                 " did not find channels -> full");
   8195                                     }
   8196                                     lastFullBandConnectedTimeMilli = now_ms;
   8197                                     if (fullBandConnectedTimeIntervalMilli
   8198                                             < mWifiConfigStore.associatedFullScanMaxIntervalMilli) {
   8199                                         // Increase the interval
   8200                                         fullBandConnectedTimeIntervalMilli
   8201                                                 = fullBandConnectedTimeIntervalMilli
   8202                                                 * mWifiConfigStore.associatedFullScanBackoff.get() / 8;
   8203 
   8204                                         if (DBG) {
   8205                                             logd("CMD_START_SCAN bump interval ="
   8206                                                     + fullBandConnectedTimeIntervalMilli);
   8207                                         }
   8208                                     }
   8209                                     handleScanRequest(
   8210                                                 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
   8211                                 }
   8212                             }
   8213 
   8214                         } else {
   8215                             logd("CMD_START_SCAN : connected mode and no configuration");
   8216                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
   8217                         }
   8218                     } else {
   8219                         // Not scan alarm source
   8220                         return NOT_HANDLED;
   8221                     }
   8222                     break;
   8223                     /* Ignore connection to same network */
   8224                 case WifiManager.CONNECT_NETWORK:
   8225                     int netId = message.arg1;
   8226                     if (mWifiInfo.getNetworkId() == netId) {
   8227                         break;
   8228                     }
   8229                     return NOT_HANDLED;
   8230                     /* Ignore */
   8231                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   8232                     break;
   8233                 case CMD_RSSI_POLL:
   8234                     if (message.arg1 == mRssiPollToken) {
   8235                         if (mWifiConfigStore.enableChipWakeUpWhenAssociated.get()) {
   8236                             if (VVDBG) log(" get link layer stats " + mWifiLinkLayerStatsSupported);
   8237                             WifiLinkLayerStats stats = getWifiLinkLayerStats(VDBG);
   8238                             if (stats != null) {
   8239                                 // Sanity check the results provided by driver
   8240                                 if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
   8241                                         && (stats.rssi_mgmt == 0
   8242                                         || stats.beacon_rx == 0)) {
   8243                                     stats = null;
   8244                                 }
   8245                             }
   8246                             // Get Info and continue polling
   8247                             fetchRssiLinkSpeedAndFrequencyNative();
   8248                             calculateWifiScore(stats);
   8249                         }
   8250                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
   8251                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
   8252 
   8253                         if (DBG) sendRssiChangeBroadcast(mWifiInfo.getRssi());
   8254                     } else {
   8255                         // Polling has completed
   8256                     }
   8257                     break;
   8258                 case CMD_ENABLE_RSSI_POLL:
   8259                     cleanWifiScore();
   8260                     if (mWifiConfigStore.enableRssiPollWhenAssociated.get()) {
   8261                         mEnableRssiPolling = (message.arg1 == 1);
   8262                     } else {
   8263                         mEnableRssiPolling = false;
   8264                     }
   8265                     mRssiPollToken++;
   8266                     if (mEnableRssiPolling) {
   8267                         // First poll
   8268                         fetchRssiLinkSpeedAndFrequencyNative();
   8269                         sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
   8270                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
   8271                     }
   8272                     break;
   8273                 case WifiManager.RSSI_PKTCNT_FETCH:
   8274                     RssiPacketCountInfo info = new RssiPacketCountInfo();
   8275                     fetchRssiLinkSpeedAndFrequencyNative();
   8276                     info.rssi = mWifiInfo.getRssi();
   8277                     fetchPktcntNative(info);
   8278                     replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
   8279                     break;
   8280                 case CMD_DELAYED_NETWORK_DISCONNECT:
   8281                     if (!linkDebouncing && mWifiConfigStore.enableLinkDebouncing) {
   8282 
   8283                         // Ignore if we are not debouncing
   8284                         logd("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore "
   8285                                 + message.arg1);
   8286                         return HANDLED;
   8287                     } else {
   8288                         logd("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect "
   8289                                 + message.arg1);
   8290 
   8291                         linkDebouncing = false;
   8292                         // If we are still debouncing while this message comes,
   8293                         // it means we were not able to reconnect within the alloted time
   8294                         // = LINK_FLAPPING_DEBOUNCE_MSEC
   8295                         // and thus, trigger a real disconnect
   8296                         handleNetworkDisconnect();
   8297                         transitionTo(mDisconnectedState);
   8298                     }
   8299                     break;
   8300                 case CMD_ASSOCIATED_BSSID:
   8301                     if ((String) message.obj == null) {
   8302                         logw("Associated command w/o BSSID");
   8303                         break;
   8304                     }
   8305                     mLastBssid = (String) message.obj;
   8306                     if (mLastBssid != null
   8307                             && (mWifiInfo.getBSSID() == null
   8308                             || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
   8309                         mWifiInfo.setBSSID((String) message.obj);
   8310                         sendNetworkStateChangeBroadcast(mLastBssid);
   8311                     }
   8312                     break;
   8313                 default:
   8314                     return NOT_HANDLED;
   8315             }
   8316 
   8317             return HANDLED;
   8318         }
   8319     }
   8320 
   8321     class ObtainingIpState extends State {
   8322         @Override
   8323         public void enter() {
   8324             if (DBG) {
   8325                 String key = "";
   8326                 if (getCurrentWifiConfiguration() != null) {
   8327                     key = getCurrentWifiConfiguration().configKey();
   8328                 }
   8329                 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
   8330                         + " " + key + " "
   8331                         + " roam=" + mAutoRoaming
   8332                         + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId)
   8333                         + " watchdog= " + obtainingIpWatchdogCount);
   8334             }
   8335 
   8336             // Reset link Debouncing, indicating we have successfully re-connected to the AP
   8337             // We might still be roaming
   8338             linkDebouncing = false;
   8339 
   8340             // Send event to CM & network change broadcast
   8341             setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
   8342 
   8343             // We must clear the config BSSID, as the wifi chipset may decide to roam
   8344             // from this point on and having the BSSID specified in the network block would
   8345             // cause the roam to faile and the device to disconnect
   8346             clearCurrentConfigBSSID("ObtainingIpAddress");
   8347 
   8348             try {
   8349                 mNwService.enableIpv6(mInterfaceName);
   8350             } catch (RemoteException re) {
   8351                 loge("Failed to enable IPv6: " + re);
   8352             } catch (IllegalStateException e) {
   8353                 loge("Failed to enable IPv6: " + e);
   8354             }
   8355 
   8356             if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
   8357                 if (isRoaming()) {
   8358                     renewDhcp();
   8359                 } else {
   8360                     // Remove any IP address on the interface in case we're switching from static
   8361                     // IP configuration to DHCP. This is safe because if we get here when not
   8362                     // roaming, we don't have a usable address.
   8363                     clearIPv4Address(mInterfaceName);
   8364                     startDhcp();
   8365                 }
   8366                 obtainingIpWatchdogCount++;
   8367                 logd("Start Dhcp Watchdog " + obtainingIpWatchdogCount);
   8368                 // Get Link layer stats so as we get fresh tx packet counters
   8369                 getWifiLinkLayerStats(true);
   8370                 sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER,
   8371                         obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC);
   8372             } else {
   8373                 // stop any running dhcp before assigning static IP
   8374                 stopDhcp();
   8375                 StaticIpConfiguration config = mWifiConfigStore.getStaticIpConfiguration(
   8376                         mLastNetworkId);
   8377                 if (config.ipAddress == null) {
   8378                     logd("Static IP lacks address");
   8379                     sendMessage(CMD_STATIC_IP_FAILURE);
   8380                 } else {
   8381                     InterfaceConfiguration ifcg = new InterfaceConfiguration();
   8382                     ifcg.setLinkAddress(config.ipAddress);
   8383                     ifcg.setInterfaceUp();
   8384                     try {
   8385                         mNwService.setInterfaceConfig(mInterfaceName, ifcg);
   8386                         if (DBG) log("Static IP configuration succeeded");
   8387                         DhcpResults dhcpResults = new DhcpResults(config);
   8388                         sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults);
   8389                     } catch (RemoteException re) {
   8390                         loge("Static IP configuration failed: " + re);
   8391                         sendMessage(CMD_STATIC_IP_FAILURE);
   8392                     } catch (IllegalStateException e) {
   8393                         loge("Static IP configuration failed: " + e);
   8394                         sendMessage(CMD_STATIC_IP_FAILURE);
   8395                     }
   8396                 }
   8397             }
   8398         }
   8399       @Override
   8400       public boolean processMessage(Message message) {
   8401           logStateAndMessage(message, getClass().getSimpleName());
   8402 
   8403           switch(message.what) {
   8404               case CMD_STATIC_IP_SUCCESS:
   8405                   handleIPv4Success((DhcpResults) message.obj, CMD_STATIC_IP_SUCCESS);
   8406                   break;
   8407               case CMD_STATIC_IP_FAILURE:
   8408                   handleIPv4Failure(CMD_STATIC_IP_FAILURE);
   8409                   break;
   8410               case CMD_AUTO_CONNECT:
   8411               case CMD_AUTO_ROAM:
   8412                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   8413                   break;
   8414               case WifiManager.SAVE_NETWORK:
   8415               case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
   8416                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   8417                   deferMessage(message);
   8418                   break;
   8419                   /* Defer any power mode changes since we must keep active power mode at DHCP */
   8420               case CMD_SET_HIGH_PERF_MODE:
   8421                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   8422                   deferMessage(message);
   8423                   break;
   8424                   /* Defer scan request since we should not switch to other channels at DHCP */
   8425               case CMD_START_SCAN:
   8426                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
   8427                   deferMessage(message);
   8428                   break;
   8429               case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
   8430                   if (message.arg1 == obtainingIpWatchdogCount) {
   8431                       logd("ObtainingIpAddress: Watchdog Triggered, count="
   8432                               + obtainingIpWatchdogCount);
   8433                       handleIpConfigurationLost();
   8434                       transitionTo(mDisconnectingState);
   8435                       break;
   8436                   }
   8437                   messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   8438                   break;
   8439               default:
   8440                   return NOT_HANDLED;
   8441           }
   8442           return HANDLED;
   8443       }
   8444     }
   8445 
   8446     // Note: currently, this state is never used, because WifiWatchdogStateMachine unconditionally
   8447     // sets mPoorNetworkDetectionEnabled to false.
   8448     class VerifyingLinkState extends State {
   8449         @Override
   8450         public void enter() {
   8451             log(getName() + " enter");
   8452             setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);
   8453             mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);
   8454             sendNetworkStateChangeBroadcast(mLastBssid);
   8455             // End roaming
   8456             mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
   8457         }
   8458         @Override
   8459         public boolean processMessage(Message message) {
   8460             logStateAndMessage(message, getClass().getSimpleName());
   8461 
   8462             switch (message.what) {
   8463                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
   8464                     // Stay here
   8465                     log(getName() + " POOR_LINK_DETECTED: no transition");
   8466                     break;
   8467                 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
   8468                     log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED");
   8469                     sendConnectedState();
   8470                     transitionTo(mConnectedState);
   8471                     break;
   8472                 default:
   8473                     if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED");
   8474                     return NOT_HANDLED;
   8475             }
   8476             return HANDLED;
   8477         }
   8478     }
   8479 
   8480     private void sendConnectedState() {
   8481         // If this network was explicitly selected by the user, evaluate whether to call
   8482         // explicitlySelected() so the system can treat it appropriately.
   8483         WifiConfiguration config = getCurrentWifiConfiguration();
   8484         if (mWifiConfigStore.isLastSelectedConfiguration(config)) {
   8485             boolean prompt = mWifiConfigStore.checkConfigOverridePermission(config.lastConnectUid);
   8486             if (DBG) {
   8487                 log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
   8488             }
   8489             if (prompt) {
   8490                 // Selected by the user via Settings or QuickSettings. If this network has Internet
   8491                 // access, switch to it. Otherwise, switch to it only if the user confirms that they
   8492                 // really want to switch, or has already confirmed and selected "Don't ask again".
   8493                 if (DBG) {
   8494                     log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
   8495                 }
   8496                 mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
   8497             }
   8498         }
   8499 
   8500         setNetworkDetailedState(DetailedState.CONNECTED);
   8501         mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
   8502         sendNetworkStateChangeBroadcast(mLastBssid);
   8503     }
   8504 
   8505     class RoamingState extends State {
   8506         boolean mAssociated;
   8507         @Override
   8508         public void enter() {
   8509             if (DBG) {
   8510                 log("RoamingState Enter"
   8511                         + " mScreenOn=" + mScreenOn );
   8512             }
   8513             setScanAlarm(false);
   8514 
   8515             // Make sure we disconnect if roaming fails
   8516             roamWatchdogCount++;
   8517             logd("Start Roam Watchdog " + roamWatchdogCount);
   8518             sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
   8519                     roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
   8520             mAssociated = false;
   8521         }
   8522         @Override
   8523         public boolean processMessage(Message message) {
   8524             logStateAndMessage(message, getClass().getSimpleName());
   8525             WifiConfiguration config;
   8526             switch (message.what) {
   8527                 case CMD_IP_CONFIGURATION_LOST:
   8528                     config = getCurrentWifiConfiguration();
   8529                     if (config != null) {
   8530                         mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
   8531                         mWifiConfigStore.noteRoamingFailure(config,
   8532                                 WifiConfiguration.ROAMING_FAILURE_IP_CONFIG);
   8533                     }
   8534                     return NOT_HANDLED;
   8535                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
   8536                     if (DBG) log("Roaming and Watchdog reports poor link -> ignore");
   8537                     return HANDLED;
   8538                 case CMD_UNWANTED_NETWORK:
   8539                     if (DBG) log("Roaming and CS doesnt want the network -> ignore");
   8540                     return HANDLED;
   8541                 case CMD_SET_OPERATIONAL_MODE:
   8542                     if (message.arg1 != CONNECT_MODE) {
   8543                         deferMessage(message);
   8544                     }
   8545                     break;
   8546                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   8547                     /**
   8548                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
   8549                      * before NETWORK_DISCONNECTION_EVENT
   8550                      * And there is an associated BSSID corresponding to our target BSSID, then
   8551                      * we have missed the network disconnection, transition to mDisconnectedState
   8552                      * and handle the rest of the events there.
   8553                      */
   8554                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   8555                     if (stateChangeResult.state == SupplicantState.DISCONNECTED
   8556                             || stateChangeResult.state == SupplicantState.INACTIVE
   8557                             || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
   8558                         if (DBG) {
   8559                             log("STATE_CHANGE_EVENT in roaming state "
   8560                                     + stateChangeResult.toString() );
   8561                         }
   8562                         if (stateChangeResult.BSSID != null
   8563                                 && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
   8564                             handleNetworkDisconnect();
   8565                             transitionTo(mDisconnectedState);
   8566                         }
   8567                     }
   8568                     if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
   8569                         // We completed the layer2 roaming part
   8570                         mAssociated = true;
   8571                         if (stateChangeResult.BSSID != null) {
   8572                             mTargetRoamBSSID = (String) stateChangeResult.BSSID;
   8573                         }
   8574                     }
   8575                     break;
   8576                 case CMD_ROAM_WATCHDOG_TIMER:
   8577                     if (roamWatchdogCount == message.arg1) {
   8578                         if (DBG) log("roaming watchdog! -> disconnect");
   8579                         mRoamFailCount++;
   8580                         handleNetworkDisconnect();
   8581                         mWifiNative.disconnect();
   8582                         transitionTo(mDisconnectedState);
   8583                     }
   8584                     break;
   8585                case WifiMonitor.NETWORK_CONNECTION_EVENT:
   8586                    if (mAssociated) {
   8587                        if (DBG) log("roaming and Network connection established");
   8588                        mLastNetworkId = message.arg1;
   8589                        mLastBssid = (String) message.obj;
   8590                        mWifiInfo.setBSSID(mLastBssid);
   8591                        mWifiInfo.setNetworkId(mLastNetworkId);
   8592                        mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, mLastBssid, true);
   8593                        sendNetworkStateChangeBroadcast(mLastBssid);
   8594                        transitionTo(mObtainingIpState);
   8595                    } else {
   8596                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   8597                    }
   8598                    break;
   8599                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   8600                    // Throw away but only if it corresponds to the network we're roaming to
   8601                    String bssid = (String)message.obj;
   8602                    if (true) {
   8603                        String target = "";
   8604                        if (mTargetRoamBSSID != null) target = mTargetRoamBSSID;
   8605                        log("NETWORK_DISCONNECTION_EVENT in roaming state"
   8606                                + " BSSID=" + bssid
   8607                                + " target=" + target);
   8608                    }
   8609                    if (bssid != null && bssid.equals(mTargetRoamBSSID)) {
   8610                        handleNetworkDisconnect();
   8611                        transitionTo(mDisconnectedState);
   8612                    }
   8613                    break;
   8614                 case WifiMonitor.SSID_TEMP_DISABLED:
   8615                     // Auth error while roaming
   8616                     logd("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId)
   8617                             + " id=" + Integer.toString(message.arg1)
   8618                             + " isRoaming=" + isRoaming()
   8619                             + " roam=" + Integer.toString(mAutoRoaming));
   8620                     if (message.arg1 == mLastNetworkId) {
   8621                         config = getCurrentWifiConfiguration();
   8622                         if (config != null) {
   8623                             mWifiLogger.captureBugReportData(
   8624                                     WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
   8625                             mWifiConfigStore.noteRoamingFailure(config,
   8626                                     WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE);
   8627                         }
   8628                         handleNetworkDisconnect();
   8629                         transitionTo(mDisconnectingState);
   8630                     }
   8631                     return NOT_HANDLED;
   8632                 case CMD_START_SCAN:
   8633                     deferMessage(message);
   8634                     break;
   8635                 default:
   8636                     return NOT_HANDLED;
   8637             }
   8638             return HANDLED;
   8639         }
   8640 
   8641         @Override
   8642         public void exit() {
   8643             logd("WifiStateMachine: Leaving Roaming state");
   8644         }
   8645     }
   8646 
   8647     class ConnectedState extends State {
   8648         @Override
   8649         public void enter() {
   8650             String address;
   8651             updateDefaultRouteMacAddress(1000);
   8652             if (DBG) {
   8653                 log("Enter ConnectedState "
   8654                        + " mScreenOn=" + mScreenOn
   8655                        + " scanperiod="
   8656                        + Integer.toString(mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get())
   8657                        + " useGscan=" + mHalBasedPnoDriverSupported + "/"
   8658                         + mWifiConfigStore.enableHalBasedPno.get()
   8659                         + " mHalBasedPnoEnableInDevSettings " + mHalBasedPnoEnableInDevSettings);
   8660             }
   8661             if (mScreenOn
   8662                     && getEnableAutoJoinWhenAssociated()) {
   8663                 if (useHalBasedAutoJoinOffload()) {
   8664                     startGScanConnectedModeOffload("connectedEnter");
   8665                 } else {
   8666                     // restart scan alarm
   8667                     startDelayedScan(mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get(),
   8668                             null, null);
   8669                 }
   8670             }
   8671             registerConnected();
   8672             lastConnectAttemptTimestamp = 0;
   8673             targetWificonfiguration = null;
   8674             // Paranoia
   8675             linkDebouncing = false;
   8676 
   8677             // Not roaming anymore
   8678             mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
   8679 
   8680             if (testNetworkDisconnect) {
   8681                 testNetworkDisconnectCounter++;
   8682                 logd("ConnectedState Enter start disconnect test " +
   8683                         testNetworkDisconnectCounter);
   8684                 sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT,
   8685                         testNetworkDisconnectCounter, 0), 15000);
   8686             }
   8687 
   8688             // Reenable all networks, allow for hidden networks to be scanned
   8689             mWifiConfigStore.enableAllNetworks();
   8690 
   8691             mLastDriverRoamAttempt = 0;
   8692 
   8693             //startLazyRoam();
   8694         }
   8695         @Override
   8696         public boolean processMessage(Message message) {
   8697             WifiConfiguration config = null;
   8698             logStateAndMessage(message, getClass().getSimpleName());
   8699 
   8700             switch (message.what) {
   8701                 case CMD_RESTART_AUTOJOIN_OFFLOAD:
   8702                     if ( (int)message.arg2 < mRestartAutoJoinOffloadCounter ) {
   8703                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
   8704                         return HANDLED;
   8705                     }
   8706                     /* If we are still in Disconnected state after having discovered a valid
   8707                      * network this means autojoin didnt managed to associate to the network,
   8708                      * then restart PNO so as we will try associating to it again.
   8709                      */
   8710                     if (useHalBasedAutoJoinOffload()) {
   8711                         if (mGScanStartTimeMilli == 0) {
   8712                             // If offload is not started, then start it...
   8713                             startGScanConnectedModeOffload("connectedRestart");
   8714                         } else {
   8715                             // If offload is already started, then check if we need to increase
   8716                             // the scan period and restart the Gscan
   8717                             long now = System.currentTimeMillis();
   8718                             if (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
   8719                                     && ((now - mGScanStartTimeMilli)
   8720                                     > DISCONNECTED_SHORT_SCANS_DURATION_MILLI)
   8721                                 && (mGScanPeriodMilli
   8722                                     < mWifiConfigStore.wifiDisconnectedLongScanIntervalMilli.get()))
   8723                             {
   8724                                 startConnectedGScan("Connected restart gscan");
   8725                             }
   8726                         }
   8727                     }
   8728                     break;
   8729                 case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
   8730                     updateAssociatedScanPermission();
   8731                     break;
   8732                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
   8733                     if (DBG) log("Watchdog reports poor link");
   8734                     transitionTo(mVerifyingLinkState);
   8735                     break;
   8736                 case CMD_UNWANTED_NETWORK:
   8737                     if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
   8738                         mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo);
   8739                         mWifiNative.disconnect();
   8740                         transitionTo(mDisconnectingState);
   8741                     } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
   8742                             message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
   8743                         config = getCurrentWifiConfiguration();
   8744                         if (config != null) {
   8745                             // Disable autojoin
   8746                             if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
   8747                                 config.validatedInternetAccess = false;
   8748                                 // Clear last-selected status, as being last-selected also avoids
   8749                                 // disabling auto-join.
   8750                                 if (mWifiConfigStore.isLastSelectedConfiguration(config)) {
   8751                                     mWifiConfigStore.setLastSelectedConfiguration(
   8752                                         WifiConfiguration.INVALID_NETWORK_ID);
   8753                                 }
   8754                             }
   8755                             config.numNoInternetAccessReports += 1;
   8756                             config.dirty = true;
   8757                             mWifiConfigStore.writeKnownNetworkHistory(false);
   8758                         }
   8759                     }
   8760                     return HANDLED;
   8761                 case CMD_NETWORK_STATUS:
   8762                     if (message.arg1 == NetworkAgent.VALID_NETWORK) {
   8763                         config = getCurrentWifiConfiguration();
   8764                         if (config != null) {
   8765                             if (!config.validatedInternetAccess
   8766                                     || config.numNoInternetAccessReports != 0) {
   8767                                 config.dirty = true;
   8768                             }
   8769                             // re-enable autojoin
   8770                             config.numNoInternetAccessReports = 0;
   8771                             config.validatedInternetAccess = true;
   8772                             mWifiConfigStore.writeKnownNetworkHistory(false);
   8773                         }
   8774                     }
   8775                     return HANDLED;
   8776                 case CMD_ACCEPT_UNVALIDATED:
   8777                     boolean accept = (message.arg1 != 0);
   8778                     config = getCurrentWifiConfiguration();
   8779                     if (config != null) {
   8780                         config.noInternetAccessExpected = accept;
   8781                     }
   8782                     return HANDLED;
   8783                 case CMD_TEST_NETWORK_DISCONNECT:
   8784                     // Force a disconnect
   8785                     if (message.arg1 == testNetworkDisconnectCounter) {
   8786                         mWifiNative.disconnect();
   8787                     }
   8788                     break;
   8789                 case CMD_ASSOCIATED_BSSID:
   8790                     // ASSOCIATING to a new BSSID while already connected, indicates
   8791                     // that driver is roaming
   8792                     mLastDriverRoamAttempt = System.currentTimeMillis();
   8793                     String toBSSID = (String)message.obj;
   8794                     if (toBSSID != null && !toBSSID.equals(mWifiInfo.getBSSID())) {
   8795                         mWifiConfigStore.driverRoamedFrom(mWifiInfo);
   8796                     }
   8797                     return NOT_HANDLED;
   8798                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   8799                     long lastRoam = 0;
   8800                     if (mLastDriverRoamAttempt != 0) {
   8801                         // Calculate time since last driver roam attempt
   8802                         lastRoam = System.currentTimeMillis() - mLastDriverRoamAttempt;
   8803                         mLastDriverRoamAttempt = 0;
   8804                     }
   8805                     if (unexpectedDisconnectedReason(message.arg2)) {
   8806                         mWifiLogger.captureBugReportData(
   8807                                 WifiLogger.REPORT_REASON_UNEXPECTED_DISCONNECT);
   8808                     }
   8809                     config = getCurrentWifiConfiguration();
   8810                     if (mScreenOn
   8811                             && !linkDebouncing
   8812                             && config != null
   8813                             && config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED
   8814                             && !mWifiConfigStore.isLastSelectedConfiguration(config)
   8815                             && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */
   8816                                 || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
   8817                             && ((ScanResult.is24GHz(mWifiInfo.getFrequency())
   8818                                     && mWifiInfo.getRssi() >
   8819                                     WifiConfiguration.BAD_RSSI_24)
   8820                                     || (ScanResult.is5GHz(mWifiInfo.getFrequency())
   8821                                     && mWifiInfo.getRssi() >
   8822                                     WifiConfiguration.BAD_RSSI_5))) {
   8823                         // Start de-bouncing the L2 disconnection:
   8824                         // this L2 disconnection might be spurious.
   8825                         // Hence we allow 7 seconds for the state machine to try
   8826                         // to reconnect, go thru the
   8827                         // roaming cycle and enter Obtaining IP address
   8828                         // before signalling the disconnect to ConnectivityService and L3
   8829                         startScanForConfiguration(getCurrentWifiConfiguration(), false);
   8830                         linkDebouncing = true;
   8831 
   8832                         sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT,
   8833                                 0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC);
   8834                         if (DBG) {
   8835                             log("NETWORK_DISCONNECTION_EVENT in connected state"
   8836                                     + " BSSID=" + mWifiInfo.getBSSID()
   8837                                     + " RSSI=" + mWifiInfo.getRssi()
   8838                                     + " freq=" + mWifiInfo.getFrequency()
   8839                                     + " reason=" + message.arg2
   8840                                     + " -> debounce");
   8841                         }
   8842                         return HANDLED;
   8843                     } else {
   8844                         if (DBG) {
   8845                             int ajst = -1;
   8846                             if (config != null) ajst = config.autoJoinStatus;
   8847                             log("NETWORK_DISCONNECTION_EVENT in connected state"
   8848                                     + " BSSID=" + mWifiInfo.getBSSID()
   8849                                     + " RSSI=" + mWifiInfo.getRssi()
   8850                                     + " freq=" + mWifiInfo.getFrequency()
   8851                                     + " was debouncing=" + linkDebouncing
   8852                                     + " reason=" + message.arg2
   8853                                     + " ajst=" + ajst);
   8854                         }
   8855                     }
   8856                     break;
   8857                 case CMD_AUTO_ROAM:
   8858                     // Clear the driver roam indication since we are attempting a framework roam
   8859                     mLastDriverRoamAttempt = 0;
   8860 
   8861                     /* Connect command coming from auto-join */
   8862                     ScanResult candidate = (ScanResult)message.obj;
   8863                     String bssid = "any";
   8864                     if (candidate != null && candidate.is5GHz()) {
   8865                         // Only lock BSSID for 5GHz networks
   8866                         bssid = candidate.BSSID;
   8867                     }
   8868                     int netId = mLastNetworkId;
   8869                     config = getCurrentWifiConfiguration();
   8870 
   8871 
   8872                     if (config == null) {
   8873                         loge("AUTO_ROAM and no config, bail out...");
   8874                         break;
   8875                     }
   8876 
   8877                     logd("CMD_AUTO_ROAM sup state "
   8878                             + mSupplicantStateTracker.getSupplicantStateName()
   8879                             + " my state " + getCurrentState().getName()
   8880                             + " nid=" + Integer.toString(netId)
   8881                             + " config " + config.configKey()
   8882                             + " roam=" + Integer.toString(message.arg2)
   8883                             + " to " + bssid
   8884                             + " targetRoamBSSID " + mTargetRoamBSSID);
   8885 
   8886                     /* Save the BSSID so as to lock it @ firmware */
   8887                     if (!autoRoamSetBSSID(config, bssid) && !linkDebouncing) {
   8888                         logd("AUTO_ROAM nothing to do");
   8889                         // Same BSSID, nothing to do
   8890                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   8891                         break;
   8892                     };
   8893 
   8894                     // Make sure the network is enabled, since supplicant will not re-enable it
   8895                     mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false);
   8896 
   8897                     if (deferForUserInput(message, netId, false)) {
   8898                         break;
   8899                     } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved ==
   8900                             WifiConfiguration.USER_BANNED) {
   8901                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   8902                                 WifiManager.NOT_AUTHORIZED);
   8903                         break;
   8904                     }
   8905 
   8906                     boolean ret = false;
   8907                     if (mLastNetworkId != netId) {
   8908                        if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false,
   8909                                WifiConfiguration.UNKNOWN_UID) && mWifiNative.reconnect()) {
   8910                            ret = true;
   8911                        }
   8912                     } else {
   8913                          ret = mWifiNative.reassociate();
   8914                     }
   8915                     if (ret) {
   8916                         lastConnectAttemptTimestamp = System.currentTimeMillis();
   8917                         targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId);
   8918 
   8919                         // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
   8920                         mAutoRoaming = message.arg2;
   8921                         transitionTo(mRoamingState);
   8922 
   8923                     } else {
   8924                         loge("Failed to connect config: " + config + " netId: " + netId);
   8925                         replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
   8926                                 WifiManager.ERROR);
   8927                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
   8928                         break;
   8929                     }
   8930                     break;
   8931                 default:
   8932                     return NOT_HANDLED;
   8933             }
   8934             return HANDLED;
   8935         }
   8936 
   8937         @Override
   8938         public void exit() {
   8939             logd("WifiStateMachine: Leaving Connected state");
   8940             setScanAlarm(false);
   8941             mLastDriverRoamAttempt = 0;
   8942 
   8943             stopLazyRoam();
   8944 
   8945             mWhiteListedSsids = null;
   8946         }
   8947     }
   8948 
   8949     class DisconnectingState extends State {
   8950 
   8951         @Override
   8952         public void enter() {
   8953 
   8954             if (PDBG) {
   8955                 logd(" Enter DisconnectingState State scan interval "
   8956                         + mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get()
   8957                         + " mLegacyPnoEnabled= " + mLegacyPnoEnabled
   8958                         + " screenOn=" + mScreenOn);
   8959             }
   8960 
   8961             // Make sure we disconnect: we enter this state prior to connecting to a new
   8962             // network, waiting for either a DISCONNECT event or a SUPPLICANT_STATE_CHANGE
   8963             // event which in this case will be indicating that supplicant started to associate.
   8964             // In some cases supplicant doesn't ignore the connect requests (it might not
   8965             // find the target SSID in its cache),
   8966             // Therefore we end up stuck that state, hence the need for the watchdog.
   8967             disconnectingWatchdogCount++;
   8968             logd("Start Disconnecting Watchdog " + disconnectingWatchdogCount);
   8969             sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
   8970                     disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
   8971         }
   8972 
   8973         @Override
   8974         public boolean processMessage(Message message) {
   8975             logStateAndMessage(message, getClass().getSimpleName());
   8976             switch (message.what) {
   8977                 case CMD_SET_OPERATIONAL_MODE:
   8978                     if (message.arg1 != CONNECT_MODE) {
   8979                         deferMessage(message);
   8980                     }
   8981                     break;
   8982                 case CMD_START_SCAN:
   8983                     deferMessage(message);
   8984                     return HANDLED;
   8985                 case CMD_DISCONNECTING_WATCHDOG_TIMER:
   8986                     if (disconnectingWatchdogCount == message.arg1) {
   8987                         if (DBG) log("disconnecting watchdog! -> disconnect");
   8988                         handleNetworkDisconnect();
   8989                         transitionTo(mDisconnectedState);
   8990                     }
   8991                     break;
   8992                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   8993                     /**
   8994                      * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
   8995                      * we have missed the network disconnection, transition to mDisconnectedState
   8996                      * and handle the rest of the events there
   8997                      */
   8998                     deferMessage(message);
   8999                     handleNetworkDisconnect();
   9000                     transitionTo(mDisconnectedState);
   9001                     break;
   9002                 default:
   9003                     return NOT_HANDLED;
   9004             }
   9005             return HANDLED;
   9006         }
   9007     }
   9008 
   9009     class DisconnectedState extends State {
   9010         @Override
   9011         public void enter() {
   9012             // We dont scan frequently if this is a temporary disconnect
   9013             // due to p2p
   9014             if (mTemporarilyDisconnectWifi) {
   9015                 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
   9016                 return;
   9017             }
   9018 
   9019             if (PDBG) {
   9020                 logd(" Enter DisconnectedState scan interval "
   9021                         + mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get()
   9022                         + " mLegacyPnoEnabled= " + mLegacyPnoEnabled
   9023                         + " screenOn=" + mScreenOn
   9024                         + " useGscan=" + mHalBasedPnoDriverSupported + "/"
   9025                         + mWifiConfigStore.enableHalBasedPno.get());
   9026             }
   9027 
   9028             /** clear the roaming state, if we were roaming, we failed */
   9029             mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
   9030 
   9031             if (useHalBasedAutoJoinOffload()) {
   9032                 startGScanDisconnectedModeOffload("disconnectedEnter");
   9033             } else {
   9034                 if (mScreenOn) {
   9035                     /**
   9036                      * screen lit and => delayed timer
   9037                      */
   9038                     startDelayedScan(500, null, null);
   9039                 } else {
   9040                     /**
   9041                      * screen dark and PNO supported => scan alarm disabled
   9042                      */
   9043                     if (mBackgroundScanSupported) {
   9044                         /* If a regular scan result is pending, do not initiate background
   9045                          * scan until the scan results are returned. This is needed because
   9046                         * initiating a background scan will cancel the regular scan and
   9047                         * scan results will not be returned until background scanning is
   9048                         * cleared
   9049                         */
   9050                         if (!mIsScanOngoing) {
   9051                             enableBackgroundScan(true);
   9052                         }
   9053                     } else {
   9054                         setScanAlarm(true);
   9055                     }
   9056                 }
   9057             }
   9058 
   9059             /**
   9060              * If we have no networks saved, the supplicant stops doing the periodic scan.
   9061              * The scans are useful to notify the user of the presence of an open network.
   9062              * Note that these are not wake up scans.
   9063              */
   9064             if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
   9065                     && mWifiConfigStore.getConfiguredNetworks().size() == 0) {
   9066                 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
   9067                         ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
   9068             }
   9069 
   9070             mDisconnectedTimeStamp = System.currentTimeMillis();
   9071             mDisconnectedPnoAlarmCount = 0;
   9072         }
   9073         @Override
   9074         public boolean processMessage(Message message) {
   9075             boolean ret = HANDLED;
   9076 
   9077             logStateAndMessage(message, getClass().getSimpleName());
   9078 
   9079             switch (message.what) {
   9080                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
   9081                     if (mP2pConnected.get()) break;
   9082                     if (mNoNetworksPeriodicScan != 0 && message.arg1 == mPeriodicScanToken &&
   9083                             mWifiConfigStore.getConfiguredNetworks().size() == 0) {
   9084                         startScan(UNKNOWN_SCAN_SOURCE, -1, null, null);
   9085                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
   9086                                     ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
   9087                     }
   9088                     break;
   9089                 case WifiManager.FORGET_NETWORK:
   9090                 case CMD_REMOVE_NETWORK:
   9091                 case CMD_REMOVE_APP_CONFIGURATIONS:
   9092                 case CMD_REMOVE_USER_CONFIGURATIONS:
   9093                     // Set up a delayed message here. After the forget/remove is handled
   9094                     // the handled delayed message will determine if there is a need to
   9095                     // scan and continue
   9096                     sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
   9097                                 ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
   9098                     ret = NOT_HANDLED;
   9099                     break;
   9100                 case CMD_SET_OPERATIONAL_MODE:
   9101                     if (message.arg1 != CONNECT_MODE) {
   9102                         mOperationalMode = message.arg1;
   9103 
   9104                         mWifiConfigStore.disableAllNetworks();
   9105                         if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
   9106                             mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
   9107                             setWifiState(WIFI_STATE_DISABLED);
   9108                         }
   9109                         transitionTo(mScanModeState);
   9110                     }
   9111                     mWifiConfigStore.
   9112                             setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID);
   9113                     break;
   9114                     /* Ignore network disconnect */
   9115                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   9116                     break;
   9117                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   9118                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
   9119                     if (DBG) {
   9120                         logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state +
   9121                                 " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state)
   9122                                 + " debouncing=" + linkDebouncing);
   9123                     }
   9124                     setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
   9125                     /* ConnectModeState does the rest of the handling */
   9126                     ret = NOT_HANDLED;
   9127                     break;
   9128                 case CMD_START_SCAN:
   9129                     if (!checkOrDeferScanAllowed(message)) {
   9130                         // The scan request was rescheduled
   9131                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
   9132                         return HANDLED;
   9133                     }
   9134                     if (message.arg1 == SCAN_ALARM_SOURCE) {
   9135                         // Check if the CMD_START_SCAN message is obsolete (and thus if it should
   9136                         // not be processed) and restart the scan
   9137                         int period =  mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get();
   9138                         if (mP2pConnected.get()) {
   9139                            period = (int)Settings.Global.getLong(mContext.getContentResolver(),
   9140                                     Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
   9141                                     period);
   9142                         }
   9143                         if (!checkAndRestartDelayedScan(message.arg2,
   9144                                 true, period, null, null)) {
   9145                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
   9146                             logd("Disconnected CMD_START_SCAN source "
   9147                                     + message.arg1
   9148                                     + " " + message.arg2 + ", " + mDelayedScanCounter
   9149                                     + " -> obsolete");
   9150                             return HANDLED;
   9151                         }
   9152                         /* Disable background scan temporarily during a regular scan */
   9153                         enableBackgroundScan(false);
   9154                         handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
   9155                         ret = HANDLED;
   9156                     } else {
   9157 
   9158                         /*
   9159                          * The SCAN request is not handled in this state and
   9160                          * would eventually might/will get handled in the
   9161                          * parent's state. The PNO, if already enabled had to
   9162                          * get disabled before the SCAN trigger. Hence, stop
   9163                          * the PNO if already enabled in this state, though the
   9164                          * SCAN request is not handled(PNO disable before the
   9165                          * SCAN trigger in any other state is not the right
   9166                          * place to issue).
   9167                          */
   9168 
   9169                         enableBackgroundScan(false);
   9170                         ret = NOT_HANDLED;
   9171                     }
   9172                     break;
   9173                 case CMD_RESTART_AUTOJOIN_OFFLOAD:
   9174                     if ( (int)message.arg2 < mRestartAutoJoinOffloadCounter ) {
   9175                         messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
   9176                         return HANDLED;
   9177                     }
   9178                     /* If we are still in Disconnected state after having discovered a valid
   9179                      * network this means autojoin didnt managed to associate to the network,
   9180                      * then restart PNO so as we will try associating to it again.
   9181                      */
   9182                     if (useHalBasedAutoJoinOffload()) {
   9183                         if (mGScanStartTimeMilli == 0) {
   9184                             // If offload is not started, then start it...
   9185                             startGScanDisconnectedModeOffload("disconnectedRestart");
   9186                         } else {
   9187                             // If offload is already started, then check if we need to increase
   9188                             // the scan period and restart the Gscan
   9189                             long now = System.currentTimeMillis();
   9190                             if (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
   9191                                     && ((now - mGScanStartTimeMilli)
   9192                                     > DISCONNECTED_SHORT_SCANS_DURATION_MILLI)
   9193                                     && (mGScanPeriodMilli
   9194                                     < mWifiConfigStore.wifiDisconnectedLongScanIntervalMilli.get()))
   9195                             {
   9196                                 startDisconnectedGScan("disconnected restart gscan");
   9197                             }
   9198                         }
   9199                     } else {
   9200                         // If we are still disconnected for a short while after having found a
   9201                         // network thru PNO, then something went wrong, and for some reason we
   9202                         // couldn't join this network.
   9203                         // It might be due to a SW bug in supplicant or the wifi stack, or an
   9204                         // interoperability issue, or we try to join a bad bss and failed
   9205                         // In that case we want to restart pno so as to make sure that we will
   9206                         // attempt again to join that network.
   9207                         if (!mScreenOn && !mIsScanOngoing && mBackgroundScanSupported) {
   9208                             enableBackgroundScan(false);
   9209                             enableBackgroundScan(true);
   9210                         }
   9211                         return HANDLED;
   9212                     }
   9213                     break;
   9214                 case WifiMonitor.SCAN_RESULTS_EVENT:
   9215                 case WifiMonitor.SCAN_FAILED_EVENT:
   9216                     /* Re-enable background scan when a pending scan result is received */
   9217                     if (!mScreenOn && mIsScanOngoing
   9218                             && mBackgroundScanSupported
   9219                             && !useHalBasedAutoJoinOffload()) {
   9220                         enableBackgroundScan(true);
   9221                     } else if (!mScreenOn
   9222                             && !mIsScanOngoing
   9223                             && mBackgroundScanSupported
   9224                             && !useHalBasedAutoJoinOffload()) {
   9225                         // We receive scan results from legacy PNO, hence restart the PNO alarm
   9226                         int delay;
   9227                         if (mDisconnectedPnoAlarmCount < 1) {
   9228                             delay = 30 * 1000;
   9229                         } else if (mDisconnectedPnoAlarmCount < 3) {
   9230                             delay = 60 * 1000;
   9231                         } else {
   9232                             delay = 360 * 1000;
   9233                         }
   9234                         mDisconnectedPnoAlarmCount++;
   9235                         if (VDBG) {
   9236                             logd("Starting PNO alarm " + delay);
   9237                         }
   9238                         mAlarmManager.set(AlarmManager.RTC_WAKEUP,
   9239                                 System.currentTimeMillis() + delay,
   9240                                 mPnoIntent);
   9241                     }
   9242                     /* Handled in parent state */
   9243                     ret = NOT_HANDLED;
   9244                     break;
   9245                 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
   9246                     NetworkInfo info = (NetworkInfo) message.obj;
   9247                     mP2pConnected.set(info.isConnected());
   9248                     if (mP2pConnected.get()) {
   9249                         int defaultInterval = mContext.getResources().getInteger(
   9250                                 R.integer.config_wifi_scan_interval_p2p_connected);
   9251                         long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
   9252                                 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
   9253                                 defaultInterval);
   9254                         mWifiNative.setScanInterval((int) scanIntervalMs/1000);
   9255                     } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) {
   9256                         if (DBG) log("Turn on scanning after p2p disconnected");
   9257                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
   9258                                     ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
   9259                     } else {
   9260                         // If P2P is not connected and there are saved networks, then restart
   9261                         // scanning at the normal period. This is necessary because scanning might
   9262                         // have been disabled altogether if WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS
   9263                         // was set to zero.
   9264                         if (useHalBasedAutoJoinOffload()) {
   9265                             startGScanDisconnectedModeOffload("p2pRestart");
   9266                         } else {
   9267                             startDelayedScan(
   9268                                     mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get(),
   9269                                     null, null);
   9270                         }
   9271                     }
   9272                     break;
   9273                 case CMD_RECONNECT:
   9274                 case CMD_REASSOCIATE:
   9275                     if (mTemporarilyDisconnectWifi) {
   9276                         // Drop a third party reconnect/reassociate if STA is
   9277                         // temporarily disconnected for p2p
   9278                         break;
   9279                     } else {
   9280                         // ConnectModeState handles it
   9281                         ret = NOT_HANDLED;
   9282                     }
   9283                     break;
   9284                 case CMD_SCREEN_STATE_CHANGED:
   9285                     handleScreenStateChanged(message.arg1 != 0);
   9286                     break;
   9287                 default:
   9288                     ret = NOT_HANDLED;
   9289             }
   9290             return ret;
   9291         }
   9292 
   9293         @Override
   9294         public void exit() {
   9295             mDisconnectedPnoAlarmCount = 0;
   9296             /* No need for a background scan upon exit from a disconnected state */
   9297             enableBackgroundScan(false);
   9298             setScanAlarm(false);
   9299             mAlarmManager.cancel(mPnoIntent);
   9300         }
   9301     }
   9302 
   9303     class WpsRunningState extends State {
   9304         // Tracks the source to provide a reply
   9305         private Message mSourceMessage;
   9306         @Override
   9307         public void enter() {
   9308             mSourceMessage = Message.obtain(getCurrentMessage());
   9309         }
   9310         @Override
   9311         public boolean processMessage(Message message) {
   9312             logStateAndMessage(message, getClass().getSimpleName());
   9313 
   9314             switch (message.what) {
   9315                 case WifiMonitor.WPS_SUCCESS_EVENT:
   9316                     // Ignore intermediate success, wait for full connection
   9317                     break;
   9318                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
   9319                     replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
   9320                     mSourceMessage.recycle();
   9321                     mSourceMessage = null;
   9322                     deferMessage(message);
   9323                     transitionTo(mDisconnectedState);
   9324                     break;
   9325                 case WifiMonitor.WPS_OVERLAP_EVENT:
   9326                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
   9327                             WifiManager.WPS_OVERLAP_ERROR);
   9328                     mSourceMessage.recycle();
   9329                     mSourceMessage = null;
   9330                     transitionTo(mDisconnectedState);
   9331                     break;
   9332                 case WifiMonitor.WPS_FAIL_EVENT:
   9333                     // Arg1 has the reason for the failure
   9334                     if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
   9335                         replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
   9336                         mSourceMessage.recycle();
   9337                         mSourceMessage = null;
   9338                         transitionTo(mDisconnectedState);
   9339                     } else {
   9340                         if (DBG) log("Ignore unspecified fail event during WPS connection");
   9341                     }
   9342                     break;
   9343                 case WifiMonitor.WPS_TIMEOUT_EVENT:
   9344                     replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
   9345                             WifiManager.WPS_TIMED_OUT);
   9346                     mSourceMessage.recycle();
   9347                     mSourceMessage = null;
   9348                     transitionTo(mDisconnectedState);
   9349                     break;
   9350                 case WifiManager.START_WPS:
   9351                     replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
   9352                     break;
   9353                 case WifiManager.CANCEL_WPS:
   9354                     if (mWifiNative.cancelWps()) {
   9355                         replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
   9356                     } else {
   9357                         replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
   9358                     }
   9359                     transitionTo(mDisconnectedState);
   9360                     break;
   9361                 /**
   9362                  * Defer all commands that can cause connections to a different network
   9363                  * or put the state machine out of connect mode
   9364                  */
   9365                 case CMD_STOP_DRIVER:
   9366                 case CMD_SET_OPERATIONAL_MODE:
   9367                 case WifiManager.CONNECT_NETWORK:
   9368                 case CMD_ENABLE_NETWORK:
   9369                 case CMD_RECONNECT:
   9370                 case CMD_REASSOCIATE:
   9371                 case CMD_ENABLE_ALL_NETWORKS:
   9372                     deferMessage(message);
   9373                     break;
   9374                 case CMD_AUTO_CONNECT:
   9375                 case CMD_AUTO_ROAM:
   9376                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   9377                     return HANDLED;
   9378                 case CMD_START_SCAN:
   9379                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
   9380                     return HANDLED;
   9381                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   9382                     if (DBG) log("Network connection lost");
   9383                     handleNetworkDisconnect();
   9384                     break;
   9385                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   9386                     if (DBG) log("Ignore Assoc reject event during WPS Connection");
   9387                     break;
   9388                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   9389                     // Disregard auth failure events during WPS connection. The
   9390                     // EAP sequence is retried several times, and there might be
   9391                     // failures (especially for wps pin). We will get a WPS_XXX
   9392                     // event at the end of the sequence anyway.
   9393                     if (DBG) log("Ignore auth failure during WPS connection");
   9394                     break;
   9395                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   9396                     // Throw away supplicant state changes when WPS is running.
   9397                     // We will start getting supplicant state changes once we get
   9398                     // a WPS success or failure
   9399                     break;
   9400                 default:
   9401                     return NOT_HANDLED;
   9402             }
   9403             return HANDLED;
   9404         }
   9405 
   9406         @Override
   9407         public void exit() {
   9408             mWifiConfigStore.enableAllNetworks();
   9409             mWifiConfigStore.loadConfiguredNetworks();
   9410         }
   9411     }
   9412 
   9413     class SoftApStartingState extends State {
   9414         @Override
   9415         public void enter() {
   9416             final Message message = getCurrentMessage();
   9417             if (message.what == CMD_START_AP) {
   9418                 final WifiConfiguration config = (WifiConfiguration) message.obj;
   9419 
   9420                 if (config == null) {
   9421                     mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
   9422                 } else {
   9423                     mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
   9424                     startSoftApWithConfig(config);
   9425                 }
   9426             } else {
   9427                 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
   9428             }
   9429         }
   9430         @Override
   9431         public boolean processMessage(Message message) {
   9432             logStateAndMessage(message, getClass().getSimpleName());
   9433 
   9434             switch(message.what) {
   9435                 case CMD_START_SUPPLICANT:
   9436                 case CMD_STOP_SUPPLICANT:
   9437                 case CMD_START_AP:
   9438                 case CMD_STOP_AP:
   9439                 case CMD_START_DRIVER:
   9440                 case CMD_STOP_DRIVER:
   9441                 case CMD_SET_OPERATIONAL_MODE:
   9442                 case CMD_SET_COUNTRY_CODE:
   9443                 case CMD_SET_FREQUENCY_BAND:
   9444                 case CMD_START_PACKET_FILTERING:
   9445                 case CMD_STOP_PACKET_FILTERING:
   9446                 case CMD_TETHER_STATE_CHANGE:
   9447                     deferMessage(message);
   9448                     break;
   9449                 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
   9450                     WifiConfiguration config = (WifiConfiguration) message.obj;
   9451                     if (config != null) {
   9452                         startSoftApWithConfig(config);
   9453                     } else {
   9454                         loge("Softap config is null!");
   9455                         sendMessage(CMD_START_AP_FAILURE, WifiManager.SAP_START_FAILURE_GENERAL);
   9456                     }
   9457                     break;
   9458                 case CMD_START_AP_SUCCESS:
   9459                     setWifiApState(WIFI_AP_STATE_ENABLED, 0);
   9460                     transitionTo(mSoftApStartedState);
   9461                     break;
   9462                 case CMD_START_AP_FAILURE:
   9463                     setWifiApState(WIFI_AP_STATE_FAILED, message.arg1);
   9464                     transitionTo(mInitialState);
   9465                     break;
   9466                 default:
   9467                     return NOT_HANDLED;
   9468             }
   9469             return HANDLED;
   9470         }
   9471     }
   9472 
   9473     class SoftApStartedState extends State {
   9474         @Override
   9475         public boolean processMessage(Message message) {
   9476             logStateAndMessage(message, getClass().getSimpleName());
   9477 
   9478             switch(message.what) {
   9479                 case CMD_STOP_AP:
   9480                     if (DBG) log("Stopping Soft AP");
   9481                     /* We have not tethered at this point, so we just shutdown soft Ap */
   9482                     try {
   9483                         mNwService.stopAccessPoint(mInterfaceName);
   9484                     } catch(Exception e) {
   9485                         loge("Exception in stopAccessPoint()");
   9486                     }
   9487                     setWifiApState(WIFI_AP_STATE_DISABLED, 0);
   9488                     transitionTo(mInitialState);
   9489                     break;
   9490                 case CMD_START_AP:
   9491                     // Ignore a start on a running access point
   9492                     break;
   9493                     // Fail client mode operation when soft AP is enabled
   9494                 case CMD_START_SUPPLICANT:
   9495                     loge("Cannot start supplicant with a running soft AP");
   9496                     setWifiState(WIFI_STATE_UNKNOWN);
   9497                     break;
   9498                 case CMD_TETHER_STATE_CHANGE:
   9499                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   9500                     if (startTethering(stateChange.available)) {
   9501                         transitionTo(mTetheringState);
   9502                     }
   9503                     break;
   9504                 default:
   9505                     return NOT_HANDLED;
   9506             }
   9507             return HANDLED;
   9508         }
   9509     }
   9510 
   9511     class TetheringState extends State {
   9512         @Override
   9513         public void enter() {
   9514             /* Send ourselves a delayed message to shut down if tethering fails to notify */
   9515             sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
   9516                     ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
   9517         }
   9518         @Override
   9519         public boolean processMessage(Message message) {
   9520             logStateAndMessage(message, getClass().getSimpleName());
   9521 
   9522             switch(message.what) {
   9523                 case CMD_TETHER_STATE_CHANGE:
   9524                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   9525                     if (isWifiTethered(stateChange.active)) {
   9526                         transitionTo(mTetheredState);
   9527                     }
   9528                     return HANDLED;
   9529                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   9530                     if (message.arg1 == mTetherToken) {
   9531                         loge("Failed to get tether update, shutdown soft access point");
   9532                         transitionTo(mSoftApStartedState);
   9533                         // Needs to be first thing handled
   9534                         sendMessageAtFrontOfQueue(CMD_STOP_AP);
   9535                     }
   9536                     break;
   9537                 case CMD_START_SUPPLICANT:
   9538                 case CMD_STOP_SUPPLICANT:
   9539                 case CMD_START_AP:
   9540                 case CMD_STOP_AP:
   9541                 case CMD_START_DRIVER:
   9542                 case CMD_STOP_DRIVER:
   9543                 case CMD_SET_OPERATIONAL_MODE:
   9544                 case CMD_SET_COUNTRY_CODE:
   9545                 case CMD_SET_FREQUENCY_BAND:
   9546                 case CMD_START_PACKET_FILTERING:
   9547                 case CMD_STOP_PACKET_FILTERING:
   9548                     deferMessage(message);
   9549                     break;
   9550                 default:
   9551                     return NOT_HANDLED;
   9552             }
   9553             return HANDLED;
   9554         }
   9555     }
   9556 
   9557     class TetheredState extends State {
   9558         @Override
   9559         public boolean processMessage(Message message) {
   9560             logStateAndMessage(message, getClass().getSimpleName());
   9561 
   9562             switch(message.what) {
   9563                 case CMD_TETHER_STATE_CHANGE:
   9564                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   9565                     if (!isWifiTethered(stateChange.active)) {
   9566                         loge("Tethering reports wifi as untethered!, shut down soft Ap");
   9567                         setHostApRunning(null, false);
   9568                         setHostApRunning(null, true);
   9569                     }
   9570                     return HANDLED;
   9571                 case CMD_STOP_AP:
   9572                     if (DBG) log("Untethering before stopping AP");
   9573                     setWifiApState(WIFI_AP_STATE_DISABLING, 0);
   9574                     stopTethering();
   9575                     transitionTo(mUntetheringState);
   9576                     // More work to do after untethering
   9577                     deferMessage(message);
   9578                     break;
   9579                 default:
   9580                     return NOT_HANDLED;
   9581             }
   9582             return HANDLED;
   9583         }
   9584     }
   9585 
   9586     class UntetheringState extends State {
   9587         @Override
   9588         public void enter() {
   9589             /* Send ourselves a delayed message to shut down if tethering fails to notify */
   9590             sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT,
   9591                     ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS);
   9592 
   9593         }
   9594         @Override
   9595         public boolean processMessage(Message message) {
   9596             logStateAndMessage(message, getClass().getSimpleName());
   9597 
   9598             switch(message.what) {
   9599                 case CMD_TETHER_STATE_CHANGE:
   9600                     TetherStateChange stateChange = (TetherStateChange) message.obj;
   9601 
   9602                     /* Wait till wifi is untethered */
   9603                     if (isWifiTethered(stateChange.active)) break;
   9604 
   9605                     transitionTo(mSoftApStartedState);
   9606                     break;
   9607                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
   9608                     if (message.arg1 == mTetherToken) {
   9609                         loge("Failed to get tether update, force stop access point");
   9610                         transitionTo(mSoftApStartedState);
   9611                     }
   9612                     break;
   9613                 case CMD_START_SUPPLICANT:
   9614                 case CMD_STOP_SUPPLICANT:
   9615                 case CMD_START_AP:
   9616                 case CMD_STOP_AP:
   9617                 case CMD_START_DRIVER:
   9618                 case CMD_STOP_DRIVER:
   9619                 case CMD_SET_OPERATIONAL_MODE:
   9620                 case CMD_SET_COUNTRY_CODE:
   9621                 case CMD_SET_FREQUENCY_BAND:
   9622                 case CMD_START_PACKET_FILTERING:
   9623                 case CMD_STOP_PACKET_FILTERING:
   9624                     deferMessage(message);
   9625                     break;
   9626                 default:
   9627                     return NOT_HANDLED;
   9628             }
   9629             return HANDLED;
   9630         }
   9631     }
   9632 
   9633     /**
   9634      * State machine initiated requests can have replyTo set to null indicating
   9635      * there are no recepients, we ignore those reply actions.
   9636      */
   9637     private void replyToMessage(Message msg, int what) {
   9638         if (msg.replyTo == null) return;
   9639         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
   9640         mReplyChannel.replyToMessage(msg, dstMsg);
   9641     }
   9642 
   9643     private void replyToMessage(Message msg, int what, int arg1) {
   9644         if (msg.replyTo == null) return;
   9645         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
   9646         dstMsg.arg1 = arg1;
   9647         mReplyChannel.replyToMessage(msg, dstMsg);
   9648     }
   9649 
   9650     private void replyToMessage(Message msg, int what, Object obj) {
   9651         if (msg.replyTo == null) return;
   9652         Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
   9653         dstMsg.obj = obj;
   9654         mReplyChannel.replyToMessage(msg, dstMsg);
   9655     }
   9656 
   9657     /**
   9658      * arg2 on the source message has a unique id that needs to be retained in replies
   9659      * to match the request
   9660      * <p>see WifiManager for details
   9661      */
   9662     private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
   9663         Message msg = Message.obtain();
   9664         msg.what = what;
   9665         msg.arg2 = srcMsg.arg2;
   9666         return msg;
   9667     }
   9668 
   9669     /**
   9670      * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
   9671      * @param msg Must have a WifiConfiguration obj to succeed
   9672      */
   9673     private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
   9674             WifiConfiguration config) {
   9675         if (config != null && config.preSharedKey != null) {
   9676             Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
   9677             intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
   9678             intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
   9679                     wifiCredentialEventType);
   9680             mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT,
   9681                     android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE);
   9682         }
   9683     }
   9684 
   9685     private static int parseHex(char ch) {
   9686         if ('0' <= ch && ch <= '9') {
   9687             return ch - '0';
   9688         } else if ('a' <= ch && ch <= 'f') {
   9689             return ch - 'a' + 10;
   9690         } else if ('A' <= ch && ch <= 'F') {
   9691             return ch - 'A' + 10;
   9692         } else {
   9693             throw new NumberFormatException("" + ch + " is not a valid hex digit");
   9694         }
   9695     }
   9696 
   9697     private byte[] parseHex(String hex) {
   9698         /* This only works for good input; don't throw bad data at it */
   9699         if (hex == null) {
   9700             return new byte[0];
   9701         }
   9702 
   9703         if (hex.length() % 2 != 0) {
   9704             throw new NumberFormatException(hex + " is not a valid hex string");
   9705         }
   9706 
   9707         byte[] result = new byte[(hex.length())/2 + 1];
   9708         result[0] = (byte) ((hex.length())/2);
   9709         for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
   9710             int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1));
   9711             byte b = (byte) (val & 0xFF);
   9712             result[j] = b;
   9713         }
   9714 
   9715         return result;
   9716     }
   9717 
   9718     private static String makeHex(byte[] bytes) {
   9719         StringBuilder sb = new StringBuilder();
   9720         for (byte b : bytes) {
   9721             sb.append(String.format("%02x", b));
   9722         }
   9723         return sb.toString();
   9724     }
   9725 
   9726     private static String makeHex(byte[] bytes, int from, int len) {
   9727         StringBuilder sb = new StringBuilder();
   9728         for (int i = 0; i < len; i++) {
   9729             sb.append(String.format("%02x", bytes[from+i]));
   9730         }
   9731         return sb.toString();
   9732     }
   9733 
   9734     private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) {
   9735 
   9736         int len = array1.length + array2.length + array3.length;
   9737 
   9738         if (array1.length != 0) {
   9739             len++;                      /* add another byte for size */
   9740         }
   9741 
   9742         if (array2.length != 0) {
   9743             len++;                      /* add another byte for size */
   9744         }
   9745 
   9746         if (array3.length != 0) {
   9747             len++;                      /* add another byte for size */
   9748         }
   9749 
   9750         byte[] result = new byte[len];
   9751 
   9752         int index = 0;
   9753         if (array1.length != 0) {
   9754             result[index] = (byte) (array1.length & 0xFF);
   9755             index++;
   9756             for (byte b : array1) {
   9757                 result[index] = b;
   9758                 index++;
   9759             }
   9760         }
   9761 
   9762         if (array2.length != 0) {
   9763             result[index] = (byte) (array2.length & 0xFF);
   9764             index++;
   9765             for (byte b : array2) {
   9766                 result[index] = b;
   9767                 index++;
   9768             }
   9769         }
   9770 
   9771         if (array3.length != 0) {
   9772             result[index] = (byte) (array3.length & 0xFF);
   9773             index++;
   9774             for (byte b : array3) {
   9775                 result[index] = b;
   9776                 index++;
   9777             }
   9778         }
   9779         return result;
   9780     }
   9781 
   9782     private static byte[] concatHex(byte[] array1, byte[] array2) {
   9783 
   9784         int len = array1.length + array2.length;
   9785 
   9786         byte[] result = new byte[len];
   9787 
   9788         int index = 0;
   9789         if (array1.length != 0) {
   9790             for (byte b : array1) {
   9791                 result[index] = b;
   9792                 index++;
   9793             }
   9794         }
   9795 
   9796         if (array2.length != 0) {
   9797             for (byte b : array2) {
   9798                 result[index] = b;
   9799                 index++;
   9800             }
   9801         }
   9802 
   9803         return result;
   9804     }
   9805 
   9806     void handleGsmAuthRequest(SimAuthRequestData requestData) {
   9807         if (targetWificonfiguration == null
   9808                 || targetWificonfiguration.networkId == requestData.networkId) {
   9809             logd("id matches targetWifiConfiguration");
   9810         } else {
   9811             logd("id does not match targetWifiConfiguration");
   9812             return;
   9813         }
   9814 
   9815         TelephonyManager tm = (TelephonyManager)
   9816                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
   9817 
   9818         if (tm != null) {
   9819             StringBuilder sb = new StringBuilder();
   9820             for (String challenge : requestData.data) {
   9821 
   9822                 if (challenge == null || challenge.isEmpty())
   9823                     continue;
   9824                 logd("RAND = " + challenge);
   9825 
   9826                 byte[] rand = null;
   9827                 try {
   9828                     rand = parseHex(challenge);
   9829                 } catch (NumberFormatException e) {
   9830                     loge("malformed challenge");
   9831                     continue;
   9832                 }
   9833 
   9834                 String base64Challenge = android.util.Base64.encodeToString(
   9835                         rand, android.util.Base64.NO_WRAP);
   9836                 /*
   9837                  * First, try with appType = 2 => USIM according to
   9838                  * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx
   9839                  */
   9840                 int appType = 2;
   9841                 String tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
   9842                 if (tmResponse == null) {
   9843                     /* Then, in case of failure, issue may be due to sim type, retry as a simple sim
   9844                      * appType = 1 => SIM
   9845                      */
   9846                     appType = 1;
   9847                     tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
   9848                 }
   9849                 logv("Raw Response - " + tmResponse);
   9850 
   9851                 if (tmResponse != null && tmResponse.length() > 4) {
   9852                     byte[] result = android.util.Base64.decode(tmResponse,
   9853                             android.util.Base64.DEFAULT);
   9854                     logv("Hex Response -" + makeHex(result));
   9855                     int sres_len = result[0];
   9856                     String sres = makeHex(result, 1, sres_len);
   9857                     int kc_offset = 1+sres_len;
   9858                     int kc_len = result[kc_offset];
   9859                     String kc = makeHex(result, 1+kc_offset, kc_len);
   9860                     sb.append(":" + kc + ":" + sres);
   9861                     logv("kc:" + kc + " sres:" + sres);
   9862                 } else {
   9863                     loge("bad response - " + tmResponse);
   9864                 }
   9865             }
   9866 
   9867             String response = sb.toString();
   9868             logv("Supplicant Response -" + response);
   9869             mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response);
   9870         } else {
   9871             loge("could not get telephony manager");
   9872         }
   9873     }
   9874 
   9875     void handle3GAuthRequest(SimAuthRequestData requestData) {
   9876         StringBuilder sb = new StringBuilder();
   9877         byte[] rand = null;
   9878         byte[] authn = null;
   9879         String res_type = "UMTS-AUTH";
   9880 
   9881         if (targetWificonfiguration == null
   9882                 || targetWificonfiguration.networkId == requestData.networkId) {
   9883             logd("id matches targetWifiConfiguration");
   9884         } else {
   9885             logd("id does not match targetWifiConfiguration");
   9886             return;
   9887         }
   9888         if (requestData.data.length == 2) {
   9889             try {
   9890                 rand = parseHex(requestData.data[0]);
   9891                 authn = parseHex(requestData.data[1]);
   9892             } catch (NumberFormatException e) {
   9893                 loge("malformed challenge");
   9894             }
   9895         } else {
   9896                loge("malformed challenge");
   9897         }
   9898 
   9899         String tmResponse = "";
   9900         if (rand != null && authn != null) {
   9901             String base64Challenge = android.util.Base64.encodeToString(
   9902                     concatHex(rand,authn), android.util.Base64.NO_WRAP);
   9903 
   9904             TelephonyManager tm = (TelephonyManager)
   9905                     mContext.getSystemService(Context.TELEPHONY_SERVICE);
   9906             if (tm != null) {
   9907                 int appType = 2; // 2 => USIM
   9908                 tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
   9909                 logv("Raw Response - " + tmResponse);
   9910             } else {
   9911                 loge("could not get telephony manager");
   9912             }
   9913         }
   9914 
   9915         if (tmResponse != null && tmResponse.length() > 4) {
   9916             byte[] result = android.util.Base64.decode(tmResponse,
   9917                     android.util.Base64.DEFAULT);
   9918             loge("Hex Response - " + makeHex(result));
   9919             byte tag = result[0];
   9920             if (tag == (byte) 0xdb) {
   9921                 logv("successful 3G authentication ");
   9922                 int res_len = result[1];
   9923                 String res = makeHex(result, 2, res_len);
   9924                 int ck_len = result[res_len + 2];
   9925                 String ck = makeHex(result, res_len + 3, ck_len);
   9926                 int ik_len = result[res_len + ck_len + 3];
   9927                 String ik = makeHex(result, res_len + ck_len + 4, ik_len);
   9928                 sb.append(":" + ik + ":" + ck + ":" + res);
   9929                 logv("ik:" + ik + "ck:" + ck + " res:" + res);
   9930             } else if (tag == (byte) 0xdc) {
   9931                 loge("synchronisation failure");
   9932                 int auts_len = result[1];
   9933                 String auts = makeHex(result, 2, auts_len);
   9934                 res_type = "UMTS-AUTS";
   9935                 sb.append(":" + auts);
   9936                 logv("auts:" + auts);
   9937             } else {
   9938                 loge("bad response - unknown tag = " + tag);
   9939                 return;
   9940             }
   9941         } else {
   9942             loge("bad response - " + tmResponse);
   9943             return;
   9944         }
   9945 
   9946         String response = sb.toString();
   9947         logv("Supplicant Response -" + response);
   9948         mWifiNative.simAuthResponse(requestData.networkId, res_type, response);
   9949     }
   9950 
   9951     /**
   9952      * @param reason reason code from supplicant on network disconnected event
   9953      * @return true if this is a suspicious disconnect
   9954      */
   9955     static boolean unexpectedDisconnectedReason(int reason) {
   9956         return reason == 2              // PREV_AUTH_NOT_VALID
   9957                 || reason == 6          // CLASS2_FRAME_FROM_NONAUTH_STA
   9958                 || reason == 7          // FRAME_FROM_NONASSOC_STA
   9959                 || reason == 8          // STA_HAS_LEFT
   9960                 || reason == 9          // STA_REQ_ASSOC_WITHOUT_AUTH
   9961                 || reason == 14         // MICHAEL_MIC_FAILURE
   9962                 || reason == 15         // 4WAY_HANDSHAKE_TIMEOUT
   9963                 || reason == 16         // GROUP_KEY_UPDATE_TIMEOUT
   9964                 || reason == 18         // GROUP_CIPHER_NOT_VALID
   9965                 || reason == 19         // PAIRWISE_CIPHER_NOT_VALID
   9966                 || reason == 23         // IEEE_802_1X_AUTH_FAILED
   9967                 || reason == 34;        // DISASSOC_LOW_ACK
   9968     }
   9969 }
   9970