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