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