WifiStateMachine.java revision bcbc449d47124ec8f73a38ffe228b97bd9b493bf
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        }
2489        List<WifiNative.WifiPnoNetwork> pnoList =
2490                mWifiConfigManager.retrieveDisconnectedWifiPnoNetworkList(enable);
2491        boolean ret = mWifiNative.enableBackgroundScan(enable, pnoList);
2492        if (ret) {
2493            mLegacyPnoEnabled = enable;
2494        } else {
2495            Log.e(TAG, " Fail to set up pno, want " + enable + " now " + mLegacyPnoEnabled);
2496        }
2497    }
2498
2499    /**
2500     * Blacklist a BSSID. This will avoid the AP if there are
2501     * alternate APs to connect
2502     *
2503     * @param bssid BSSID of the network
2504     */
2505    public void addToBlacklist(String bssid) {
2506        sendMessage(CMD_BLACKLIST_NETWORK, bssid);
2507    }
2508
2509    /**
2510     * Clear the blacklist list
2511     */
2512    public void clearBlacklist() {
2513        sendMessage(CMD_CLEAR_BLACKLIST);
2514    }
2515
2516    public void enableRssiPolling(boolean enabled) {
2517        sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
2518    }
2519
2520    public void enableAllNetworks() {
2521        sendMessage(CMD_ENABLE_ALL_NETWORKS);
2522    }
2523
2524    /**
2525     * Start filtering Multicast v4 packets
2526     */
2527    public void startFilteringMulticastV4Packets() {
2528        mFilteringMulticastV4Packets.set(true);
2529        sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0);
2530    }
2531
2532    /**
2533     * Stop filtering Multicast v4 packets
2534     */
2535    public void stopFilteringMulticastV4Packets() {
2536        mFilteringMulticastV4Packets.set(false);
2537        sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0);
2538    }
2539
2540    /**
2541     * Start filtering Multicast v4 packets
2542     */
2543    public void startFilteringMulticastV6Packets() {
2544        sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0);
2545    }
2546
2547    /**
2548     * Stop filtering Multicast v4 packets
2549     */
2550    public void stopFilteringMulticastV6Packets() {
2551        sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0);
2552    }
2553
2554    /**
2555     * Set high performance mode of operation.
2556     * Enabling would set active power mode and disable suspend optimizations;
2557     * disabling would set auto power mode and enable suspend optimizations
2558     *
2559     * @param enable true if enable, false otherwise
2560     */
2561    public void setHighPerfModeEnabled(boolean enable) {
2562        sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);
2563    }
2564
2565    /**
2566     * Set the country code
2567     *
2568     * @param countryCode following ISO 3166 format
2569     * @param persist     {@code true} if the setting should be remembered.
2570     */
2571    public synchronized void setCountryCode(String countryCode, boolean persist) {
2572        // If it's a good country code, apply after the current
2573        // wifi connection is terminated; ignore resetting of code
2574        // for now (it is unclear what the chipset should do when
2575        // country code is reset)
2576
2577        // if mCountryCodeSequence == 0, it is the first time to set country code, always set
2578        // else only when the new country code is different from the current one to set
2579
2580        if (TextUtils.isEmpty(countryCode)) {
2581            if (DBG) log("Ignoring resetting of country code");
2582        } else {
2583            int countryCodeSequence = mCountryCodeSequence.get();
2584            String currentCountryCode = getCurrentCountryCode();
2585            if (countryCodeSequence == 0
2586                    || TextUtils.equals(countryCode, currentCountryCode) == false) {
2587
2588                countryCodeSequence = mCountryCodeSequence.incrementAndGet();
2589                sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0,
2590                        countryCode);
2591            }
2592        }
2593    }
2594
2595    /**
2596     * reset the country code to default
2597     */
2598    public synchronized void resetCountryCode() {
2599        if (mRevertCountryCodeOnCellularLoss && TextUtils.isEmpty(mDefaultCountryCode) == false) {
2600            logd("resetting country code to " + mDefaultCountryCode);
2601            setCountryCode(mDefaultCountryCode, /* persist = */ true);
2602        }
2603    }
2604
2605    /**
2606     * reset cached SIM credential data
2607     */
2608    public synchronized void resetSimAuthNetworks() {
2609        sendMessage(CMD_RESET_SIM_NETWORKS);
2610    }
2611
2612
2613    /**
2614     * Get Network object of current wifi network
2615     * @return Network object of current wifi network
2616     */
2617    public Network getCurrentNetwork() {
2618        if (mNetworkAgent != null) {
2619            return new Network(mNetworkAgent.netId);
2620        } else {
2621            return null;
2622        }
2623    }
2624
2625    /**
2626     * Get the country code
2627     *
2628     * @return countryCode following ISO 3166 format
2629     */
2630    public String getCurrentCountryCode() {
2631        return mFacade.getStringSetting(mContext, Settings.Global.WIFI_COUNTRY_CODE);
2632    }
2633
2634    /**
2635     * Set the operational frequency band
2636     *
2637     * @param band
2638     * @param persist {@code true} if the setting should be remembered.
2639     */
2640    public void setFrequencyBand(int band, boolean persist) {
2641        if (persist) {
2642            Settings.Global.putInt(mContext.getContentResolver(),
2643                    Settings.Global.WIFI_FREQUENCY_BAND,
2644                    band);
2645        }
2646        sendMessage(CMD_SET_FREQUENCY_BAND, band, 0);
2647    }
2648
2649    /**
2650     * Enable TDLS for a specific MAC address
2651     */
2652    public void enableTdls(String remoteMacAddress, boolean enable) {
2653        int enabler = enable ? 1 : 0;
2654        sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress);
2655    }
2656
2657    /**
2658     * Returns the operational frequency band
2659     */
2660    public int getFrequencyBand() {
2661        return mFrequencyBand.get();
2662    }
2663
2664    /**
2665     * Returns the wifi configuration file
2666     */
2667    public String getConfigFile() {
2668        return mWifiConfigManager.getConfigFile();
2669    }
2670
2671    /**
2672     * Send a message indicating bluetooth adapter connection state changed
2673     */
2674    public void sendBluetoothAdapterStateChange(int state) {
2675        sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0);
2676    }
2677
2678    /**
2679     * Send a message indicating a package has been uninstalled.
2680     */
2681    public void removeAppConfigs(String packageName, int uid) {
2682        // Build partial AppInfo manually - package may not exist in database any more
2683        ApplicationInfo ai = new ApplicationInfo();
2684        ai.packageName = packageName;
2685        ai.uid = uid;
2686        sendMessage(CMD_REMOVE_APP_CONFIGURATIONS, ai);
2687    }
2688
2689    /**
2690     * Send a message indicating a user has been removed.
2691     */
2692    public void removeUserConfigs(int userId) {
2693        sendMessage(CMD_REMOVE_USER_CONFIGURATIONS, userId);
2694    }
2695
2696    /**
2697     * Save configuration on supplicant
2698     *
2699     * @return {@code true} if the operation succeeds, {@code false} otherwise
2700     * <p/>
2701     * TODO: deprecate this
2702     */
2703    public boolean syncSaveConfig(AsyncChannel channel) {
2704        Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG);
2705        boolean result = (resultMsg.arg1 != FAILURE);
2706        resultMsg.recycle();
2707        return result;
2708    }
2709
2710    public void updateBatteryWorkSource(WorkSource newSource) {
2711        synchronized (mRunningWifiUids) {
2712            try {
2713                if (newSource != null) {
2714                    mRunningWifiUids.set(newSource);
2715                }
2716                if (mIsRunning) {
2717                    if (mReportedRunning) {
2718                        // If the work source has changed since last time, need
2719                        // to remove old work from battery stats.
2720                        if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
2721                            mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,
2722                                    mRunningWifiUids);
2723                            mLastRunningWifiUids.set(mRunningWifiUids);
2724                        }
2725                    } else {
2726                        // Now being started, report it.
2727                        mBatteryStats.noteWifiRunning(mRunningWifiUids);
2728                        mLastRunningWifiUids.set(mRunningWifiUids);
2729                        mReportedRunning = true;
2730                    }
2731                } else {
2732                    if (mReportedRunning) {
2733                        // Last reported we were running, time to stop.
2734                        mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
2735                        mLastRunningWifiUids.clear();
2736                        mReportedRunning = false;
2737                    }
2738                }
2739                mWakeLock.setWorkSource(newSource);
2740            } catch (RemoteException ignore) {
2741            }
2742        }
2743    }
2744
2745    @Override
2746    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2747        super.dump(fd, pw, args);
2748        mSupplicantStateTracker.dump(fd, pw, args);
2749        pw.println("mLinkProperties " + mLinkProperties);
2750        pw.println("mWifiInfo " + mWifiInfo);
2751        pw.println("mDhcpResults " + mDhcpResults);
2752        pw.println("mNetworkInfo " + mNetworkInfo);
2753        pw.println("mLastSignalLevel " + mLastSignalLevel);
2754        pw.println("mLastBssid " + mLastBssid);
2755        pw.println("mLastNetworkId " + mLastNetworkId);
2756        pw.println("mOperationalMode " + mOperationalMode);
2757        pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
2758        pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
2759        pw.println("Supplicant status " + mWifiNative.status(true));
2760        pw.println("mLegacyPnoEnabled " + mLegacyPnoEnabled);
2761        pw.println("mDriverSetCountryCode " + mDriverSetCountryCode);
2762        pw.println("mConnectedModeGScanOffloadStarted " + mConnectedModeGScanOffloadStarted);
2763        pw.println("mGScanPeriodMilli " + mGScanPeriodMilli);
2764        if (mWhiteListedSsids != null && mWhiteListedSsids.length > 0) {
2765            pw.println("SSID whitelist :" );
2766            for (int i=0; i < mWhiteListedSsids.length; i++) {
2767                pw.println("       " + mWhiteListedSsids[i]);
2768            }
2769        }
2770        if (mNetworkFactory != null) {
2771            mNetworkFactory.dump(fd, pw, args);
2772        } else {
2773            pw.println("mNetworkFactory is not initialized");
2774        }
2775
2776        if (mUntrustedNetworkFactory != null) {
2777            mUntrustedNetworkFactory.dump(fd, pw, args);
2778        } else {
2779            pw.println("mUntrustedNetworkFactory is not initialized");
2780        }
2781        pw.println();
2782        updateWifiMetrics();
2783        mWifiMetrics.dump(fd, pw, args);
2784        pw.println();
2785        mNetworkFactory.dump(fd, pw, args);
2786        mUntrustedNetworkFactory.dump(fd, pw, args);
2787        pw.println();
2788
2789        mWifiConfigManager.dump(fd, pw, args);
2790        pw.println();
2791        mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_USER_ACTION);
2792        mWifiLogger.dump(fd, pw, args);
2793        mWifiQualifiedNetworkSelector.dump(fd, pw, args);
2794    }
2795
2796    public void handleUserSwitch(int userId) {
2797        sendMessage(CMD_USER_SWITCH, userId);
2798    }
2799
2800    /**
2801     * ******************************************************
2802     * Internal private functions
2803     * ******************************************************
2804     */
2805
2806    private void logStateAndMessage(Message message, State state) {
2807        messageHandlingStatus = 0;
2808        if (mLogMessages) {
2809            logd(" " + state.getClass().getSimpleName() + " " + getLogRecString(message));
2810        }
2811    }
2812
2813    /**
2814     * helper, prints the milli time since boot wi and w/o suspended time
2815     */
2816    String printTime() {
2817        StringBuilder sb = new StringBuilder();
2818        sb.append(" rt=").append(SystemClock.uptimeMillis());
2819        sb.append("/").append(SystemClock.elapsedRealtime());
2820        return sb.toString();
2821    }
2822
2823    /**
2824     * Return the additional string to be logged by LogRec, default
2825     *
2826     * @param msg that was processed
2827     * @return information to be logged as a String
2828     */
2829    protected String getLogRecString(Message msg) {
2830        WifiConfiguration config;
2831        Long now;
2832        String report;
2833        String key;
2834        StringBuilder sb = new StringBuilder();
2835        if (mScreenOn) {
2836            sb.append("!");
2837        }
2838        if (messageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) {
2839            sb.append("(").append(messageHandlingStatus).append(")");
2840        }
2841        sb.append(smToString(msg));
2842        if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) {
2843            sb.append(" uid=" + msg.sendingUid);
2844        }
2845        sb.append(" ").append(printTime());
2846        switch (msg.what) {
2847            case CMD_STARTED_GSCAN_DBG:
2848            case CMD_STARTED_PNO_DBG:
2849                sb.append(" ");
2850                sb.append(Integer.toString(msg.arg1));
2851                sb.append(" ");
2852                sb.append(Integer.toString(msg.arg2));
2853                if (msg.obj != null) {
2854                    sb.append(" " + (String)msg.obj);
2855                }
2856                break;
2857            case CMD_RESTART_AUTOJOIN_OFFLOAD:
2858                sb.append(" ");
2859                sb.append(Integer.toString(msg.arg1));
2860                sb.append(" ");
2861                sb.append(Integer.toString(msg.arg2));
2862                sb.append("/").append(Integer.toString(mRestartAutoJoinOffloadCounter));
2863                if (msg.obj != null) {
2864                    sb.append(" " + (String)msg.obj);
2865                }
2866                break;
2867            case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
2868                sb.append(" ");
2869                sb.append(Integer.toString(msg.arg1));
2870                sb.append(" ");
2871                sb.append(Integer.toString(msg.arg2));
2872                sb.append(" halAllowed=").append(useHalBasedAutoJoinOffload());
2873                sb.append(" scanAllowed=").append(allowFullBandScanAndAssociated());
2874                sb.append(" autojoinAllowed=");
2875                sb.append(mWifiConfigManager.enableAutoJoinWhenAssociated.get());
2876                sb.append(" withTraffic=").append(getAllowScansWithTraffic());
2877                sb.append(" tx=").append(mWifiInfo.txSuccessRate);
2878                sb.append("/").append(mWifiConfigManager.maxTxPacketForFullScans);
2879                sb.append(" rx=").append(mWifiInfo.rxSuccessRate);
2880                sb.append("/").append(mWifiConfigManager.maxRxPacketForFullScans);
2881                sb.append(" -> ").append(mConnectedModeGScanOffloadStarted);
2882                break;
2883            case CMD_PNO_NETWORK_FOUND:
2884                sb.append(" ");
2885                sb.append(Integer.toString(msg.arg1));
2886                sb.append(" ");
2887                sb.append(Integer.toString(msg.arg2));
2888                if (msg.obj != null) {
2889                    ScanResult[] results = (ScanResult[])msg.obj;
2890                    for (int i = 0; i < results.length; i++) {
2891                       sb.append(" ").append(results[i].SSID).append(" ");
2892                       sb.append(results[i].frequency);
2893                       sb.append(" ").append(results[i].level);
2894                    }
2895                }
2896                break;
2897            case CMD_START_SCAN:
2898                now = System.currentTimeMillis();
2899                sb.append(" ");
2900                sb.append(Integer.toString(msg.arg1));
2901                sb.append(" ");
2902                sb.append(Integer.toString(msg.arg2));
2903                sb.append(" ic=");
2904                sb.append(Integer.toString(sScanAlarmIntentCount));
2905                if (msg.obj != null) {
2906                    Bundle bundle = (Bundle) msg.obj;
2907                    Long request = bundle.getLong(SCAN_REQUEST_TIME, 0);
2908                    if (request != 0) {
2909                        sb.append(" proc(ms):").append(now - request);
2910                    }
2911                }
2912                if (mIsScanOngoing) sb.append(" onGoing");
2913                if (mIsFullScanOngoing) sb.append(" full");
2914                if (lastStartScanTimeStamp != 0) {
2915                    sb.append(" started:").append(lastStartScanTimeStamp);
2916                    sb.append(",").append(now - lastStartScanTimeStamp);
2917                }
2918                if (lastScanDuration != 0) {
2919                    sb.append(" dur:").append(lastScanDuration);
2920                }
2921                sb.append(" cnt=").append(mDelayedScanCounter);
2922                sb.append(" rssi=").append(mWifiInfo.getRssi());
2923                sb.append(" f=").append(mWifiInfo.getFrequency());
2924                sb.append(" sc=").append(mWifiInfo.score);
2925                sb.append(" link=").append(mWifiInfo.getLinkSpeed());
2926                sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
2927                sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
2928                sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
2929                sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
2930                if (lastScanFreqs != null) {
2931                    sb.append(" list=");
2932                    for(int freq : lastScanFreqs) {
2933                        sb.append(freq).append(",");
2934                    }
2935                } else {
2936                    sb.append(" fiv=").append(fullBandConnectedTimeIntervalMilli);
2937                }
2938                report = reportOnTime();
2939                if (report != null) {
2940                    sb.append(" ").append(report);
2941                }
2942                break;
2943            case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
2944                sb.append(" ");
2945                sb.append(Integer.toString(msg.arg1));
2946                sb.append(" ");
2947                sb.append(Integer.toString(msg.arg2));
2948                StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
2949                if (stateChangeResult != null) {
2950                    sb.append(stateChangeResult.toString());
2951                }
2952                break;
2953            case WifiManager.SAVE_NETWORK:
2954            case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
2955                sb.append(" ");
2956                sb.append(Integer.toString(msg.arg1));
2957                sb.append(" ");
2958                sb.append(Integer.toString(msg.arg2));
2959                if (lastSavedConfigurationAttempt != null) {
2960                    sb.append(" ").append(lastSavedConfigurationAttempt.configKey());
2961                    sb.append(" nid=").append(lastSavedConfigurationAttempt.networkId);
2962                    if (lastSavedConfigurationAttempt.hiddenSSID) {
2963                        sb.append(" hidden");
2964                    }
2965                    if (lastSavedConfigurationAttempt.preSharedKey != null
2966                            && !lastSavedConfigurationAttempt.preSharedKey.equals("*")) {
2967                        sb.append(" hasPSK");
2968                    }
2969                    if (lastSavedConfigurationAttempt.ephemeral) {
2970                        sb.append(" ephemeral");
2971                    }
2972                    if (lastSavedConfigurationAttempt.selfAdded) {
2973                        sb.append(" selfAdded");
2974                    }
2975                    sb.append(" cuid=").append(lastSavedConfigurationAttempt.creatorUid);
2976                    sb.append(" suid=").append(lastSavedConfigurationAttempt.lastUpdateUid);
2977                }
2978                break;
2979            case WifiManager.FORGET_NETWORK:
2980                sb.append(" ");
2981                sb.append(Integer.toString(msg.arg1));
2982                sb.append(" ");
2983                sb.append(Integer.toString(msg.arg2));
2984                if (lastForgetConfigurationAttempt != null) {
2985                    sb.append(" ").append(lastForgetConfigurationAttempt.configKey());
2986                    sb.append(" nid=").append(lastForgetConfigurationAttempt.networkId);
2987                    if (lastForgetConfigurationAttempt.hiddenSSID) {
2988                        sb.append(" hidden");
2989                    }
2990                    if (lastForgetConfigurationAttempt.preSharedKey != null) {
2991                        sb.append(" hasPSK");
2992                    }
2993                    if (lastForgetConfigurationAttempt.ephemeral) {
2994                        sb.append(" ephemeral");
2995                    }
2996                    if (lastForgetConfigurationAttempt.selfAdded) {
2997                        sb.append(" selfAdded");
2998                    }
2999                    sb.append(" cuid=").append(lastForgetConfigurationAttempt.creatorUid);
3000                    sb.append(" suid=").append(lastForgetConfigurationAttempt.lastUpdateUid);
3001                    WifiConfiguration.NetworkSelectionStatus netWorkSelectionStatus =
3002                            lastForgetConfigurationAttempt.getNetworkSelectionStatus();
3003                    sb.append(" ajst=").append(
3004                            netWorkSelectionStatus.getNetworkStatusString());
3005                }
3006                break;
3007            case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
3008                sb.append(" ");
3009                sb.append(Integer.toString(msg.arg1));
3010                sb.append(" ");
3011                sb.append(Integer.toString(msg.arg2));
3012                String bssid = (String) msg.obj;
3013                if (bssid != null && bssid.length() > 0) {
3014                    sb.append(" ");
3015                    sb.append(bssid);
3016                }
3017                sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID));
3018                break;
3019            case WifiMonitor.SCAN_RESULTS_EVENT:
3020                sb.append(" ");
3021                sb.append(Integer.toString(msg.arg1));
3022                sb.append(" ");
3023                sb.append(Integer.toString(msg.arg2));
3024                if (mScanResults != null) {
3025                    sb.append(" found=");
3026                    sb.append(mScanResults.size());
3027                }
3028                sb.append(" known=").append(mNumScanResultsKnown);
3029                sb.append(" got=").append(mNumScanResultsReturned);
3030                if (lastScanDuration != 0) {
3031                    sb.append(" dur:").append(lastScanDuration);
3032                }
3033                if (mOnTime != 0) {
3034                    sb.append(" on:").append(mOnTimeThisScan).append(",").append(mOnTimeScan);
3035                    sb.append(",").append(mOnTime);
3036                }
3037                if (mTxTime != 0) {
3038                    sb.append(" tx:").append(mTxTimeThisScan).append(",").append(mTxTimeScan);
3039                    sb.append(",").append(mTxTime);
3040                }
3041                if (mRxTime != 0) {
3042                    sb.append(" rx:").append(mRxTimeThisScan).append(",").append(mRxTimeScan);
3043                    sb.append(",").append(mRxTime);
3044                }
3045                sb.append(String.format(" bcn=%d", mRunningBeaconCount));
3046                sb.append(String.format(" con=%d", mConnectionRequests));
3047                key = mWifiConfigManager.getLastSelectedConfiguration();
3048                if (key != null) {
3049                    sb.append(" last=").append(key);
3050                }
3051                break;
3052            case WifiMonitor.SCAN_FAILED_EVENT:
3053                break;
3054            case WifiMonitor.NETWORK_CONNECTION_EVENT:
3055                sb.append(" ");
3056                sb.append(Integer.toString(msg.arg1));
3057                sb.append(" ");
3058                sb.append(Integer.toString(msg.arg2));
3059                sb.append(" ").append(mLastBssid);
3060                sb.append(" nid=").append(mLastNetworkId);
3061                config = getCurrentWifiConfiguration();
3062                if (config != null) {
3063                    sb.append(" ").append(config.configKey());
3064                }
3065                key = mWifiConfigManager.getLastSelectedConfiguration();
3066                if (key != null) {
3067                    sb.append(" last=").append(key);
3068                }
3069                break;
3070            case CMD_TARGET_BSSID:
3071            case CMD_ASSOCIATED_BSSID:
3072                sb.append(" ");
3073                sb.append(Integer.toString(msg.arg1));
3074                sb.append(" ");
3075                sb.append(Integer.toString(msg.arg2));
3076                if (msg.obj != null) {
3077                    sb.append(" BSSID=").append((String) msg.obj);
3078                }
3079                if (mTargetRoamBSSID != null) {
3080                    sb.append(" Target=").append(mTargetRoamBSSID);
3081                }
3082                sb.append(" roam=").append(Boolean.toString(mAutoRoaming));
3083                break;
3084            case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3085                if (msg.obj != null) {
3086                    sb.append(" ").append((String) msg.obj);
3087                }
3088                sb.append(" nid=").append(msg.arg1);
3089                sb.append(" reason=").append(msg.arg2);
3090                if (mLastBssid != null) {
3091                    sb.append(" lastbssid=").append(mLastBssid);
3092                }
3093                if (mWifiInfo.getFrequency() != -1) {
3094                    sb.append(" freq=").append(mWifiInfo.getFrequency());
3095                    sb.append(" rssi=").append(mWifiInfo.getRssi());
3096                }
3097                if (linkDebouncing) {
3098                    sb.append(" debounce");
3099                }
3100                break;
3101            case WifiMonitor.SSID_TEMP_DISABLED:
3102            case WifiMonitor.SSID_REENABLED:
3103                sb.append(" nid=").append(msg.arg1);
3104                if (msg.obj != null) {
3105                    sb.append(" ").append((String) msg.obj);
3106                }
3107                config = getCurrentWifiConfiguration();
3108                if (config != null) {
3109                    WifiConfiguration.NetworkSelectionStatus netWorkSelectionStatus =
3110                            config.getNetworkSelectionStatus();
3111                    sb.append(" cur=").append(config.configKey());
3112                    sb.append(" ajst=").append(netWorkSelectionStatus.getNetworkStatusString());
3113                    if (config.selfAdded) {
3114                        sb.append(" selfAdded");
3115                    }
3116                    if (config.status != 0) {
3117                        sb.append(" st=").append(config.status);
3118                        sb.append(" rs=").append(
3119                                netWorkSelectionStatus.getNetworkDisableReasonString());
3120                    }
3121                    if (config.lastConnected != 0) {
3122                        now = System.currentTimeMillis();
3123                        sb.append(" lastconn=").append(now - config.lastConnected).append("(ms)");
3124                    }
3125                    if (mLastBssid != null) {
3126                        sb.append(" lastbssid=").append(mLastBssid);
3127                    }
3128                    if (mWifiInfo.getFrequency() != -1) {
3129                        sb.append(" freq=").append(mWifiInfo.getFrequency());
3130                        sb.append(" rssi=").append(mWifiInfo.getRssi());
3131                        sb.append(" bssid=").append(mWifiInfo.getBSSID());
3132                    }
3133                }
3134                break;
3135            case CMD_RSSI_POLL:
3136            case CMD_UNWANTED_NETWORK:
3137            case WifiManager.RSSI_PKTCNT_FETCH:
3138                sb.append(" ");
3139                sb.append(Integer.toString(msg.arg1));
3140                sb.append(" ");
3141                sb.append(Integer.toString(msg.arg2));
3142                if (mWifiInfo.getSSID() != null)
3143                    if (mWifiInfo.getSSID() != null)
3144                        sb.append(" ").append(mWifiInfo.getSSID());
3145                if (mWifiInfo.getBSSID() != null)
3146                    sb.append(" ").append(mWifiInfo.getBSSID());
3147                sb.append(" rssi=").append(mWifiInfo.getRssi());
3148                sb.append(" f=").append(mWifiInfo.getFrequency());
3149                sb.append(" sc=").append(mWifiInfo.score);
3150                sb.append(" link=").append(mWifiInfo.getLinkSpeed());
3151                sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate));
3152                sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate));
3153                sb.append(String.format(" %.1f ", mWifiInfo.txBadRate));
3154                sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate));
3155                sb.append(String.format(" bcn=%d", mRunningBeaconCount));
3156                report = reportOnTime();
3157                if (report != null) {
3158                    sb.append(" ").append(report);
3159                }
3160                if (wifiScoringReport != null) {
3161                    sb.append(wifiScoringReport);
3162                }
3163                if (mConnectedModeGScanOffloadStarted) {
3164                    sb.append(" offload-started periodMilli " + mGScanPeriodMilli);
3165                } else {
3166                    sb.append(" offload-stopped");
3167                }
3168                break;
3169            case CMD_AUTO_CONNECT:
3170            case WifiManager.CONNECT_NETWORK:
3171                sb.append(" ");
3172                sb.append(Integer.toString(msg.arg1));
3173                sb.append(" ");
3174                sb.append(Integer.toString(msg.arg2));
3175                config = mWifiConfigManager.getWifiConfiguration(msg.arg1);
3176                if (config != null) {
3177                    sb.append(" ").append(config.configKey());
3178                    if (config.visibility != null) {
3179                        sb.append(" ").append(config.visibility.toString());
3180                    }
3181                }
3182                if (mTargetRoamBSSID != null) {
3183                    sb.append(" ").append(mTargetRoamBSSID);
3184                }
3185                sb.append(" roam=").append(Boolean.toString(mAutoRoaming));
3186                config = getCurrentWifiConfiguration();
3187                if (config != null) {
3188                    sb.append(config.configKey());
3189                    if (config.visibility != null) {
3190                        sb.append(" ").append(config.visibility.toString());
3191                    }
3192                }
3193                break;
3194            case CMD_AUTO_ROAM:
3195                sb.append(" ");
3196                sb.append(Integer.toString(msg.arg1));
3197                sb.append(" ");
3198                sb.append(Integer.toString(msg.arg2));
3199                ScanResult result = (ScanResult) msg.obj;
3200                if (result != null) {
3201                    now = System.currentTimeMillis();
3202                    sb.append(" bssid=").append(result.BSSID);
3203                    sb.append(" rssi=").append(result.level);
3204                    sb.append(" freq=").append(result.frequency);
3205                    if (result.seen > 0 && result.seen < now) {
3206                        sb.append(" seen=").append(now - result.seen);
3207                    } else {
3208                        // Somehow the timestamp for this scan result is inconsistent
3209                        sb.append(" !seen=").append(result.seen);
3210                    }
3211                }
3212                if (mTargetRoamBSSID != null) {
3213                    sb.append(" ").append(mTargetRoamBSSID);
3214                }
3215                sb.append(" roam=").append(Boolean.toString(mAutoRoaming));
3216                sb.append(" fail count=").append(Integer.toString(mRoamFailCount));
3217                break;
3218            case CMD_ADD_OR_UPDATE_NETWORK:
3219                sb.append(" ");
3220                sb.append(Integer.toString(msg.arg1));
3221                sb.append(" ");
3222                sb.append(Integer.toString(msg.arg2));
3223                if (msg.obj != null) {
3224                    config = (WifiConfiguration) msg.obj;
3225                    sb.append(" ").append(config.configKey());
3226                    sb.append(" prio=").append(config.priority);
3227                    sb.append(" status=").append(config.status);
3228                    if (config.BSSID != null) {
3229                        sb.append(" ").append(config.BSSID);
3230                    }
3231                    WifiConfiguration curConfig = getCurrentWifiConfiguration();
3232                    if (curConfig != null) {
3233                        if (curConfig.configKey().equals(config.configKey())) {
3234                            sb.append(" is current");
3235                        } else {
3236                            sb.append(" current=").append(curConfig.configKey());
3237                            sb.append(" prio=").append(curConfig.priority);
3238                            sb.append(" status=").append(curConfig.status);
3239                        }
3240                    }
3241                }
3242                break;
3243            case WifiManager.DISABLE_NETWORK:
3244            case CMD_ENABLE_NETWORK:
3245                sb.append(" ");
3246                sb.append(Integer.toString(msg.arg1));
3247                sb.append(" ");
3248                sb.append(Integer.toString(msg.arg2));
3249                key = mWifiConfigManager.getLastSelectedConfiguration();
3250                if (key != null) {
3251                    sb.append(" last=").append(key);
3252                }
3253                config = mWifiConfigManager.getWifiConfiguration(msg.arg1);
3254                if (config != null && (key == null || !config.configKey().equals(key))) {
3255                    sb.append(" target=").append(key);
3256                }
3257                break;
3258            case CMD_GET_CONFIGURED_NETWORKS:
3259                sb.append(" ");
3260                sb.append(Integer.toString(msg.arg1));
3261                sb.append(" ");
3262                sb.append(Integer.toString(msg.arg2));
3263                sb.append(" num=").append(mWifiConfigManager.getConfiguredNetworksSize());
3264                break;
3265            case DhcpClient.CMD_PRE_DHCP_ACTION:
3266                sb.append(" ");
3267                sb.append(Integer.toString(msg.arg1));
3268                sb.append(" ");
3269                sb.append(Integer.toString(msg.arg2));
3270                sb.append(" txpkts=").append(mWifiInfo.txSuccess);
3271                sb.append(",").append(mWifiInfo.txBad);
3272                sb.append(",").append(mWifiInfo.txRetries);
3273                break;
3274            case DhcpClient.CMD_POST_DHCP_ACTION:
3275                sb.append(" ");
3276                sb.append(Integer.toString(msg.arg1));
3277                sb.append(" ");
3278                sb.append(Integer.toString(msg.arg2));
3279                if (msg.arg1 == DhcpClient.DHCP_SUCCESS) {
3280                    sb.append(" OK ");
3281                } else if (msg.arg1 == DhcpClient.DHCP_FAILURE) {
3282                    sb.append(" FAIL ");
3283                }
3284                if (mLinkProperties != null) {
3285                    sb.append(" ");
3286                    sb.append(getLinkPropertiesSummary(mLinkProperties));
3287                }
3288                break;
3289            case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
3290                sb.append(" ");
3291                sb.append(Integer.toString(msg.arg1));
3292                sb.append(" ");
3293                sb.append(Integer.toString(msg.arg2));
3294                if (msg.obj != null) {
3295                    NetworkInfo info = (NetworkInfo) msg.obj;
3296                    NetworkInfo.State state = info.getState();
3297                    NetworkInfo.DetailedState detailedState = info.getDetailedState();
3298                    if (state != null) {
3299                        sb.append(" st=").append(state);
3300                    }
3301                    if (detailedState != null) {
3302                        sb.append("/").append(detailedState);
3303                    }
3304                }
3305                break;
3306            case CMD_IP_CONFIGURATION_LOST:
3307                int count = -1;
3308                WifiConfiguration c = getCurrentWifiConfiguration();
3309                if (c != null) {
3310                    count = c.getNetworkSelectionStatus().getDisableReasonCounter(
3311                            WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
3312                }
3313                sb.append(" ");
3314                sb.append(Integer.toString(msg.arg1));
3315                sb.append(" ");
3316                sb.append(Integer.toString(msg.arg2));
3317                sb.append(" failures: ");
3318                sb.append(Integer.toString(count));
3319                sb.append("/");
3320                sb.append(Integer.toString(mWifiConfigManager.getMaxDhcpRetries()));
3321                if (mWifiInfo.getBSSID() != null) {
3322                    sb.append(" ").append(mWifiInfo.getBSSID());
3323                }
3324                sb.append(String.format(" bcn=%d", mRunningBeaconCount));
3325                break;
3326            case CMD_UPDATE_LINKPROPERTIES:
3327                sb.append(" ");
3328                sb.append(Integer.toString(msg.arg1));
3329                sb.append(" ");
3330                sb.append(Integer.toString(msg.arg2));
3331                if (mLinkProperties != null) {
3332                    sb.append(" ");
3333                    sb.append(getLinkPropertiesSummary(mLinkProperties));
3334                }
3335                break;
3336            case CMD_IP_REACHABILITY_LOST:
3337                if (msg.obj != null) {
3338                    sb.append(" ").append((String) msg.obj);
3339                }
3340                break;
3341            case CMD_SET_COUNTRY_CODE:
3342                sb.append(" ");
3343                sb.append(Integer.toString(msg.arg1));
3344                sb.append(" ");
3345                sb.append(Integer.toString(msg.arg2));
3346                if (msg.obj != null) {
3347                    sb.append(" ").append((String) msg.obj);
3348                }
3349                break;
3350            case CMD_ROAM_WATCHDOG_TIMER:
3351                sb.append(" ");
3352                sb.append(Integer.toString(msg.arg1));
3353                sb.append(" ");
3354                sb.append(Integer.toString(msg.arg2));
3355                sb.append(" cur=").append(roamWatchdogCount);
3356                break;
3357            case CMD_DISCONNECTING_WATCHDOG_TIMER:
3358                sb.append(" ");
3359                sb.append(Integer.toString(msg.arg1));
3360                sb.append(" ");
3361                sb.append(Integer.toString(msg.arg2));
3362                sb.append(" cur=").append(disconnectingWatchdogCount);
3363                break;
3364            case CMD_START_RSSI_MONITORING_OFFLOAD:
3365            case CMD_STOP_RSSI_MONITORING_OFFLOAD:
3366            case CMD_RSSI_THRESHOLD_BREACH:
3367                sb.append(" rssi=");
3368                sb.append(Integer.toString(msg.arg1));
3369                sb.append(" thresholds=");
3370                sb.append(Arrays.toString(mRssiRanges));
3371                break;
3372            case CMD_USER_SWITCH:
3373                sb.append(" userId=");
3374                sb.append(Integer.toString(msg.arg1));
3375                break;
3376            case CMD_IPV4_PROVISIONING_SUCCESS:
3377                sb.append(" ");
3378                if (msg.arg1 == DhcpClient.DHCP_SUCCESS) {
3379                    sb.append("DHCP_OK");
3380                } else if (msg.arg1 == CMD_STATIC_IP_SUCCESS) {
3381                    sb.append("STATIC_OK");
3382                } else {
3383                    sb.append(Integer.toString(msg.arg1));
3384                }
3385                break;
3386            case CMD_IPV4_PROVISIONING_FAILURE:
3387                sb.append(" ");
3388                if (msg.arg1 == DhcpClient.DHCP_FAILURE) {
3389                    sb.append("DHCP_FAIL");
3390                } else if (msg.arg1 == CMD_STATIC_IP_FAILURE) {
3391                    sb.append("STATIC_FAIL");
3392                } else {
3393                    sb.append(Integer.toString(msg.arg1));
3394                }
3395                break;
3396            default:
3397                sb.append(" ");
3398                sb.append(Integer.toString(msg.arg1));
3399                sb.append(" ");
3400                sb.append(Integer.toString(msg.arg2));
3401                break;
3402        }
3403
3404        return sb.toString();
3405    }
3406
3407    private void stopPnoOffload() {
3408
3409        // clear the PNO list
3410        if (!mWifiNative.setPnoList(null, WifiStateMachine.this)) {
3411            Log.e(TAG, "Failed to stop pno");
3412        }
3413
3414    }
3415
3416
3417    private boolean configureSsidWhiteList() {
3418
3419        mWhiteListedSsids = mWifiConfigManager.getWhiteListedSsids(getCurrentWifiConfiguration());
3420        if (mWhiteListedSsids == null || mWhiteListedSsids.length == 0) {
3421            return true;
3422        }
3423
3424       if (!mWifiNative.setSsidWhitelist(mWhiteListedSsids)) {
3425            loge("configureSsidWhiteList couldnt program SSID list, size "
3426                    + mWhiteListedSsids.length);
3427            return false;
3428        }
3429
3430        logd("configureSsidWhiteList success");
3431        return true;
3432    }
3433
3434    // In associated more, lazy roam will be looking for 5GHz roam candidate
3435    //Fixme: This is for network selection offload , whole function need to be re-written according
3436    // to the new design
3437    private boolean configureLazyRoam() {
3438        /*boolean status;
3439        if (!useHalBasedAutoJoinOffload()) return false;
3440
3441        WifiNative.WifiLazyRoamParams params = new WifiNative.WifiLazyRoamParams();
3442        //params.A_band_boost_threshold = mWifiConfigManager.bandPreferenceBoostThreshold5.get();
3443        //params.A_band_penalty_threshold =
3444            mWifiConfigManager.bandPreferencePenaltyThreshold5.get();
3445        params.A_band_boost_factor = mWifiConfigManager.bandPreferenceBoostFactor5;
3446        params.A_band_penalty_factor = mWifiConfigManager.bandPreferencePenaltyFactor5;
3447        params.A_band_max_boost = 65;
3448        params.lazy_roam_hysteresis = 25;
3449        params.alert_roam_rssi_trigger = -75;
3450
3451        if (DBG) {
3452            Log.e(TAG, "configureLazyRoam " + params.toString());
3453        }
3454
3455        if (!mWifiNative.setLazyRoam(true, params)) {
3456
3457            Log.e(TAG, "configureLazyRoam couldnt program params");
3458
3459            return false;
3460        }
3461        if (DBG) {
3462            Log.e(TAG, "configureLazyRoam success");
3463        }*/
3464        return true;
3465    }
3466
3467    // In associated more, lazy roam will be looking for 5GHz roam candidate
3468    private boolean stopLazyRoam() {
3469        boolean status;
3470        if (!useHalBasedAutoJoinOffload()) return false;
3471        if (DBG) {
3472            Log.e(TAG, "stopLazyRoam");
3473        }
3474        return mWifiNative.setLazyRoam(false, null);
3475    }
3476
3477    private boolean startGScanConnectedModeOffload(String reason) {
3478        if (DBG) {
3479            if (reason == null) {
3480                reason = "";
3481            }
3482            logd("startGScanConnectedModeOffload " + reason);
3483        }
3484        stopGScan("startGScanConnectedModeOffload " + reason);
3485        if (!mScreenOn) return false;
3486
3487        if (USE_PAUSE_SCANS) {
3488            mWifiNative.pauseScan();
3489        }
3490        mPnoEnabled = configurePno();
3491        if (mPnoEnabled == false) {
3492            if (USE_PAUSE_SCANS) {
3493                mWifiNative.restartScan();
3494            }
3495            return false;
3496        }
3497        mLazyRoamEnabled = configureLazyRoam();
3498        if (mLazyRoamEnabled == false) {
3499            if (USE_PAUSE_SCANS) {
3500                mWifiNative.restartScan();
3501            }
3502            return false;
3503        }
3504        if (mWifiConfigManager.getLastSelectedConfiguration() == null) {
3505            configureSsidWhiteList();
3506        }
3507        if (!startConnectedGScan(reason)) {
3508            if (USE_PAUSE_SCANS) {
3509                mWifiNative.restartScan();
3510            }
3511            return false;
3512        }
3513        if (USE_PAUSE_SCANS) {
3514            mWifiNative.restartScan();
3515        }
3516        mConnectedModeGScanOffloadStarted = true;
3517        if (DBG) {
3518            logd("startGScanConnectedModeOffload success");
3519        }
3520        return true;
3521    }
3522
3523    private boolean startGScanDisconnectedModeOffload(String reason) {
3524        if (DBG) {
3525            logd("startGScanDisconnectedModeOffload " + reason);
3526        }
3527        stopGScan("startGScanDisconnectedModeOffload " + reason);
3528        if (USE_PAUSE_SCANS) {
3529            mWifiNative.pauseScan();
3530        }
3531        mPnoEnabled = configurePno();
3532        if (mPnoEnabled == false) {
3533            if (USE_PAUSE_SCANS) {
3534                mWifiNative.restartScan();
3535            }
3536            return false;
3537        }
3538        if (!startDisconnectedGScan(reason)) {
3539            if (USE_PAUSE_SCANS) {
3540                mWifiNative.restartScan();
3541            }
3542            return false;
3543        }
3544        if (USE_PAUSE_SCANS) {
3545            mWifiNative.restartScan();
3546        }
3547        return true;
3548    }
3549
3550    private boolean configurePno() {
3551        if (!useHalBasedAutoJoinOffload()) return false;
3552
3553        if (mWifiScanner == null) {
3554            log("configurePno: mWifiScanner is null ");
3555            return true;
3556        }
3557
3558        List<WifiNative.WifiPnoNetwork> llist = null;
3559        //TODO: add getPnoList in WifiQualifiedNetworkSelector
3560        //mWifiAutoJoinController.getPnoList(getCurrentWifiConfiguration());
3561        if (llist == null || llist.size() == 0) {
3562            stopPnoOffload();
3563            log("configurePno: empty PNO list ");
3564            return true;
3565        }
3566        if (DBG) {
3567            log("configurePno: got llist size " + llist.size());
3568        }
3569
3570        // first program the network we want to look for thru the pno API
3571        WifiNative.WifiPnoNetwork list[]
3572                = (WifiNative.WifiPnoNetwork[]) llist.toArray(new WifiNative.WifiPnoNetwork[0]);
3573
3574        if (!mWifiNative.setPnoList(list, WifiStateMachine.this)) {
3575            Log.e(TAG, "Failed to set pno, length = " + list.length);
3576            return false;
3577        }
3578
3579        if (true) {
3580            StringBuilder sb = new StringBuilder();
3581            for (WifiNative.WifiPnoNetwork network : list) {
3582                sb.append("[").append(network.SSID).append(" auth=").append(network.auth);
3583                sb.append(" flags=");
3584                sb.append(network.flags).append(" rssi").append(network.rssi_threshold);
3585                sb.append("] ");
3586
3587            }
3588            sendMessage(CMD_STARTED_PNO_DBG, 1, (int)mGScanPeriodMilli, sb.toString());
3589        }
3590        return true;
3591    }
3592
3593    final static int DISCONNECTED_SHORT_SCANS_DURATION_MILLI = 2 * 60 * 1000;
3594    final static int CONNECTED_SHORT_SCANS_DURATION_MILLI = 2 * 60 * 1000;
3595
3596    private boolean startConnectedGScan(String reason) {
3597        // send a scan background request so as to kick firmware
3598        // 5GHz roaming and autojoin
3599        // We do this only if screen is on
3600        WifiScanner.ScanSettings settings;
3601
3602        if (mPnoEnabled || mLazyRoamEnabled) {
3603            settings = new WifiScanner.ScanSettings();
3604            settings.band = WifiScanner.WIFI_BAND_BOTH;
3605            long now = System.currentTimeMillis();
3606
3607            if (!mScreenOn  || (mGScanStartTimeMilli!= 0 && now > mGScanStartTimeMilli
3608                    && ((now - mGScanStartTimeMilli) > CONNECTED_SHORT_SCANS_DURATION_MILLI))) {
3609                settings.periodInMs = mWifiConfigManager.wifiAssociatedLongScanIntervalMilli.get();
3610            } else {
3611                mGScanStartTimeMilli = now;
3612                settings.periodInMs = mWifiConfigManager.wifiAssociatedShortScanIntervalMilli.get();
3613                // if we start offload with short interval, then reconfigure it after a given
3614                // duration of time so as to reduce the scan frequency
3615                int delay = 30 * 1000 + CONNECTED_SHORT_SCANS_DURATION_MILLI;
3616                sendMessageDelayed(CMD_RESTART_AUTOJOIN_OFFLOAD, delay,
3617                        mRestartAutoJoinOffloadCounter, " startConnectedGScan " + reason,
3618                        (long)delay);
3619                mRestartAutoJoinOffloadCounter++;
3620            }
3621            mGScanPeriodMilli = settings.periodInMs;
3622            settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL;
3623            if (DBG) {
3624                log("startConnectedScan: settings band="+ settings.band
3625                        + " period=" + settings.periodInMs);
3626            }
3627
3628            mWifiScanner.startBackgroundScan(settings, mWifiScanListener);
3629            if (true) {
3630                sendMessage(CMD_STARTED_GSCAN_DBG, 1, (int)mGScanPeriodMilli, reason);
3631            }
3632        }
3633        return true;
3634    }
3635
3636    private boolean startDisconnectedGScan(String reason) {
3637        // send a scan background request so as to kick firmware
3638        // PNO
3639        // This is done in both screen On and screen Off modes
3640        WifiScanner.ScanSettings settings;
3641
3642        if (mWifiScanner == null) {
3643            log("startDisconnectedGScan: no wifi scanner");
3644            return false;
3645        }
3646
3647        if (mPnoEnabled || mLazyRoamEnabled) {
3648            settings = new WifiScanner.ScanSettings();
3649            settings.band = WifiScanner.WIFI_BAND_BOTH;
3650            long now = System.currentTimeMillis();
3651
3652
3653            if (!mScreenOn  || (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
3654                    && ((now - mGScanStartTimeMilli) > DISCONNECTED_SHORT_SCANS_DURATION_MILLI))) {
3655                settings.periodInMs =
3656                        mWifiConfigManager.wifiDisconnectedLongScanIntervalMilli.get();
3657            } else {
3658                settings.periodInMs =
3659                        mWifiConfigManager.wifiDisconnectedShortScanIntervalMilli.get();
3660                mGScanStartTimeMilli = now;
3661                // if we start offload with short interval, then reconfigure it after a given
3662                // duration of time so as to reduce the scan frequency
3663                int delay = 30 * 1000 + DISCONNECTED_SHORT_SCANS_DURATION_MILLI;
3664                sendMessageDelayed(CMD_RESTART_AUTOJOIN_OFFLOAD, delay,
3665                        mRestartAutoJoinOffloadCounter, " startDisconnectedGScan " + reason,
3666                        (long)delay);
3667                mRestartAutoJoinOffloadCounter++;
3668            }
3669            mGScanPeriodMilli = settings.periodInMs;
3670            settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL;
3671            if (DBG) {
3672                log("startDisconnectedScan: settings band="+ settings.band
3673                        + " period=" + settings.periodInMs);
3674            }
3675            mWifiScanner.startBackgroundScan(settings, mWifiScanListener);
3676            if (true) {
3677                sendMessage(CMD_STARTED_GSCAN_DBG, 1, (int)mGScanPeriodMilli, reason);
3678            }
3679        }
3680        return true;
3681    }
3682
3683    private boolean stopGScan(String reason) {
3684        mGScanStartTimeMilli = 0;
3685        mGScanPeriodMilli = 0;
3686        if (mWifiScanner != null) {
3687            mWifiScanner.stopBackgroundScan(mWifiScanListener);
3688        }
3689        mConnectedModeGScanOffloadStarted = false;
3690        if (true) {
3691            sendMessage(CMD_STARTED_GSCAN_DBG, 0, 0, reason);
3692        }
3693        return true;
3694    }
3695
3696    private void handleScreenStateChanged(boolean screenOn) {
3697        mScreenOn = screenOn;
3698        if (PDBG) {
3699            logd(" handleScreenStateChanged Enter: screenOn=" + screenOn
3700                    + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt
3701                    + " state " + getCurrentState().getName()
3702                    + " suppState:" + mSupplicantStateTracker.getSupplicantStateName());
3703        }
3704        enableRssiPolling(screenOn);
3705        if (mUserWantsSuspendOpt.get()) {
3706            if (screenOn) {
3707                sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0);
3708            } else {
3709                // Allow 2s for suspend optimizations to be set
3710                mSuspendWakeLock.acquire(2000);
3711                sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0);
3712            }
3713        }
3714        mScreenBroadcastReceived.set(true);
3715
3716        getWifiLinkLayerStats(false);
3717        mOnTimeScreenStateChange = mOnTime;
3718        lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate;
3719
3720        cancelDelayedScan();
3721
3722        if (screenOn) {
3723            enableBackgroundScan(false);
3724            setScanAlarm(false);
3725            clearBlacklist();
3726
3727            fullBandConnectedTimeIntervalMilli
3728                    = mWifiConfigManager.wifiAssociatedShortScanIntervalMilli.get();
3729            // In either Disconnectedstate or ConnectedState,
3730            // start the scan alarm so as to enable autojoin
3731            if (getCurrentState() == mConnectedState
3732                    && allowFullBandScanAndAssociated()) {
3733                if (useHalBasedAutoJoinOffload()) {
3734                    startGScanConnectedModeOffload("screenOnConnected");
3735                } else {
3736                    // Scan after 500ms
3737                    startDelayedScan(500, null, null);
3738                }
3739            } else if (getCurrentState() == mDisconnectedState) {
3740                if (useHalBasedAutoJoinOffload()) {
3741                    startGScanDisconnectedModeOffload("screenOnDisconnected");
3742                } else {
3743                    // Scan after 500ms
3744                    startDelayedScan(500, null, null);
3745                }
3746            }
3747        } else {
3748            if (getCurrentState() == mDisconnectedState) {
3749                // Screen Off and Disconnected and chipset doesn't support scan offload
3750                //              => start scan alarm
3751                // Screen Off and Disconnected and chipset does support scan offload
3752                //              => will use scan offload (i.e. background scan)
3753                if (useHalBasedAutoJoinOffload()) {
3754                    startGScanDisconnectedModeOffload("screenOffDisconnected");
3755                } else {
3756                    if (!mBackgroundScanSupported) {
3757                        setScanAlarm(true);
3758                    } else {
3759                        if (!mIsScanOngoing) {
3760                            enableBackgroundScan(true);
3761                        }
3762                    }
3763                }
3764            } else {
3765                enableBackgroundScan(false);
3766                if (useHalBasedAutoJoinOffload()) {
3767                    // don't try stop Gscan if it is not enabled
3768                    stopGScan("ScreenOffStop(enableBackground=" + mLegacyPnoEnabled + ") ");
3769                }
3770            }
3771        }
3772        if (DBG) logd("backgroundScan enabled=" + mLegacyPnoEnabled);
3773
3774        if (DBG) log("handleScreenStateChanged Exit: " + screenOn);
3775    }
3776
3777    private void checkAndSetConnectivityInstance() {
3778        if (mCm == null) {
3779            mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
3780        }
3781    }
3782
3783    /**
3784     * Set the country code from the system setting value, if any.
3785     */
3786    private void initializeCountryCode() {
3787        String countryCode = getCurrentCountryCode();
3788        if (countryCode != null && !countryCode.isEmpty()) {
3789            setCountryCode(countryCode, false);
3790        } else {
3791            //use driver default
3792        }
3793    }
3794
3795    /**
3796     * Set the frequency band from the system setting value, if any.
3797     */
3798    private void setFrequencyBand() {
3799        int band = mFacade.getIntegerSetting(mContext,
3800                Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
3801
3802        if (mWifiNative.setBand(band)) {
3803            mFrequencyBand.set(band);
3804            if (PDBG) {
3805                logd("done set frequency band " + band);
3806                mWifiQualifiedNetworkSelector.setUserPreferredBand(band);
3807            }
3808        } else {
3809            loge("Failed to set frequency band " + band);
3810        }
3811    }
3812
3813    private void setSuspendOptimizationsNative(int reason, boolean enabled) {
3814        if (DBG) {
3815            log("setSuspendOptimizationsNative: " + reason + " " + enabled
3816                    + " -want " + mUserWantsSuspendOpt.get()
3817                    + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
3818                    + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
3819                    + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
3820                    + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
3821        }
3822        //mWifiNative.setSuspendOptimizations(enabled);
3823
3824        if (enabled) {
3825            mSuspendOptNeedsDisabled &= ~reason;
3826            /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
3827            if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) {
3828                if (DBG) {
3829                    log("setSuspendOptimizationsNative do it " + reason + " " + enabled
3830                            + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
3831                            + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
3832                            + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
3833                            + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
3834                }
3835                mWifiNative.setSuspendOptimizations(true);
3836            }
3837        } else {
3838            mSuspendOptNeedsDisabled |= reason;
3839            mWifiNative.setSuspendOptimizations(false);
3840        }
3841    }
3842
3843    private void setSuspendOptimizations(int reason, boolean enabled) {
3844        if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled);
3845        if (enabled) {
3846            mSuspendOptNeedsDisabled &= ~reason;
3847        } else {
3848            mSuspendOptNeedsDisabled |= reason;
3849        }
3850        if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
3851    }
3852
3853    private void setWifiState(int wifiState) {
3854        final int previousWifiState = mWifiState.get();
3855
3856        try {
3857            if (wifiState == WIFI_STATE_ENABLED) {
3858                mBatteryStats.noteWifiOn();
3859            } else if (wifiState == WIFI_STATE_DISABLED) {
3860                mBatteryStats.noteWifiOff();
3861            }
3862        } catch (RemoteException e) {
3863            loge("Failed to note battery stats in wifi");
3864        }
3865
3866        mWifiState.set(wifiState);
3867
3868        if (DBG) log("setWifiState: " + syncGetWifiStateByName());
3869
3870        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
3871        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3872        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
3873        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
3874        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3875    }
3876
3877    private void setWifiApState(int wifiApState, int reason) {
3878        final int previousWifiApState = mWifiApState.get();
3879
3880        try {
3881            if (wifiApState == WIFI_AP_STATE_ENABLED) {
3882                mBatteryStats.noteWifiOn();
3883            } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
3884                mBatteryStats.noteWifiOff();
3885            }
3886        } catch (RemoteException e) {
3887            loge("Failed to note battery stats in wifi");
3888        }
3889
3890        // Update state
3891        mWifiApState.set(wifiApState);
3892
3893        if (DBG) log("setWifiApState: " + syncGetWifiApStateByName());
3894
3895        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
3896        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3897        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
3898        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
3899        if (wifiApState == WifiManager.WIFI_AP_STATE_FAILED) {
3900            //only set reason number when softAP start failed
3901            intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
3902        }
3903
3904        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
3905    }
3906
3907    private void setScanResults() {
3908        mNumScanResultsKnown = 0;
3909        mNumScanResultsReturned = 0;
3910
3911        ArrayList<ScanDetail> scanResults = mWifiNative.getScanResults();
3912
3913        if (scanResults.isEmpty()) {
3914            mScanResults = new ArrayList<>();
3915            return;
3916        }
3917
3918        mWifiConfigManager.trimANQPCache(false);
3919
3920        boolean connected = mLastBssid != null;
3921        long activeBssid = 0L;
3922        if (connected) {
3923            try {
3924                activeBssid = Utils.parseMac(mLastBssid);
3925            } catch (IllegalArgumentException iae) {
3926                connected = false;
3927            }
3928        }
3929
3930        synchronized (mScanResultCache) {
3931            ScanDetail activeScanDetail = null;
3932            mScanResults = scanResults;
3933            mNumScanResultsReturned = mScanResults.size();
3934            for (ScanDetail resultDetail : mScanResults) {
3935                mScanResultCache.put(resultDetail.getNetworkDetail(), resultDetail);
3936                if (connected && resultDetail.getNetworkDetail().getBSSID() == activeBssid) {
3937                    if (activeScanDetail == null
3938                            || activeScanDetail.getNetworkDetail().getBSSID() != activeBssid
3939                            || activeScanDetail.getNetworkDetail().getANQPElements() == null) {
3940                        activeScanDetail = resultDetail;
3941                    }
3942                }
3943                // Cache DTIM values parsed from the beacon frame Traffic Indication Map (TIM)
3944                // Information Element (IE), into the associated WifiConfigurations. Most of the
3945                // time there is no TIM IE in the scan result (Probe Response instead of Beacon
3946                // Frame), these scanResult DTIM's are negative and ignored.
3947                NetworkDetail networkDetail = resultDetail.getNetworkDetail();
3948                if (networkDetail != null && networkDetail.getDtimInterval() > 0) {
3949                    List<WifiConfiguration> associatedWifiConfigurations =
3950                            mWifiConfigManager.updateSavedNetworkWithNewScanDetail(resultDetail);
3951                    if (associatedWifiConfigurations != null) {
3952                        for (WifiConfiguration associatedConf : associatedWifiConfigurations) {
3953                            if (associatedConf != null) {
3954                                associatedConf.dtimInterval = networkDetail.getDtimInterval();
3955                            }
3956                        }
3957                    }
3958                }
3959            }
3960            mActiveScanDetail = activeScanDetail;
3961        }
3962        if (mNumScanResultsReturned > 0) {
3963            mWifiMetrics.incrementNonEmptyScanResultCount();
3964        } else {
3965            mWifiMetrics.incrementEmptyScanResultCount();
3966        }
3967
3968        if (linkDebouncing) {
3969            // If debouncing, we dont re-select a SSID or BSSID hence
3970            // there is no need to call the network selection code
3971            // in WifiAutoJoinController, instead,
3972            // just try to reconnect to the same SSID by triggering a roam
3973            // The third parameter 1 means roam not from network selection but debouncing
3974            sendMessage(CMD_AUTO_ROAM, mLastNetworkId, 1, null);
3975        } else {
3976            WifiConfiguration candidate =
3977                    mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
3978                    mAllowUntrustedConnections, mScanResults, linkDebouncing, isConnected(),
3979                    isDisconnected(), isSupplicantTransientState());
3980            tryToConnectToNetwork(candidate);
3981        }
3982    }
3983
3984    /**
3985     * Set whether connections to untrusted connections are allowed.
3986     */
3987    void setAllowUntrustedConnections(boolean allow) {
3988        boolean changed = (mAllowUntrustedConnections != allow);
3989        mAllowUntrustedConnections = allow;
3990        if (changed) {
3991            // Trigger a scan so as to reattempt autojoin
3992            startScanForUntrustedSettingChange();
3993        }
3994    }
3995
3996    public ScanDetail getActiveScanDetail() {
3997        synchronized (mScanResultCache) {
3998            return mActiveScanDetail;
3999        }
4000    }
4001
4002    /*
4003     * Fetch RSSI, linkspeed, and frequency on current connection
4004     */
4005    private void fetchRssiLinkSpeedAndFrequencyNative() {
4006        Integer newRssi = null;
4007        Integer newLinkSpeed = null;
4008        Integer newFrequency = null;
4009
4010        String signalPoll = mWifiNative.signalPoll();
4011
4012        if (signalPoll != null) {
4013            String[] lines = signalPoll.split("\n");
4014            for (String line : lines) {
4015                String[] prop = line.split("=");
4016                if (prop.length < 2) continue;
4017                try {
4018                    if (prop[0].equals("RSSI")) {
4019                        newRssi = Integer.parseInt(prop[1]);
4020                    } else if (prop[0].equals("LINKSPEED")) {
4021                        newLinkSpeed = Integer.parseInt(prop[1]);
4022                    } else if (prop[0].equals("FREQUENCY")) {
4023                        newFrequency = Integer.parseInt(prop[1]);
4024                    }
4025                } catch (NumberFormatException e) {
4026                    //Ignore, defaults on rssi and linkspeed are assigned
4027                }
4028            }
4029        }
4030
4031        if (PDBG) {
4032            logd("fetchRssiLinkSpeedAndFrequencyNative rssi=" + newRssi +
4033                 " linkspeed=" + newLinkSpeed + " freq=" + newFrequency);
4034        }
4035
4036        if (newRssi != null && newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) {
4037            // screen out invalid values
4038            /* some implementations avoid negative values by adding 256
4039             * so we need to adjust for that here.
4040             */
4041            if (newRssi > 0) newRssi -= 256;
4042            mWifiInfo.setRssi(newRssi);
4043            /*
4044             * Rather then sending the raw RSSI out every time it
4045             * changes, we precalculate the signal level that would
4046             * be displayed in the status bar, and only send the
4047             * broadcast if that much more coarse-grained number
4048             * changes. This cuts down greatly on the number of
4049             * broadcasts, at the cost of not informing others
4050             * interested in RSSI of all the changes in signal
4051             * level.
4052             */
4053            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS);
4054            if (newSignalLevel != mLastSignalLevel) {
4055                updateCapabilities(getCurrentWifiConfiguration());
4056                sendRssiChangeBroadcast(newRssi);
4057            }
4058            mLastSignalLevel = newSignalLevel;
4059        } else {
4060            mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
4061            updateCapabilities(getCurrentWifiConfiguration());
4062        }
4063
4064        if (newLinkSpeed != null) {
4065            mWifiInfo.setLinkSpeed(newLinkSpeed);
4066        }
4067        if (newFrequency != null && newFrequency > 0) {
4068            if (ScanResult.is5GHz(newFrequency)) {
4069                mWifiConnectionStatistics.num5GhzConnected++;
4070            }
4071            if (ScanResult.is24GHz(newFrequency)) {
4072                mWifiConnectionStatistics.num24GhzConnected++;
4073            }
4074            mWifiInfo.setFrequency(newFrequency);
4075        }
4076        mWifiConfigManager.updateConfiguration(mWifiInfo);
4077    }
4078
4079    /**
4080     * Determine if we need to switch network:
4081     * - the delta determine the urgency to switch and/or or the expected evilness of the disruption
4082     * - match the uregncy of the switch versus the packet usage at the interface
4083     */
4084    boolean shouldSwitchNetwork(int networkDelta) {
4085        int delta;
4086        if (networkDelta <= 0) {
4087            return false;
4088        }
4089        delta = networkDelta;
4090        if (mWifiInfo != null) {
4091            if (!getEnableAutoJoinWhenAssociated()
4092                    && mWifiInfo.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
4093                // If AutoJoin while associated is not enabled,
4094                // we should never switch network when already associated
4095                delta = -1000;
4096            } else {
4097                // TODO: Look at per AC packet count, do not switch if VO/VI traffic is present
4098                // TODO: at the interface. We should also discriminate between ucast and mcast,
4099                // TODO: since the rxSuccessRate include all the bonjour and Ipv6
4100                // TODO: broadcasts
4101                if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) {
4102                    delta -= 999;
4103                } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) {
4104                    delta -= 6;
4105                }
4106                logd("shouldSwitchNetwork "
4107                        + " txSuccessRate=" + String.format("%.2f", mWifiInfo.txSuccessRate)
4108                        + " rxSuccessRate=" + String.format("%.2f", mWifiInfo.rxSuccessRate)
4109                        + " delta " + networkDelta + " -> " + delta);
4110            }
4111        } else {
4112            logd("shouldSwitchNetwork "
4113                    + " delta " + networkDelta + " -> " + delta);
4114        }
4115        if (delta > 0) {
4116            return true;
4117        }
4118        return false;
4119    }
4120
4121    // Polling has completed, hence we wont have a score anymore
4122    private void cleanWifiScore() {
4123        mWifiInfo.txBadRate = 0;
4124        mWifiInfo.txSuccessRate = 0;
4125        mWifiInfo.txRetriesRate = 0;
4126        mWifiInfo.rxSuccessRate = 0;
4127    }
4128
4129    int mBadLinkspeedcount = 0;
4130
4131    // For debug, provide information about the last scoring operation
4132    String wifiScoringReport = null;
4133
4134    private void calculateWifiScore(WifiLinkLayerStats stats) {
4135        StringBuilder sb = new StringBuilder();
4136
4137        int score = 56; // Starting score, temporarily hardcoded in between 50 and 60
4138        boolean isBadLinkspeed = (mWifiInfo.is24GHz()
4139                && mWifiInfo.getLinkSpeed() < mWifiConfigManager.badLinkSpeed24)
4140                || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed()
4141                < mWifiConfigManager.badLinkSpeed5);
4142        boolean isGoodLinkspeed = (mWifiInfo.is24GHz()
4143                && mWifiInfo.getLinkSpeed() >= mWifiConfigManager.goodLinkSpeed24)
4144                || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed()
4145                >= mWifiConfigManager.goodLinkSpeed5);
4146
4147        if (isBadLinkspeed) {
4148            if (mBadLinkspeedcount < 6)
4149                mBadLinkspeedcount++;
4150        } else {
4151            if (mBadLinkspeedcount > 0)
4152                mBadLinkspeedcount--;
4153        }
4154
4155        if (isBadLinkspeed) sb.append(" bl(").append(mBadLinkspeedcount).append(")");
4156        if (isGoodLinkspeed) sb.append(" gl");
4157
4158        /**
4159         * We want to make sure that we use the 24GHz RSSI thresholds if
4160         * there are 2.4GHz scan results
4161         * otherwise we end up lowering the score based on 5GHz values
4162         * which may cause a switch to LTE before roaming has a chance to try 2.4GHz
4163         * We also might unblacklist the configuation based on 2.4GHz
4164         * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good
4165         */
4166        boolean use24Thresholds = false;
4167        boolean homeNetworkBoost = false;
4168        WifiConfiguration currentConfiguration = getCurrentWifiConfiguration();
4169        ScanDetailCache scanDetailCache =
4170                mWifiConfigManager.getScanDetailCache(currentConfiguration);
4171        if (currentConfiguration != null && scanDetailCache != null) {
4172            currentConfiguration.setVisibility(scanDetailCache.getVisibility(12000));
4173            if (currentConfiguration.visibility != null) {
4174                if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI
4175                        && currentConfiguration.visibility.rssi24
4176                        >= (currentConfiguration.visibility.rssi5 - 2)) {
4177                    use24Thresholds = true;
4178                }
4179            }
4180            if (scanDetailCache.size() <= 6
4181                && currentConfiguration.allowedKeyManagement.cardinality() == 1
4182                && currentConfiguration.allowedKeyManagement.
4183                    get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) {
4184                // A PSK network with less than 6 known BSSIDs
4185                // This is most likely a home network and thus we want to stick to wifi more
4186                homeNetworkBoost = true;
4187            }
4188        }
4189        if (homeNetworkBoost) sb.append(" hn");
4190        if (use24Thresholds) sb.append(" u24");
4191
4192        int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover
4193                + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0);
4194        sb.append(String.format(" rssi=%d ag=%d", rssi, mAggressiveHandover));
4195
4196        boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz();
4197
4198        boolean isBadRSSI = (is24GHz && rssi < mWifiConfigManager.thresholdMinimumRssi24.get())
4199                || (!is24GHz && rssi < mWifiConfigManager.thresholdMinimumRssi5.get());
4200        boolean isLowRSSI = (is24GHz && rssi < mWifiConfigManager.thresholdQualifiedRssi24.get())
4201                || (!is24GHz &&
4202                    mWifiInfo.getRssi() < mWifiConfigManager.thresholdMinimumRssi5.get());
4203        boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigManager.thresholdSaturatedRssi24.get())
4204                || (!is24GHz && mWifiInfo.getRssi()
4205                >= mWifiConfigManager.thresholdSaturatedRssi5.get());
4206
4207        if (isBadRSSI) sb.append(" br");
4208        if (isLowRSSI) sb.append(" lr");
4209        if (isHighRSSI) sb.append(" hr");
4210
4211        int penalizedDueToUserTriggeredDisconnect = 0;        // For debug information
4212        if (currentConfiguration != null &&
4213                (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 5)) {
4214            if (isBadRSSI) {
4215                currentConfiguration.numTicksAtBadRSSI++;
4216                if (currentConfiguration.numTicksAtBadRSSI > 1000) {
4217                    // We remained associated for a compound amount of time while passing
4218                    // traffic, hence loose the corresponding user triggered disabled stats
4219                    if (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0) {
4220                        currentConfiguration.numUserTriggeredWifiDisableBadRSSI--;
4221                    }
4222                    if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) {
4223                        currentConfiguration.numUserTriggeredWifiDisableLowRSSI--;
4224                    }
4225                    if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
4226                        currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
4227                    }
4228                    currentConfiguration.numTicksAtBadRSSI = 0;
4229                }
4230                if (mWifiConfigManager.enableWifiCellularHandoverUserTriggeredAdjustment &&
4231                        (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0
4232                                || currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0
4233                                || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) {
4234                    score = score - 5;
4235                    penalizedDueToUserTriggeredDisconnect = 1;
4236                    sb.append(" p1");
4237                }
4238            } else if (isLowRSSI) {
4239                currentConfiguration.numTicksAtLowRSSI++;
4240                if (currentConfiguration.numTicksAtLowRSSI > 1000) {
4241                    // We remained associated for a compound amount of time while passing
4242                    // traffic, hence loose the corresponding user triggered disabled stats
4243                    if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) {
4244                        currentConfiguration.numUserTriggeredWifiDisableLowRSSI--;
4245                    }
4246                    if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
4247                        currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
4248                    }
4249                    currentConfiguration.numTicksAtLowRSSI = 0;
4250                }
4251                if (mWifiConfigManager.enableWifiCellularHandoverUserTriggeredAdjustment &&
4252                        (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0
4253                                || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) {
4254                    score = score - 5;
4255                    penalizedDueToUserTriggeredDisconnect = 2;
4256                    sb.append(" p2");
4257                }
4258            } else if (!isHighRSSI) {
4259                currentConfiguration.numTicksAtNotHighRSSI++;
4260                if (currentConfiguration.numTicksAtNotHighRSSI > 1000) {
4261                    // We remained associated for a compound amount of time while passing
4262                    // traffic, hence loose the corresponding user triggered disabled stats
4263                    if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
4264                        currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--;
4265                    }
4266                    currentConfiguration.numTicksAtNotHighRSSI = 0;
4267                }
4268                if (mWifiConfigManager.enableWifiCellularHandoverUserTriggeredAdjustment &&
4269                        currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) {
4270                    score = score - 5;
4271                    penalizedDueToUserTriggeredDisconnect = 3;
4272                    sb.append(" p3");
4273                }
4274            }
4275            sb.append(String.format(" ticks %d,%d,%d", currentConfiguration.numTicksAtBadRSSI,
4276                    currentConfiguration.numTicksAtLowRSSI,
4277                    currentConfiguration.numTicksAtNotHighRSSI));
4278        }
4279
4280        if (PDBG) {
4281            String rssiStatus = "";
4282            if (isBadRSSI) rssiStatus += " badRSSI ";
4283            else if (isHighRSSI) rssiStatus += " highRSSI ";
4284            else if (isLowRSSI) rssiStatus += " lowRSSI ";
4285            if (isBadLinkspeed) rssiStatus += " lowSpeed ";
4286            logd("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency())
4287                    + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed())
4288                    + " score=" + Integer.toString(mWifiInfo.score)
4289                    + rssiStatus
4290                    + " -> txbadrate=" + String.format("%.2f", mWifiInfo.txBadRate)
4291                    + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate)
4292                    + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate)
4293                    + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate)
4294                    + " userTriggerdPenalty" + penalizedDueToUserTriggeredDisconnect);
4295        }
4296
4297        if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3)
4298                && (isBadRSSI || isLowRSSI)) {
4299            // Link is stuck
4300            if (mWifiInfo.linkStuckCount < 5)
4301                mWifiInfo.linkStuckCount += 1;
4302            sb.append(String.format(" ls+=%d", mWifiInfo.linkStuckCount));
4303            if (PDBG) logd(" bad link -> stuck count ="
4304                    + Integer.toString(mWifiInfo.linkStuckCount));
4305        } else if (mWifiInfo.txBadRate < 0.3) {
4306            if (mWifiInfo.linkStuckCount > 0)
4307                mWifiInfo.linkStuckCount -= 1;
4308            sb.append(String.format(" ls-=%d", mWifiInfo.linkStuckCount));
4309            if (PDBG) logd(" good link -> stuck count ="
4310                    + Integer.toString(mWifiInfo.linkStuckCount));
4311        }
4312
4313        sb.append(String.format(" [%d", score));
4314
4315        if (mWifiInfo.linkStuckCount > 1) {
4316            // Once link gets stuck for more than 3 seconds, start reducing the score
4317            score = score - 2 * (mWifiInfo.linkStuckCount - 1);
4318        }
4319        sb.append(String.format(",%d", score));
4320
4321        if (isBadLinkspeed) {
4322            score -= 4;
4323            if (PDBG) {
4324                logd(" isBadLinkspeed   ---> count=" + mBadLinkspeedcount
4325                        + " score=" + Integer.toString(score));
4326            }
4327        } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) {
4328            score += 4; // So as bad rssi alone dont kill us
4329        }
4330        sb.append(String.format(",%d", score));
4331
4332        if (isBadRSSI) {
4333            if (mWifiInfo.badRssiCount < 7)
4334                mWifiInfo.badRssiCount += 1;
4335        } else if (isLowRSSI) {
4336            mWifiInfo.lowRssiCount = 1; // Dont increment the lowRssi count above 1
4337            if (mWifiInfo.badRssiCount > 0) {
4338                // Decrement bad Rssi count
4339                mWifiInfo.badRssiCount -= 1;
4340            }
4341        } else {
4342            mWifiInfo.badRssiCount = 0;
4343            mWifiInfo.lowRssiCount = 0;
4344        }
4345
4346        score -= mWifiInfo.badRssiCount * 2 + mWifiInfo.lowRssiCount;
4347        sb.append(String.format(",%d", score));
4348
4349        if (PDBG) logd(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount)
4350                + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount)
4351                + " --> score " + Integer.toString(score));
4352
4353
4354        if (isHighRSSI) {
4355            score += 5;
4356            if (PDBG) logd(" isHighRSSI       ---> score=" + Integer.toString(score));
4357        }
4358        sb.append(String.format(",%d]", score));
4359
4360        sb.append(String.format(" brc=%d lrc=%d", mWifiInfo.badRssiCount, mWifiInfo.lowRssiCount));
4361
4362        //sanitize boundaries
4363        if (score > NetworkAgent.WIFI_BASE_SCORE)
4364            score = NetworkAgent.WIFI_BASE_SCORE;
4365        if (score < 0)
4366            score = 0;
4367
4368        //report score
4369        if (score != mWifiInfo.score) {
4370            if (DBG) {
4371                logd("calculateWifiScore() report new score " + Integer.toString(score));
4372            }
4373            mWifiInfo.score = score;
4374            if (mNetworkAgent != null) {
4375                mNetworkAgent.sendNetworkScore(score);
4376            }
4377        }
4378        wifiScoringReport = sb.toString();
4379    }
4380
4381    public double getTxPacketRate() {
4382        if (mWifiInfo != null) {
4383            return mWifiInfo.txSuccessRate;
4384        }
4385        return -1;
4386    }
4387
4388    public double getRxPacketRate() {
4389        if (mWifiInfo != null) {
4390            return mWifiInfo.rxSuccessRate;
4391        }
4392        return -1;
4393    }
4394
4395    /**
4396     * Fetch TX packet counters on current connection
4397     */
4398    private void fetchPktcntNative(RssiPacketCountInfo info) {
4399        String pktcntPoll = mWifiNative.pktcntPoll();
4400
4401        if (pktcntPoll != null) {
4402            String[] lines = pktcntPoll.split("\n");
4403            for (String line : lines) {
4404                String[] prop = line.split("=");
4405                if (prop.length < 2) continue;
4406                try {
4407                    if (prop[0].equals("TXGOOD")) {
4408                        info.txgood = Integer.parseInt(prop[1]);
4409                    } else if (prop[0].equals("TXBAD")) {
4410                        info.txbad = Integer.parseInt(prop[1]);
4411                    }
4412                } catch (NumberFormatException e) {
4413                    // Ignore
4414                }
4415            }
4416        }
4417    }
4418
4419    private void notifyLinkProperties() {
4420        // TODO: Add setters for TCP buffer sizes and HTTP proxy to IpManager.
4421        // Once that is done delete this.
4422        updateLinkProperties(new LinkProperties(mLinkProperties));
4423    }
4424
4425    private void updateLinkProperties(LinkProperties newLp) {
4426        // HTTP proxy and TCP buffer sizes are locally configured.
4427        newLp.setHttpProxy(mWifiConfigManager.getProxyProperties(mLastNetworkId));
4428        if (!TextUtils.isEmpty(mTcpBufferSizes)) {
4429            newLp.setTcpBufferSizes(mTcpBufferSizes);
4430        }
4431
4432        if (!newLp.equals(mLinkProperties)) {
4433            if (DBG) {
4434                log("Link configuration changed for netId: " + mLastNetworkId
4435                        + " old: " + mLinkProperties + " new: " + newLp);
4436            }
4437            // We own this instance of LinkProperties because IpManager passes us a copy.
4438            mLinkProperties = newLp;
4439            if (mNetworkAgent != null) {
4440                mNetworkAgent.sendLinkProperties(mLinkProperties);
4441            }
4442
4443            if (getNetworkDetailedState() == DetailedState.CONNECTED) {
4444                // If anything has changed and we're already connected, send out a notification.
4445                // TODO: Update all callers to use NetworkCallbacks and delete this.
4446                sendLinkConfigurationChangedBroadcast();
4447            }
4448        }
4449
4450        if (DBG) {
4451            StringBuilder sb = new StringBuilder();
4452            sb.append("updateLinkProperties nid: " + mLastNetworkId);
4453            sb.append(" state: " + getNetworkDetailedState());
4454
4455            if (mLinkProperties != null) {
4456                sb.append(" ");
4457                sb.append(getLinkPropertiesSummary(mLinkProperties));
4458            }
4459            logd(sb.toString());
4460        }
4461    }
4462
4463    /**
4464     * Clears all our link properties.
4465     */
4466    private void clearLinkProperties() {
4467        // Clear the link properties obtained from DHCP. The only caller of this
4468        // function has already called IpManager#stop(), which clears its state.
4469        synchronized (mDhcpResultsLock) {
4470            if (mDhcpResults != null) {
4471                mDhcpResults.clear();
4472            }
4473        }
4474
4475        // Now clear the merged link properties.
4476        mLinkProperties.clear();
4477        if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties);
4478    }
4479
4480    /**
4481     * try to update default route MAC address.
4482     */
4483    private String updateDefaultRouteMacAddress(int timeout) {
4484        String address = null;
4485        for (RouteInfo route : mLinkProperties.getRoutes()) {
4486            if (route.isDefaultRoute() && route.hasGateway()) {
4487                InetAddress gateway = route.getGateway();
4488                if (gateway instanceof Inet4Address) {
4489                    if (PDBG) {
4490                        logd("updateDefaultRouteMacAddress found Ipv4 default :"
4491                                + gateway.getHostAddress());
4492                    }
4493                    address = macAddressFromRoute(gateway.getHostAddress());
4494                    /* The gateway's MAC address is known */
4495                    if ((address == null) && (timeout > 0)) {
4496                        boolean reachable = false;
4497                        try {
4498                            reachable = gateway.isReachable(timeout);
4499                        } catch (Exception e) {
4500                            loge("updateDefaultRouteMacAddress exception reaching :"
4501                                    + gateway.getHostAddress());
4502
4503                        } finally {
4504                            if (reachable == true) {
4505
4506                                address = macAddressFromRoute(gateway.getHostAddress());
4507                                if (PDBG) {
4508                                    logd("updateDefaultRouteMacAddress reachable (tried again) :"
4509                                            + gateway.getHostAddress() + " found " + address);
4510                                }
4511                            }
4512                        }
4513                    }
4514                    if (address != null) {
4515                        mWifiConfigManager.setDefaultGwMacAddress(mLastNetworkId, address);
4516                    }
4517                }
4518            }
4519        }
4520        return address;
4521    }
4522
4523    void sendScanResultsAvailableBroadcast(boolean scanSucceeded) {
4524        Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
4525        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4526        intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, scanSucceeded);
4527        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
4528    }
4529
4530    private void sendRssiChangeBroadcast(final int newRssi) {
4531        try {
4532            mBatteryStats.noteWifiRssiChanged(newRssi);
4533        } catch (RemoteException e) {
4534            // Won't happen.
4535        }
4536        Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
4537        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4538        intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
4539        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4540    }
4541
4542    private void sendNetworkStateChangeBroadcast(String bssid) {
4543        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
4544        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4545        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
4546        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
4547        if (bssid != null)
4548            intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
4549        if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK ||
4550                mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
4551            // We no longer report MAC address to third-parties and our code does
4552            // not rely on this broadcast, so just send the default MAC address.
4553            WifiInfo sentWifiInfo = new WifiInfo(mWifiInfo);
4554            sentWifiInfo.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
4555            intent.putExtra(WifiManager.EXTRA_WIFI_INFO, sentWifiInfo);
4556        }
4557        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4558    }
4559
4560    private WifiInfo getWiFiInfoForUid(int uid) {
4561        if (Binder.getCallingUid() == Process.myUid()) {
4562            return mWifiInfo;
4563        }
4564
4565        WifiInfo result = new WifiInfo(mWifiInfo);
4566        result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
4567
4568        IBinder binder = mFacade.getService("package");
4569        IPackageManager packageManager = IPackageManager.Stub.asInterface(binder);
4570
4571        try {
4572            if (packageManager.checkUidPermission(Manifest.permission.LOCAL_MAC_ADDRESS,
4573                    uid) == PackageManager.PERMISSION_GRANTED) {
4574                result.setMacAddress(mWifiInfo.getMacAddress());
4575            }
4576        } catch (RemoteException e) {
4577            Log.e(TAG, "Error checking receiver permission", e);
4578        }
4579
4580        return result;
4581    }
4582
4583    private void sendLinkConfigurationChangedBroadcast() {
4584        Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
4585        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4586        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
4587        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
4588    }
4589
4590    private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
4591        Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
4592        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
4593        intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
4594        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
4595    }
4596
4597    /**
4598     * Record the detailed state of a network.
4599     *
4600     * @param state the new {@code DetailedState}
4601     */
4602    private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {
4603        boolean hidden = false;
4604
4605        if (linkDebouncing || isRoaming()) {
4606            // There is generally a confusion in the system about colluding
4607            // WiFi Layer 2 state (as reported by supplicant) and the Network state
4608            // which leads to multiple confusion.
4609            //
4610            // If link is de-bouncing or roaming, we already have an IP address
4611            // as well we were connected and are doing L2 cycles of
4612            // reconnecting or renewing IP address to check that we still have it
4613            // This L2 link flapping should ne be reflected into the Network state
4614            // which is the state of the WiFi Network visible to Layer 3 and applications
4615            // Note that once debouncing and roaming are completed, we will
4616            // set the Network state to where it should be, or leave it as unchanged
4617            //
4618            hidden = true;
4619        }
4620        if (DBG) {
4621            log("setDetailed state, old ="
4622                    + mNetworkInfo.getDetailedState() + " and new state=" + state
4623                    + " hidden=" + hidden);
4624        }
4625        if (mNetworkInfo.getExtraInfo() != null && mWifiInfo.getSSID() != null
4626                && !mWifiInfo.getSSID().equals(WifiSsid.NONE)) {
4627            // Always indicate that SSID has changed
4628            if (!mNetworkInfo.getExtraInfo().equals(mWifiInfo.getSSID())) {
4629                if (DBG) {
4630                    log("setDetailed state send new extra info" + mWifiInfo.getSSID());
4631                }
4632                mNetworkInfo.setExtraInfo(mWifiInfo.getSSID());
4633                sendNetworkStateChangeBroadcast(null);
4634            }
4635        }
4636        if (hidden == true) {
4637            return false;
4638        }
4639
4640        if (state != mNetworkInfo.getDetailedState()) {
4641            mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());
4642            if (mNetworkAgent != null) {
4643                mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4644            }
4645            sendNetworkStateChangeBroadcast(null);
4646            return true;
4647        }
4648        return false;
4649    }
4650
4651    private DetailedState getNetworkDetailedState() {
4652        return mNetworkInfo.getDetailedState();
4653    }
4654
4655    private SupplicantState handleSupplicantStateChange(Message message) {
4656        StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
4657        SupplicantState state = stateChangeResult.state;
4658        // Supplicant state change
4659        // [31-13] Reserved for future use
4660        // [8 - 0] Supplicant state (as defined in SupplicantState.java)
4661        // 50023 supplicant_state_changed (custom|1|5)
4662        mWifiInfo.setSupplicantState(state);
4663        // Network id is only valid when we start connecting
4664        if (SupplicantState.isConnecting(state)) {
4665            mWifiInfo.setNetworkId(stateChangeResult.networkId);
4666        } else {
4667            mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
4668        }
4669
4670        mWifiInfo.setBSSID(stateChangeResult.BSSID);
4671
4672        if (mWhiteListedSsids != null
4673                && mWhiteListedSsids.length > 0
4674                && stateChangeResult.wifiSsid != null) {
4675            String SSID = stateChangeResult.wifiSsid.toString();
4676            String currentSSID = mWifiInfo.getSSID();
4677            if (SSID != null && currentSSID != null && !SSID.equals(WifiSsid.NONE)) {
4678                // Remove quote before comparing
4679                if (SSID.length() >= 2 && SSID.charAt(0) == '"'
4680                        && SSID.charAt(SSID.length() - 1) == '"') {
4681                    SSID = SSID.substring(1, SSID.length() - 1);
4682                }
4683                if (currentSSID.length() >= 2 && currentSSID.charAt(0) == '"'
4684                        && currentSSID.charAt(currentSSID.length() - 1) == '"') {
4685                    currentSSID = currentSSID.substring(1, currentSSID.length() - 1);
4686                }
4687                if ((!SSID.equals(currentSSID)) && (getCurrentState() == mConnectedState)) {
4688                    lastConnectAttemptTimestamp = System.currentTimeMillis();
4689                    targetWificonfiguration =
4690                            mWifiConfigManager.getWifiConfiguration(mWifiInfo.getNetworkId());
4691                    transitionTo(mRoamingState);
4692                }
4693            }
4694        }
4695
4696        mWifiInfo.setSSID(stateChangeResult.wifiSsid);
4697        mWifiInfo.setEphemeral(mWifiConfigManager.isEphemeral(mWifiInfo.getNetworkId()));
4698
4699        mSupplicantStateTracker.sendMessage(Message.obtain(message));
4700
4701        return state;
4702    }
4703
4704    /**
4705     * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
4706     * using the interface, stopping DHCP & disabling interface
4707     */
4708    private void handleNetworkDisconnect() {
4709        if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP"
4710                + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()
4711                + " - " + Thread.currentThread().getStackTrace()[3].getMethodName()
4712                + " - " + Thread.currentThread().getStackTrace()[4].getMethodName()
4713                + " - " + Thread.currentThread().getStackTrace()[5].getMethodName());
4714
4715        stopRssiMonitoringOffload();
4716
4717        clearCurrentConfigBSSID("handleNetworkDisconnect");
4718
4719        stopIpManager();
4720
4721        /* Reset data structures */
4722        mBadLinkspeedcount = 0;
4723        mWifiInfo.reset();
4724        linkDebouncing = false;
4725        /* Reset roaming parameters */
4726        mAutoRoaming = false;
4727
4728        /**
4729         *  fullBandConnectedTimeIntervalMilli:
4730         *  - start scans at mWifiConfigManager.wifiAssociatedShortScanIntervalMilli seconds
4731         *    interval
4732         *  - exponentially increase to mWifiConfigManager.associatedFullScanMaxIntervalMilli
4733         *  Initialize to sane value = 20 seconds
4734         */
4735        fullBandConnectedTimeIntervalMilli = 20 * 1000;
4736
4737        setNetworkDetailedState(DetailedState.DISCONNECTED);
4738        if (mNetworkAgent != null) {
4739            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
4740            mNetworkAgent = null;
4741        }
4742        mWifiConfigManager.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
4743
4744        /* Clear network properties */
4745        clearLinkProperties();
4746
4747        /* Cend event to CM & network change broadcast */
4748        sendNetworkStateChangeBroadcast(mLastBssid);
4749
4750        /* Cancel auto roam requests */
4751        autoRoamSetBSSID(mLastNetworkId, "any");
4752        mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
4753        mLastBssid = null;
4754        registerDisconnected();
4755        mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
4756    }
4757
4758    private void handleSupplicantConnectionLoss(boolean killSupplicant) {
4759        /* Socket connection can be lost when we do a graceful shutdown
4760        * or when the driver is hung. Ensure supplicant is stopped here.
4761        */
4762        if (killSupplicant) {
4763            mWifiMonitor.killSupplicant(mP2pSupported);
4764        }
4765        mWifiNative.closeSupplicantConnection();
4766        sendSupplicantConnectionChangedBroadcast(false);
4767        setWifiState(WIFI_STATE_DISABLED);
4768    }
4769
4770    void handlePreDhcpSetup() {
4771        if (!mBluetoothConnectionActive) {
4772            /*
4773             * There are problems setting the Wi-Fi driver's power
4774             * mode to active when bluetooth coexistence mode is
4775             * enabled or sense.
4776             * <p>
4777             * We set Wi-Fi to active mode when
4778             * obtaining an IP address because we've found
4779             * compatibility issues with some routers with low power
4780             * mode.
4781             * <p>
4782             * In order for this active power mode to properly be set,
4783             * we disable coexistence mode until we're done with
4784             * obtaining an IP address.  One exception is if we
4785             * are currently connected to a headset, since disabling
4786             * coexistence would interrupt that connection.
4787             */
4788            // Disable the coexistence mode
4789            mWifiNative.setBluetoothCoexistenceMode(
4790                    mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
4791        }
4792
4793        // Disable power save and suspend optimizations during DHCP
4794        // Note: The order here is important for now. Brcm driver changes
4795        // power settings when we control suspend mode optimizations.
4796        // TODO: Remove this comment when the driver is fixed.
4797        setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
4798        mWifiNative.setPowerSave(false);
4799
4800        // Update link layer stats
4801        getWifiLinkLayerStats(false);
4802
4803        /* P2p discovery breaks dhcp, shut it down in order to get through this */
4804        Message msg = new Message();
4805        msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY;
4806        msg.arg1 = WifiP2pServiceImpl.ENABLED;
4807        msg.arg2 = DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE;
4808        msg.obj = WifiStateMachine.this;
4809        mWifiP2pChannel.sendMessage(msg);
4810    }
4811
4812    void handlePostDhcpSetup() {
4813        /* Restore power save and suspend optimizations */
4814        setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
4815        mWifiNative.setPowerSave(true);
4816
4817        mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY,
4818                WifiP2pServiceImpl.DISABLED);
4819
4820        // Set the coexistence mode back to its default value
4821        mWifiNative.setBluetoothCoexistenceMode(
4822                mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
4823    }
4824
4825    void connectScanningService() {
4826        if (mWifiScanner == null) {
4827            mWifiScanner = (WifiScanner) mContext.getSystemService(Context.WIFI_SCANNING_SERVICE);
4828        }
4829    }
4830
4831    private void handleIPv4Success(DhcpResults dhcpResults) {
4832        if (PDBG) {
4833            logd("handleIPv4Success <" + dhcpResults.toString() + ">");
4834            logd("link address " + dhcpResults.ipAddress);
4835        }
4836
4837        Inet4Address addr;
4838        synchronized (mDhcpResultsLock) {
4839            mDhcpResults = dhcpResults;
4840            addr = (Inet4Address) dhcpResults.ipAddress.getAddress();
4841        }
4842
4843        if (isRoaming()) {
4844            int previousAddress = mWifiInfo.getIpAddress();
4845            int newAddress = NetworkUtils.inetAddressToInt(addr);
4846            if (previousAddress != newAddress) {
4847                logd("handleIPv4Success, roaming and address changed" +
4848                        mWifiInfo + " got: " + addr);
4849            }
4850        }
4851        mWifiInfo.setInetAddress(addr);
4852        mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint());
4853    }
4854
4855    private void handleSuccessfulIpConfiguration() {
4856        mLastSignalLevel = -1; // Force update of signal strength
4857        WifiConfiguration c = getCurrentWifiConfiguration();
4858        if (c != null) {
4859            // Reset IP failure tracking
4860            c.getNetworkSelectionStatus().clearDisableReasonCounter(
4861                    WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
4862
4863            // Tell the framework whether the newly connected network is trusted or untrusted.
4864            updateCapabilities(c);
4865        }
4866        if (c != null) {
4867            ScanResult result = getCurrentScanResult();
4868            if (result == null) {
4869                logd("WifiStateMachine: handleSuccessfulIpConfiguration and no scan results" +
4870                        c.configKey());
4871            } else {
4872                // Clear the per BSSID failure count
4873                result.numIpConfigFailures = 0;
4874                // Clear the WHOLE BSSID blacklist, which means supplicant is free to retry
4875                // any BSSID, even though it may already have a non zero ip failure count,
4876                // this will typically happen if the user walks away and come back to his arrea
4877                // TODO: implement blacklisting based on a timer, i.e. keep BSSID blacklisted
4878                // in supplicant for a couple of hours or a day
4879                mWifiConfigManager.clearBssidBlacklist();
4880            }
4881        }
4882    }
4883
4884    private void handleIPv4Failure() {
4885        // TODO: Move this to provisioning failure, not DHCP failure.
4886        // DHCPv4 failure is expected on an IPv6-only network.
4887        mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_DHCP_FAILURE);
4888        if (DBG) {
4889            int count = -1;
4890            WifiConfiguration config = getCurrentWifiConfiguration();
4891            if (config != null) {
4892                count = config.getNetworkSelectionStatus().getDisableReasonCounter(
4893                        WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
4894            }
4895            log("DHCP failure count=" + count);
4896        }
4897        mWifiMetrics.endConnectionEvent(
4898                WifiMetrics.ConnectionEvent.LLF_NONE,
4899                WifiMetricsProto.ConnectionEvent.HLF_DHCP);
4900        synchronized(mDhcpResultsLock) {
4901             if (mDhcpResults != null) {
4902                 mDhcpResults.clear();
4903             }
4904        }
4905        if (PDBG) {
4906            logd("handleIPv4Failure");
4907        }
4908    }
4909
4910    private void handleIpConfigurationLost() {
4911        mWifiInfo.setInetAddress(null);
4912        mWifiInfo.setMeteredHint(false);
4913
4914        mWifiConfigManager.updateNetworkSelectionStatus(mLastNetworkId,
4915                WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);
4916
4917        /* DHCP times out after about 30 seconds, we do a
4918         * disconnect thru supplicant, we will let autojoin retry connecting to the network
4919         */
4920        mWifiNative.disconnect();
4921    }
4922
4923    // TODO: De-duplicated this and handleIpConfigurationLost().
4924    private void handleIpReachabilityLost() {
4925        mWifiInfo.setInetAddress(null);
4926        mWifiInfo.setMeteredHint(false);
4927
4928        // TODO: Determine whether to call some form of mWifiConfigManager.handleSSIDStateChange().
4929
4930        // Disconnect via supplicant, and let autojoin retry connecting to the network.
4931        mWifiNative.disconnect();
4932    }
4933
4934    private int convertFrequencyToChannelNumber(int frequency) {
4935        if (frequency >= 2412 && frequency <= 2484) {
4936            return (frequency -2412) / 5 + 1;
4937        } else if (frequency >= 5170  &&  frequency <=5825) {
4938            //DFS is included
4939            return (frequency -5170) / 5 + 34;
4940        } else {
4941            return 0;
4942        }
4943    }
4944
4945    private int chooseApChannel(int apBand) {
4946        int apChannel;
4947        int[] channel;
4948
4949        if (apBand == 0)  {
4950            ArrayList<Integer> allowed2GChannel =
4951                    mWifiApConfigStore.getAllowed2GChannel();
4952            if (allowed2GChannel == null || allowed2GChannel.size() == 0) {
4953                //most safe channel to use
4954                if(DBG) {
4955                    Log.d(TAG, "No specified 2G allowed channel list");
4956                }
4957                apChannel = 6;
4958            } else {
4959                int index = mRandom.nextInt(allowed2GChannel.size());
4960                apChannel = allowed2GChannel.get(index).intValue();
4961            }
4962        } else {
4963            //5G without DFS
4964            channel = mWifiNative.getChannelsForBand(2);
4965            if (channel != null && channel.length > 0) {
4966                apChannel = channel[mRandom.nextInt(channel.length)];
4967                apChannel = convertFrequencyToChannelNumber(apChannel);
4968            } else {
4969                Log.e(TAG, "SoftAp do not get available channel list");
4970                apChannel = 0;
4971            }
4972        }
4973
4974        if(DBG) {
4975            Log.d(TAG, "SoftAp set on channel " + apChannel);
4976        }
4977
4978        return apChannel;
4979    }
4980
4981    /* Driver/firmware setup for soft AP. */
4982    private boolean setupDriverForSoftAp() {
4983        if (!mWifiNative.loadDriver()) {
4984            Log.e(TAG, "Failed to load driver for softap");
4985            return false;
4986        }
4987
4988        if (mWifiNative.getInterfaces() != 0) {
4989            if (!mWifiNative.toggleInterface(0)) {
4990                Log.e(TAG, "toggleInterface failed");
4991                return false;
4992            }
4993        } else {
4994            if (DBG) Log.d(TAG, "No interfaces to toggle");
4995        }
4996
4997        try {
4998            mNwService.wifiFirmwareReload(mInterfaceName, "AP");
4999            if (DBG) Log.d(TAG, "Firmware reloaded in AP mode");
5000        } catch (Exception e) {
5001            Log.e(TAG, "Failed to reload AP firmware " + e);
5002        }
5003
5004        if (!mWifiNative.startHal()) {
5005            /* starting HAL is optional */
5006            Log.e(TAG, "Failed to start HAL");
5007        }
5008        return true;
5009    }
5010
5011    private byte[] macAddressFromString(String macString) {
5012        String[] macBytes = macString.split(":");
5013        if (macBytes.length != 6) {
5014            throw new IllegalArgumentException("MAC address should be 6 bytes long!");
5015        }
5016        byte[] mac = new byte[6];
5017        for (int i = 0; i < macBytes.length; i++) {
5018            Integer hexVal = Integer.parseInt(macBytes[i], 16);
5019            mac[i] = hexVal.byteValue();
5020        }
5021        return mac;
5022    }
5023
5024    /*
5025     * Read a MAC address in /proc/arp/table, used by WifistateMachine
5026     * so as to record MAC address of default gateway.
5027     **/
5028    private String macAddressFromRoute(String ipAddress) {
5029        String macAddress = null;
5030        BufferedReader reader = null;
5031        try {
5032            reader = new BufferedReader(new FileReader("/proc/net/arp"));
5033
5034            // Skip over the line bearing colum titles
5035            String line = reader.readLine();
5036
5037            while ((line = reader.readLine()) != null) {
5038                String[] tokens = line.split("[ ]+");
5039                if (tokens.length < 6) {
5040                    continue;
5041                }
5042
5043                // ARP column format is
5044                // Address HWType HWAddress Flags Mask IFace
5045                String ip = tokens[0];
5046                String mac = tokens[3];
5047
5048                if (ipAddress.equals(ip)) {
5049                    macAddress = mac;
5050                    break;
5051                }
5052            }
5053
5054            if (macAddress == null) {
5055                loge("Did not find remoteAddress {" + ipAddress + "} in " +
5056                        "/proc/net/arp");
5057            }
5058
5059        } catch (FileNotFoundException e) {
5060            loge("Could not open /proc/net/arp to lookup mac address");
5061        } catch (IOException e) {
5062            loge("Could not read /proc/net/arp to lookup mac address");
5063        } finally {
5064            try {
5065                if (reader != null) {
5066                    reader.close();
5067                }
5068            } catch (IOException e) {
5069                // Do nothing
5070            }
5071        }
5072        return macAddress;
5073
5074    }
5075
5076    private class WifiNetworkFactory extends NetworkFactory {
5077        public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) {
5078            super(l, c, TAG, f);
5079        }
5080
5081        @Override
5082        protected void needNetworkFor(NetworkRequest networkRequest, int score) {
5083            ++mConnectionRequests;
5084        }
5085
5086        @Override
5087        protected void releaseNetworkFor(NetworkRequest networkRequest) {
5088            --mConnectionRequests;
5089        }
5090
5091        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5092            pw.println("mConnectionRequests " + mConnectionRequests);
5093        }
5094
5095    }
5096
5097    private class UntrustedWifiNetworkFactory extends NetworkFactory {
5098        private int mUntrustedReqCount;
5099
5100        public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) {
5101            super(l, c, tag, f);
5102        }
5103
5104        @Override
5105        protected void needNetworkFor(NetworkRequest networkRequest, int score) {
5106            if (!networkRequest.networkCapabilities.hasCapability(
5107                    NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
5108                if (++mUntrustedReqCount == 1) {
5109                    setAllowUntrustedConnections(true);
5110                }
5111            }
5112        }
5113
5114        @Override
5115        protected void releaseNetworkFor(NetworkRequest networkRequest) {
5116            if (!networkRequest.networkCapabilities.hasCapability(
5117                    NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
5118                if (--mUntrustedReqCount == 0) {
5119                    setAllowUntrustedConnections(false);
5120                }
5121            }
5122        }
5123
5124        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5125            pw.println("mUntrustedReqCount " + mUntrustedReqCount);
5126        }
5127    }
5128
5129    void maybeRegisterNetworkFactory() {
5130        if (mNetworkFactory == null) {
5131            checkAndSetConnectivityInstance();
5132            if (mCm != null) {
5133                mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext,
5134                        NETWORKTYPE, mNetworkCapabilitiesFilter);
5135                mNetworkFactory.setScoreFilter(60);
5136                mNetworkFactory.register();
5137
5138                // We can't filter untrusted network in the capabilities filter because a trusted
5139                // network would still satisfy a request that accepts untrusted ones.
5140                mUntrustedNetworkFactory = new UntrustedWifiNetworkFactory(getHandler().getLooper(),
5141                        mContext, NETWORKTYPE_UNTRUSTED, mNetworkCapabilitiesFilter);
5142                mUntrustedNetworkFactory.setScoreFilter(Integer.MAX_VALUE);
5143                mUntrustedNetworkFactory.register();
5144            }
5145        }
5146    }
5147
5148    /********************************************************
5149     * HSM states
5150     *******************************************************/
5151
5152    class DefaultState extends State {
5153        @Override
5154        public boolean processMessage(Message message) {
5155            logStateAndMessage(message, this);
5156
5157            switch (message.what) {
5158                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
5159                    AsyncChannel ac = (AsyncChannel) message.obj;
5160                    if (ac == mWifiP2pChannel) {
5161                        if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
5162                            mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
5163                        } else {
5164                            loge("WifiP2pService connection failure, error=" + message.arg1);
5165                        }
5166                    } else {
5167                        loge("got HALF_CONNECTED for unknown channel");
5168                    }
5169                    break;
5170                }
5171                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
5172                    AsyncChannel ac = (AsyncChannel) message.obj;
5173                    if (ac == mWifiP2pChannel) {
5174                        loge("WifiP2pService channel lost, message.arg1 =" + message.arg1);
5175                        //TODO: Re-establish connection to state machine after a delay
5176                        // mWifiP2pChannel.connect(mContext, getHandler(),
5177                        // mWifiP2pManager.getMessenger());
5178                    }
5179                    break;
5180                }
5181                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
5182                    mBluetoothConnectionActive = (message.arg1 !=
5183                            BluetoothAdapter.STATE_DISCONNECTED);
5184                    break;
5185                    /* Synchronous call returns */
5186                case CMD_PING_SUPPLICANT:
5187                case CMD_ENABLE_NETWORK:
5188                case CMD_ADD_OR_UPDATE_NETWORK:
5189                case CMD_REMOVE_NETWORK:
5190                case CMD_SAVE_CONFIG:
5191                    replyToMessage(message, message.what, FAILURE);
5192                    break;
5193                case CMD_GET_CAPABILITY_FREQ:
5194                    replyToMessage(message, message.what, null);
5195                    break;
5196                case CMD_GET_CONFIGURED_NETWORKS:
5197                    replyToMessage(message, message.what, (List<WifiConfiguration>) null);
5198                    break;
5199                case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
5200                    replyToMessage(message, message.what, (List<WifiConfiguration>) null);
5201                    break;
5202                case CMD_ENABLE_RSSI_POLL:
5203                    mEnableRssiPolling = (message.arg1 == 1);
5204                    break;
5205                case CMD_SET_HIGH_PERF_MODE:
5206                    if (message.arg1 == 1) {
5207                        setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);
5208                    } else {
5209                        setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);
5210                    }
5211                    break;
5212                case CMD_BOOT_COMPLETED:
5213                    maybeRegisterNetworkFactory();
5214                    break;
5215                case CMD_SCREEN_STATE_CHANGED:
5216                    handleScreenStateChanged(message.arg1 != 0);
5217                    break;
5218                    /* Discard */
5219                case CMD_START_SCAN:
5220                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5221                    break;
5222                case CMD_START_SUPPLICANT:
5223                case CMD_STOP_SUPPLICANT:
5224                case CMD_STOP_SUPPLICANT_FAILED:
5225                case CMD_START_DRIVER:
5226                case CMD_STOP_DRIVER:
5227                case CMD_DRIVER_START_TIMED_OUT:
5228                case CMD_START_AP:
5229                case CMD_START_AP_FAILURE:
5230                case CMD_STOP_AP:
5231                case CMD_AP_STOPPED:
5232                case CMD_DISCONNECT:
5233                case CMD_RECONNECT:
5234                case CMD_REASSOCIATE:
5235                case CMD_RELOAD_TLS_AND_RECONNECT:
5236                case WifiMonitor.SUP_CONNECTION_EVENT:
5237                case WifiMonitor.SUP_DISCONNECTION_EVENT:
5238                case WifiMonitor.NETWORK_CONNECTION_EVENT:
5239                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5240                case WifiMonitor.SCAN_RESULTS_EVENT:
5241                case WifiMonitor.SCAN_FAILED_EVENT:
5242                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5243                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
5244                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
5245                case WifiMonitor.WPS_OVERLAP_EVENT:
5246                case CMD_BLACKLIST_NETWORK:
5247                case CMD_CLEAR_BLACKLIST:
5248                case CMD_SET_OPERATIONAL_MODE:
5249                case CMD_SET_FREQUENCY_BAND:
5250                case CMD_RSSI_POLL:
5251                case CMD_ENABLE_ALL_NETWORKS:
5252                case DhcpClient.CMD_PRE_DHCP_ACTION:
5253                case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
5254                case DhcpClient.CMD_POST_DHCP_ACTION:
5255                case CMD_NO_NETWORKS_PERIODIC_SCAN:
5256                case CMD_DISABLE_P2P_RSP:
5257                case WifiMonitor.SUP_REQUEST_IDENTITY:
5258                case CMD_TEST_NETWORK_DISCONNECT:
5259                case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
5260                case WifiMonitor.SUP_REQUEST_SIM_AUTH:
5261                case CMD_TARGET_BSSID:
5262                case CMD_AUTO_CONNECT:
5263                case CMD_AUTO_ROAM:
5264                case CMD_AUTO_SAVE_NETWORK:
5265                case CMD_ASSOCIATED_BSSID:
5266                case CMD_UNWANTED_NETWORK:
5267                case CMD_DISCONNECTING_WATCHDOG_TIMER:
5268                case CMD_ROAM_WATCHDOG_TIMER:
5269                case CMD_DISABLE_EPHEMERAL_NETWORK:
5270                case CMD_RESTART_AUTOJOIN_OFFLOAD:
5271                case CMD_STARTED_PNO_DBG:
5272                case CMD_STARTED_GSCAN_DBG:
5273                case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
5274                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5275                    break;
5276                case CMD_SET_COUNTRY_CODE:
5277                    String country = (String) message.obj;
5278                    final boolean persist = (message.arg2 == 1);
5279                    final int sequence = message.arg1;
5280                    if (sequence != mCountryCodeSequence.get()) {
5281                        if (DBG) log("set country code ignored due to sequnce num");
5282                        break;
5283                    }
5284
5285                    if (persist) {
5286                        country = country.toUpperCase(Locale.ROOT);
5287                        if (DBG) log("set country code " + (country == null ? "(null)" : country));
5288                        Settings.Global.putString(mContext.getContentResolver(),
5289                                Settings.Global.WIFI_COUNTRY_CODE,
5290                                country == null ? "" : country);
5291                    }
5292
5293                    break;
5294                case CMD_SET_SUSPEND_OPT_ENABLED:
5295                    if (message.arg1 == 1) {
5296                        mSuspendWakeLock.release();
5297                        setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true);
5298                    } else {
5299                        setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false);
5300                    }
5301                    break;
5302                case WifiMonitor.DRIVER_HUNG_EVENT:
5303                    setSupplicantRunning(false);
5304                    setSupplicantRunning(true);
5305                    break;
5306                case WifiManager.CONNECT_NETWORK:
5307                    replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
5308                            WifiManager.BUSY);
5309                    break;
5310                case WifiManager.FORGET_NETWORK:
5311                    replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
5312                            WifiManager.BUSY);
5313                    break;
5314                case WifiManager.SAVE_NETWORK:
5315                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
5316                    replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
5317                            WifiManager.BUSY);
5318                    break;
5319                case WifiManager.START_WPS:
5320                    replyToMessage(message, WifiManager.WPS_FAILED,
5321                            WifiManager.BUSY);
5322                    break;
5323                case WifiManager.CANCEL_WPS:
5324                    replyToMessage(message, WifiManager.CANCEL_WPS_FAILED,
5325                            WifiManager.BUSY);
5326                    break;
5327                case WifiManager.DISABLE_NETWORK:
5328                    replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
5329                            WifiManager.BUSY);
5330                    break;
5331                case WifiManager.RSSI_PKTCNT_FETCH:
5332                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED,
5333                            WifiManager.BUSY);
5334                    break;
5335                case CMD_GET_SUPPORTED_FEATURES:
5336                    int featureSet = mWifiNative.getSupportedFeatureSet();
5337                    replyToMessage(message, message.what, featureSet);
5338                    break;
5339                case CMD_FIRMWARE_ALERT:
5340                    if (mWifiLogger != null) {
5341                        byte[] buffer = (byte[])message.obj;
5342                        mWifiLogger.captureAlertData(message.arg1, buffer);
5343                    }
5344                    break;
5345                case CMD_GET_LINK_LAYER_STATS:
5346                    // Not supported hence reply with error message
5347                    replyToMessage(message, message.what, null);
5348                    break;
5349                case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
5350                    NetworkInfo info = (NetworkInfo) message.obj;
5351                    mP2pConnected.set(info.isConnected());
5352                    break;
5353                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
5354                    mTemporarilyDisconnectWifi = (message.arg1 == 1);
5355                    replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
5356                    break;
5357                /* Link configuration (IP address, DNS, ...) changes notified via netlink */
5358                case CMD_UPDATE_LINKPROPERTIES:
5359                    updateLinkProperties((LinkProperties) message.obj);
5360                    break;
5361                case CMD_GET_MATCHING_CONFIG:
5362                    replyToMessage(message, message.what);
5363                    break;
5364                case CMD_IP_CONFIGURATION_SUCCESSFUL:
5365                case CMD_IP_CONFIGURATION_LOST:
5366                case CMD_IP_REACHABILITY_LOST:
5367                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5368                    break;
5369                case CMD_GET_CONNECTION_STATISTICS:
5370                    replyToMessage(message, message.what, mWifiConnectionStatistics);
5371                    break;
5372                case CMD_REMOVE_APP_CONFIGURATIONS:
5373                    deferMessage(message);
5374                    break;
5375                case CMD_REMOVE_USER_CONFIGURATIONS:
5376                    deferMessage(message);
5377                    break;
5378                case CMD_START_IP_PACKET_OFFLOAD:
5379                    if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent(
5380                            message.arg1,
5381                            ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
5382                    break;
5383                case CMD_STOP_IP_PACKET_OFFLOAD:
5384                    if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent(
5385                            message.arg1,
5386                            ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
5387                    break;
5388                case CMD_START_RSSI_MONITORING_OFFLOAD:
5389                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5390                    break;
5391                case CMD_STOP_RSSI_MONITORING_OFFLOAD:
5392                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
5393                    break;
5394                case CMD_USER_SWITCH:
5395                    mCurrentUserId = message.arg1;
5396                    mWifiConfigManager.handleUserSwitch();
5397                    break;
5398                case CMD_ADD_PASSPOINT_MO:
5399                case CMD_MODIFY_PASSPOINT_MO:
5400                case CMD_QUERY_OSU_ICON:
5401                case CMD_MATCH_PROVIDER_NETWORK:
5402                    /* reply with arg1 = 0 - it returns API failure to the calling app
5403                     * (message.what is not looked at)
5404                     */
5405                    replyToMessage(message, message.what);
5406                    break;
5407                default:
5408                    loge("Error! unhandled message" + message);
5409                    break;
5410            }
5411            return HANDLED;
5412        }
5413    }
5414
5415    class InitialState extends State {
5416        @Override
5417        public void enter() {
5418            mWifiNative.stopHal();
5419            mWifiNative.unloadDriver();
5420            if (mWifiP2pChannel == null) {
5421                mWifiP2pChannel = new AsyncChannel();
5422                mWifiP2pChannel.connect(mContext, getHandler(),
5423                    mWifiP2pServiceImpl.getP2pStateMachineMessenger());
5424            }
5425
5426            if (mWifiApConfigStore == null) {
5427                mWifiApConfigStore = mFacade.makeApConfigStore(mContext);
5428            }
5429
5430            if (mWifiConfigManager.enableHalBasedPno.get()) {
5431                // make sure developer Settings are in sync with the config option
5432                mHalBasedPnoEnableInDevSettings = true;
5433            }
5434        }
5435        @Override
5436        public boolean processMessage(Message message) {
5437            logStateAndMessage(message, this);
5438            switch (message.what) {
5439                case CMD_START_SUPPLICANT:
5440                    if (mWifiNative.loadDriver()) {
5441                        try {
5442                            mNwService.wifiFirmwareReload(mInterfaceName, "STA");
5443                        } catch (Exception e) {
5444                            loge("Failed to reload STA firmware " + e);
5445                            // Continue
5446                        }
5447
5448                        try {
5449                            // A runtime crash can leave the interface up and
5450                            // IP addresses configured, and this affects
5451                            // connectivity when supplicant starts up.
5452                            // Ensure interface is down and we have no IP
5453                            // addresses before a supplicant start.
5454                            mNwService.setInterfaceDown(mInterfaceName);
5455                            mNwService.clearInterfaceAddresses(mInterfaceName);
5456
5457                            // Set privacy extensions
5458                            mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
5459
5460                            // IPv6 is enabled only as long as access point is connected since:
5461                            // - IPv6 addresses and routes stick around after disconnection
5462                            // - kernel is unaware when connected and fails to start IPv6 negotiation
5463                            // - kernel can start autoconfiguration when 802.1x is not complete
5464                            mNwService.disableIpv6(mInterfaceName);
5465                        } catch (RemoteException re) {
5466                            loge("Unable to change interface settings: " + re);
5467                        } catch (IllegalStateException ie) {
5468                            loge("Unable to change interface settings: " + ie);
5469                        }
5470
5471                       /* Stop a running supplicant after a runtime restart
5472                        * Avoids issues with drivers that do not handle interface down
5473                        * on a running supplicant properly.
5474                        */
5475                        mWifiMonitor.killSupplicant(mP2pSupported);
5476
5477                        if (mWifiNative.startHal() == false) {
5478                            /* starting HAL is optional */
5479                            loge("Failed to start HAL");
5480                        }
5481
5482                        if (mWifiNative.startSupplicant(mP2pSupported)) {
5483                            setWifiState(WIFI_STATE_ENABLING);
5484                            if (DBG) log("Supplicant start successful");
5485                            mWifiMonitor.startMonitoring(mInterfaceName);
5486                            transitionTo(mSupplicantStartingState);
5487                        } else {
5488                            loge("Failed to start supplicant!");
5489                        }
5490                    } else {
5491                        loge("Failed to load driver");
5492                    }
5493                    break;
5494                case CMD_START_AP:
5495                    if (setupDriverForSoftAp()) {
5496                        transitionTo(mSoftApState);
5497                    } else {
5498                        setWifiApState(WIFI_AP_STATE_FAILED,
5499                                WifiManager.SAP_START_FAILURE_GENERAL);
5500                        /**
5501                         * Transition to InitialState (current state) to reset the
5502                         * driver/HAL back to the initial state.
5503                         */
5504                        transitionTo(mInitialState);
5505                    }
5506                    break;
5507                default:
5508                    return NOT_HANDLED;
5509            }
5510            return HANDLED;
5511        }
5512    }
5513
5514    class SupplicantStartingState extends State {
5515        private void initializeWpsDetails() {
5516            String detail;
5517            detail = SystemProperties.get("ro.product.name", "");
5518            if (!mWifiNative.setDeviceName(detail)) {
5519                loge("Failed to set device name " +  detail);
5520            }
5521            detail = SystemProperties.get("ro.product.manufacturer", "");
5522            if (!mWifiNative.setManufacturer(detail)) {
5523                loge("Failed to set manufacturer " + detail);
5524            }
5525            detail = SystemProperties.get("ro.product.model", "");
5526            if (!mWifiNative.setModelName(detail)) {
5527                loge("Failed to set model name " + detail);
5528            }
5529            detail = SystemProperties.get("ro.product.model", "");
5530            if (!mWifiNative.setModelNumber(detail)) {
5531                loge("Failed to set model number " + detail);
5532            }
5533            detail = SystemProperties.get("ro.serialno", "");
5534            if (!mWifiNative.setSerialNumber(detail)) {
5535                loge("Failed to set serial number " + detail);
5536            }
5537            if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) {
5538                loge("Failed to set WPS config methods");
5539            }
5540            if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
5541                loge("Failed to set primary device type " + mPrimaryDeviceType);
5542            }
5543        }
5544
5545        @Override
5546        public boolean processMessage(Message message) {
5547            logStateAndMessage(message, this);
5548
5549            switch(message.what) {
5550                case WifiMonitor.SUP_CONNECTION_EVENT:
5551                    if (DBG) log("Supplicant connection established");
5552                    setWifiState(WIFI_STATE_ENABLED);
5553                    mSupplicantRestartCount = 0;
5554                    /* Reset the supplicant state to indicate the supplicant
5555                     * state is not known at this time */
5556                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
5557                    /* Initialize data structures */
5558                    mLastBssid = null;
5559                    mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
5560                    mLastSignalLevel = -1;
5561
5562                    mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
5563                    /* set frequency band of operation */
5564                    setFrequencyBand();
5565                    mWifiNative.enableSaveConfig();
5566                    mWifiConfigManager.loadAndEnableAllNetworks();
5567                    if (mWifiConfigManager.enableVerboseLogging.get() > 0) {
5568                        enableVerboseLogging(mWifiConfigManager.enableVerboseLogging.get());
5569                    }
5570                    initializeWpsDetails();
5571
5572                    sendSupplicantConnectionChangedBroadcast(true);
5573                    transitionTo(mDriverStartedState);
5574                    break;
5575                case WifiMonitor.SUP_DISCONNECTION_EVENT:
5576                    if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
5577                        loge("Failed to setup control channel, restart supplicant");
5578                        mWifiMonitor.killSupplicant(mP2pSupported);
5579                        transitionTo(mInitialState);
5580                        sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
5581                    } else {
5582                        loge("Failed " + mSupplicantRestartCount +
5583                                " times to start supplicant, unload driver");
5584                        mSupplicantRestartCount = 0;
5585                        setWifiState(WIFI_STATE_UNKNOWN);
5586                        transitionTo(mInitialState);
5587                    }
5588                    break;
5589                case CMD_START_SUPPLICANT:
5590                case CMD_STOP_SUPPLICANT:
5591                case CMD_START_AP:
5592                case CMD_STOP_AP:
5593                case CMD_START_DRIVER:
5594                case CMD_STOP_DRIVER:
5595                case CMD_SET_OPERATIONAL_MODE:
5596                case CMD_SET_COUNTRY_CODE:
5597                case CMD_SET_FREQUENCY_BAND:
5598                case CMD_START_PACKET_FILTERING:
5599                case CMD_STOP_PACKET_FILTERING:
5600                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5601                    deferMessage(message);
5602                    break;
5603                default:
5604                    return NOT_HANDLED;
5605            }
5606            return HANDLED;
5607        }
5608    }
5609
5610    class SupplicantStartedState extends State {
5611        @Override
5612        public void enter() {
5613            /* Wifi is available as long as we have a connection to supplicant */
5614            mNetworkInfo.setIsAvailable(true);
5615            if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
5616
5617            int defaultInterval = mContext.getResources().getInteger(
5618                    R.integer.config_wifi_supplicant_scan_interval);
5619
5620            mSupplicantScanIntervalMs = mFacade.getLongSetting(mContext,
5621                    Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
5622                    defaultInterval);
5623
5624            mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
5625            mWifiNative.setExternalSim(true);
5626
5627            /* turn on use of DFS channels */
5628            mWifiNative.setDfsFlag(true);
5629
5630            /* set country code */
5631            initializeCountryCode();
5632
5633            setRandomMacOui();
5634            mWifiNative.enableAutoConnect(false);
5635        }
5636
5637        @Override
5638        public boolean processMessage(Message message) {
5639            logStateAndMessage(message, this);
5640
5641            switch(message.what) {
5642                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
5643                    if (mP2pSupported) {
5644                        transitionTo(mWaitForP2pDisableState);
5645                    } else {
5646                        transitionTo(mSupplicantStoppingState);
5647                    }
5648                    break;
5649                case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
5650                    loge("Connection lost, restart supplicant");
5651                    handleSupplicantConnectionLoss(true);
5652                    handleNetworkDisconnect();
5653                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
5654                    if (mP2pSupported) {
5655                        transitionTo(mWaitForP2pDisableState);
5656                    } else {
5657                        transitionTo(mInitialState);
5658                    }
5659                    sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
5660                    break;
5661                case WifiMonitor.SCAN_RESULTS_EVENT:
5662                case WifiMonitor.SCAN_FAILED_EVENT:
5663                    maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered
5664                    noteScanEnd();
5665                    setScanResults();
5666                    if (mIsFullScanOngoing || mSendScanResultsBroadcast) {
5667                        /* Just updated results from full scan, let apps know about this */
5668                        boolean scanSucceeded = message.what == WifiMonitor.SCAN_RESULTS_EVENT;
5669                        sendScanResultsAvailableBroadcast(scanSucceeded);
5670                    }
5671                    mSendScanResultsBroadcast = false;
5672                    mIsScanOngoing = false;
5673                    mIsFullScanOngoing = false;
5674                    if (mBufferedScanMsg.size() > 0)
5675                        sendMessage(mBufferedScanMsg.remove());
5676                    break;
5677                case CMD_PING_SUPPLICANT:
5678                    boolean ok = mWifiNative.ping();
5679                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
5680                    break;
5681                case CMD_GET_CAPABILITY_FREQ:
5682                    String freqs = mWifiNative.getFreqCapability();
5683                    replyToMessage(message, message.what, freqs);
5684                    break;
5685                case CMD_START_AP:
5686                    /* Cannot start soft AP while in client mode */
5687                    loge("Failed to start soft AP with a running supplicant");
5688                    setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL);
5689                    break;
5690                case CMD_SET_OPERATIONAL_MODE:
5691                    mOperationalMode = message.arg1;
5692                    mWifiConfigManager.
5693                            setAndEnableLastSelectedConfiguration(
5694                                    WifiConfiguration.INVALID_NETWORK_ID);
5695                    break;
5696                case CMD_TARGET_BSSID:
5697                    // Trying to associate to this BSSID
5698                    if (message.obj != null) {
5699                        mTargetRoamBSSID = (String) message.obj;
5700                    }
5701                    break;
5702                case CMD_GET_LINK_LAYER_STATS:
5703                    WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG);
5704                    if (stats == null) {
5705                        // When firmware doesnt support link layer stats, return an empty object
5706                        stats = new WifiLinkLayerStats();
5707                    }
5708                    replyToMessage(message, message.what, stats);
5709                    break;
5710                case CMD_SET_COUNTRY_CODE:
5711                    String country = (String) message.obj;
5712                    final boolean persist = (message.arg2 == 1);
5713                    final int sequence = message.arg1;
5714                    if (sequence != mCountryCodeSequence.get()) {
5715                        if (DBG) log("set country code ignored due to sequnce num");
5716                        break;
5717                    }
5718
5719                    country = country.toUpperCase(Locale.ROOT);
5720
5721                    if (DBG) log("set country code " + (country == null ? "(null)" : country));
5722
5723                    if (!TextUtils.equals(mDriverSetCountryCode, country)) {
5724                        if (mWifiNative.setCountryCode(country)) {
5725                            mDriverSetCountryCode = country;
5726                        } else {
5727                            loge("Failed to set country code " + country);
5728                        }
5729                    }
5730
5731                    if (persist) {
5732                        Settings.Global.putString(mContext.getContentResolver(),
5733                                Settings.Global.WIFI_COUNTRY_CODE,
5734                                country == null ? "" : country);
5735                    }
5736
5737                    mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country);
5738                    break;
5739                case CMD_RESET_SIM_NETWORKS:
5740                    log("resetting EAP-SIM/AKA/AKA' networks since SIM was removed");
5741                    mWifiConfigManager.resetSimNetworks();
5742                    break;
5743                default:
5744                    return NOT_HANDLED;
5745            }
5746            return HANDLED;
5747        }
5748
5749        @Override
5750        public void exit() {
5751            mNetworkInfo.setIsAvailable(false);
5752            if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
5753        }
5754    }
5755
5756    class SupplicantStoppingState extends State {
5757        @Override
5758        public void enter() {
5759            /* Send any reset commands to supplicant before shutting it down */
5760            handleNetworkDisconnect();
5761
5762            String suppState = System.getProperty("init.svc.wpa_supplicant");
5763            if (suppState == null) suppState = "unknown";
5764            String p2pSuppState = System.getProperty("init.svc.p2p_supplicant");
5765            if (p2pSuppState == null) p2pSuppState = "unknown";
5766
5767            logd("SupplicantStoppingState: stopSupplicant "
5768                    + " init.svc.wpa_supplicant=" + suppState
5769                    + " init.svc.p2p_supplicant=" + p2pSuppState);
5770            mWifiMonitor.stopSupplicant();
5771
5772            /* Send ourselves a delayed message to indicate failure after a wait time */
5773            sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
5774                    ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
5775            setWifiState(WIFI_STATE_DISABLING);
5776            mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
5777        }
5778        @Override
5779        public boolean processMessage(Message message) {
5780            logStateAndMessage(message, this);
5781
5782            switch(message.what) {
5783                case WifiMonitor.SUP_CONNECTION_EVENT:
5784                    loge("Supplicant connection received while stopping");
5785                    break;
5786                case WifiMonitor.SUP_DISCONNECTION_EVENT:
5787                    if (DBG) log("Supplicant connection lost");
5788                    handleSupplicantConnectionLoss(false);
5789                    transitionTo(mInitialState);
5790                    break;
5791                case CMD_STOP_SUPPLICANT_FAILED:
5792                    if (message.arg1 == mSupplicantStopFailureToken) {
5793                        loge("Timed out on a supplicant stop, kill and proceed");
5794                        handleSupplicantConnectionLoss(true);
5795                        transitionTo(mInitialState);
5796                    }
5797                    break;
5798                case CMD_START_SUPPLICANT:
5799                case CMD_STOP_SUPPLICANT:
5800                case CMD_START_AP:
5801                case CMD_STOP_AP:
5802                case CMD_START_DRIVER:
5803                case CMD_STOP_DRIVER:
5804                case CMD_SET_OPERATIONAL_MODE:
5805                case CMD_SET_COUNTRY_CODE:
5806                case CMD_SET_FREQUENCY_BAND:
5807                case CMD_START_PACKET_FILTERING:
5808                case CMD_STOP_PACKET_FILTERING:
5809                    deferMessage(message);
5810                    break;
5811                default:
5812                    return NOT_HANDLED;
5813            }
5814            return HANDLED;
5815        }
5816    }
5817
5818    class DriverStartingState extends State {
5819        private int mTries;
5820        @Override
5821        public void enter() {
5822            mTries = 1;
5823            /* Send ourselves a delayed message to start driver a second time */
5824            sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
5825                        ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
5826        }
5827        @Override
5828        public boolean processMessage(Message message) {
5829            logStateAndMessage(message, this);
5830
5831            switch(message.what) {
5832               case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5833                    SupplicantState state = handleSupplicantStateChange(message);
5834                    /* If suplicant is exiting out of INTERFACE_DISABLED state into
5835                     * a state that indicates driver has started, it is ready to
5836                     * receive driver commands
5837                     */
5838                    if (SupplicantState.isDriverActive(state)) {
5839                        transitionTo(mDriverStartedState);
5840                    }
5841                    break;
5842                case CMD_DRIVER_START_TIMED_OUT:
5843                    if (message.arg1 == mDriverStartToken) {
5844                        if (mTries >= 2) {
5845                            loge("Failed to start driver after " + mTries);
5846                            transitionTo(mDriverStoppedState);
5847                        } else {
5848                            loge("Driver start failed, retrying");
5849                            mWakeLock.acquire();
5850                            mWifiNative.startDriver();
5851                            mWakeLock.release();
5852
5853                            ++mTries;
5854                            /* Send ourselves a delayed message to start driver again */
5855                            sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT,
5856                                        ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS);
5857                        }
5858                    }
5859                    break;
5860                    /* Queue driver commands & connection events */
5861                case CMD_START_DRIVER:
5862                case CMD_STOP_DRIVER:
5863                case WifiMonitor.NETWORK_CONNECTION_EVENT:
5864                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5865                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
5866                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
5867                case WifiMonitor.WPS_OVERLAP_EVENT:
5868                case CMD_SET_COUNTRY_CODE:
5869                case CMD_SET_FREQUENCY_BAND:
5870                case CMD_START_PACKET_FILTERING:
5871                case CMD_STOP_PACKET_FILTERING:
5872                case CMD_START_SCAN:
5873                case CMD_DISCONNECT:
5874                case CMD_REASSOCIATE:
5875                case CMD_RECONNECT:
5876                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
5877                    deferMessage(message);
5878                    break;
5879                case WifiMonitor.SCAN_RESULTS_EVENT:
5880                case WifiMonitor.SCAN_FAILED_EVENT:
5881                    // Loose scan results obtained in Driver Starting state, they can only confuse
5882                    // the state machine
5883                    break;
5884                default:
5885                    return NOT_HANDLED;
5886            }
5887            return HANDLED;
5888        }
5889    }
5890
5891    class DriverStartedState extends State {
5892        @Override
5893        public void enter() {
5894
5895            if (PDBG) {
5896                logd("DriverStartedState enter");
5897            }
5898
5899            mWifiLogger.startLogging(mVerboseLoggingLevel > 0);
5900            mIsRunning = true;
5901            updateBatteryWorkSource(null);
5902            /**
5903             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
5904             * When this mode is on, some of the low-level scan parameters used by the
5905             * driver are changed to reduce interference with bluetooth
5906             */
5907            mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
5908            /* initialize network state */
5909            setNetworkDetailedState(DetailedState.DISCONNECTED);
5910
5911            /* Remove any filtering on Multicast v6 at start */
5912            mWifiNative.stopFilteringMulticastV6Packets();
5913
5914            /* Reset Multicast v4 filtering state */
5915            if (mFilteringMulticastV4Packets.get()) {
5916                mWifiNative.startFilteringMulticastV4Packets();
5917            } else {
5918                mWifiNative.stopFilteringMulticastV4Packets();
5919            }
5920
5921            if (mOperationalMode != CONNECT_MODE) {
5922                mWifiNative.disconnect();
5923                mWifiConfigManager.disableAllNetworks();
5924                if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
5925                    setWifiState(WIFI_STATE_DISABLED);
5926                }
5927                transitionTo(mScanModeState);
5928            } else {
5929
5930                // Status pulls in the current supplicant state and network connection state
5931                // events over the monitor connection. This helps framework sync up with
5932                // current supplicant state
5933                // TODO: actually check th supplicant status string and make sure the supplicant
5934                // is in disconnecte4d state.
5935                mWifiNative.status();
5936                // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin
5937                transitionTo(mDisconnectedState);
5938                transitionTo(mDisconnectedState);
5939            }
5940
5941            // We may have missed screen update at boot
5942            if (mScreenBroadcastReceived.get() == false) {
5943                PowerManager powerManager = (PowerManager)mContext.getSystemService(
5944                        Context.POWER_SERVICE);
5945                handleScreenStateChanged(powerManager.isScreenOn());
5946            } else {
5947                // Set the right suspend mode settings
5948                mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
5949                        && mUserWantsSuspendOpt.get());
5950            }
5951            mWifiNative.setPowerSave(true);
5952
5953            if (mP2pSupported) {
5954                if (mOperationalMode == CONNECT_MODE) {
5955                    mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
5956                } else {
5957                    // P2P statemachine starts in disabled state, and is not enabled until
5958                    // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
5959                    // keep it disabled.
5960                }
5961            }
5962
5963            final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
5964            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
5965            intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
5966            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
5967
5968            mHalFeatureSet = mWifiNative.getSupportedFeatureSet();
5969            if ((mHalFeatureSet & WifiManager.WIFI_FEATURE_HAL_EPNO)
5970                    == WifiManager.WIFI_FEATURE_HAL_EPNO) {
5971                mHalBasedPnoDriverSupported = true;
5972            }
5973
5974            // Enable link layer stats gathering
5975            mWifiNative.setWifiLinkLayerStats("wlan0", 1);
5976
5977            if (PDBG) {
5978                logd("Driverstarted State enter done, epno=" + mHalBasedPnoDriverSupported
5979                     + " feature=" + mHalFeatureSet);
5980            }
5981        }
5982
5983        @Override
5984        public boolean processMessage(Message message) {
5985            logStateAndMessage(message, this);
5986
5987            switch(message.what) {
5988                case CMD_START_SCAN:
5989                    handleScanRequest(message);
5990                    break;
5991                case CMD_SET_FREQUENCY_BAND:
5992                    int band =  message.arg1;
5993                    if (DBG) log("set frequency band " + band);
5994                    if (mWifiNative.setBand(band)) {
5995
5996                        if (PDBG)  logd("did set frequency band " + band);
5997
5998                        mFrequencyBand.set(band);
5999                        // Flush old data - like scan results
6000                        mWifiNative.bssFlush();
6001
6002                        if (PDBG)  logd("done set frequency band " + band);
6003
6004                    } else {
6005                        loge("Failed to set frequency band " + band);
6006                    }
6007                    break;
6008                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
6009                    mBluetoothConnectionActive = (message.arg1 !=
6010                            BluetoothAdapter.STATE_DISCONNECTED);
6011                    mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
6012                    break;
6013                case CMD_STOP_DRIVER:
6014                    int mode = message.arg1;
6015
6016                    log("stop driver");
6017                    mWifiConfigManager.disableAllNetworks();
6018
6019                    if (getCurrentState() != mDisconnectedState) {
6020                        mWifiNative.disconnect();
6021                        handleNetworkDisconnect();
6022                    }
6023                    mWakeLock.acquire();
6024                    mWifiNative.stopDriver();
6025                    mWakeLock.release();
6026                    if (mP2pSupported) {
6027                        transitionTo(mWaitForP2pDisableState);
6028                    } else {
6029                        transitionTo(mDriverStoppingState);
6030                    }
6031                    break;
6032                case CMD_START_DRIVER:
6033                    if (mOperationalMode == CONNECT_MODE) {
6034                        mWifiConfigManager.enableAllNetworks();
6035                    }
6036                    break;
6037                case CMD_START_PACKET_FILTERING:
6038                    if (message.arg1 == MULTICAST_V6) {
6039                        mWifiNative.startFilteringMulticastV6Packets();
6040                    } else if (message.arg1 == MULTICAST_V4) {
6041                        mWifiNative.startFilteringMulticastV4Packets();
6042                    } else {
6043                        loge("Illegal arugments to CMD_START_PACKET_FILTERING");
6044                    }
6045                    break;
6046                case CMD_STOP_PACKET_FILTERING:
6047                    if (message.arg1 == MULTICAST_V6) {
6048                        mWifiNative.stopFilteringMulticastV6Packets();
6049                    } else if (message.arg1 == MULTICAST_V4) {
6050                        mWifiNative.stopFilteringMulticastV4Packets();
6051                    } else {
6052                        loge("Illegal arugments to CMD_STOP_PACKET_FILTERING");
6053                    }
6054                    break;
6055                case CMD_SET_SUSPEND_OPT_ENABLED:
6056                    if (message.arg1 == 1) {
6057                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true);
6058                        mSuspendWakeLock.release();
6059                    } else {
6060                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false);
6061                    }
6062                    break;
6063                case CMD_SET_HIGH_PERF_MODE:
6064                    if (message.arg1 == 1) {
6065                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false);
6066                    } else {
6067                        setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
6068                    }
6069                    break;
6070                case CMD_ENABLE_TDLS:
6071                    if (message.obj != null) {
6072                        String remoteAddress = (String) message.obj;
6073                        boolean enable = (message.arg1 == 1);
6074                        mWifiNative.startTdls(remoteAddress, enable);
6075                    }
6076                    break;
6077                case WifiMonitor.ANQP_DONE_EVENT:
6078                    mWifiConfigManager.notifyANQPDone((Long) message.obj, message.arg1 != 0);
6079                    break;
6080                case CMD_STOP_IP_PACKET_OFFLOAD: {
6081                    int slot = message.arg1;
6082                    int ret = stopWifiIPPacketOffload(slot);
6083                    if (mNetworkAgent != null) {
6084                        mNetworkAgent.onPacketKeepaliveEvent(slot, ret);
6085                    }
6086                    break;
6087                }
6088                case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
6089                    mWifiConfigManager.notifyIconReceived((IconEvent) message.obj);
6090                    break;
6091                case WifiMonitor.HS20_REMEDIATION_EVENT:
6092                    mWifiConfigManager.wnmFrameReceived((WnmData) message.obj);
6093                    break;
6094                default:
6095                    return NOT_HANDLED;
6096            }
6097            return HANDLED;
6098        }
6099        @Override
6100        public void exit() {
6101
6102            mWifiLogger.stopLogging();
6103
6104            mIsRunning = false;
6105            updateBatteryWorkSource(null);
6106            mScanResults = new ArrayList<>();
6107
6108            final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
6109            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
6110            intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
6111            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
6112            noteScanEnd(); // wrap up any pending request.
6113            mBufferedScanMsg.clear();
6114        }
6115    }
6116
6117    class WaitForP2pDisableState extends State {
6118        private State mTransitionToState;
6119        @Override
6120        public void enter() {
6121            switch (getCurrentMessage().what) {
6122                case WifiMonitor.SUP_DISCONNECTION_EVENT:
6123                    mTransitionToState = mInitialState;
6124                    break;
6125                case CMD_STOP_DRIVER:
6126                    mTransitionToState = mDriverStoppingState;
6127                    break;
6128                case CMD_STOP_SUPPLICANT:
6129                    mTransitionToState = mSupplicantStoppingState;
6130                    break;
6131                default:
6132                    mTransitionToState = mDriverStoppingState;
6133                    break;
6134            }
6135            mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
6136        }
6137        @Override
6138        public boolean processMessage(Message message) {
6139            logStateAndMessage(message, this);
6140
6141            switch(message.what) {
6142                case WifiStateMachine.CMD_DISABLE_P2P_RSP:
6143                    transitionTo(mTransitionToState);
6144                    break;
6145                /* Defer wifi start/shut and driver commands */
6146                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6147                case CMD_START_SUPPLICANT:
6148                case CMD_STOP_SUPPLICANT:
6149                case CMD_START_AP:
6150                case CMD_STOP_AP:
6151                case CMD_START_DRIVER:
6152                case CMD_STOP_DRIVER:
6153                case CMD_SET_OPERATIONAL_MODE:
6154                case CMD_SET_COUNTRY_CODE:
6155                case CMD_SET_FREQUENCY_BAND:
6156                case CMD_START_PACKET_FILTERING:
6157                case CMD_STOP_PACKET_FILTERING:
6158                case CMD_START_SCAN:
6159                case CMD_DISCONNECT:
6160                case CMD_REASSOCIATE:
6161                case CMD_RECONNECT:
6162                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6163                    deferMessage(message);
6164                    break;
6165                default:
6166                    return NOT_HANDLED;
6167            }
6168            return HANDLED;
6169        }
6170    }
6171
6172    class DriverStoppingState extends State {
6173        @Override
6174        public boolean processMessage(Message message) {
6175            logStateAndMessage(message, this);
6176
6177            switch(message.what) {
6178                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6179                    SupplicantState state = handleSupplicantStateChange(message);
6180                    if (state == SupplicantState.INTERFACE_DISABLED) {
6181                        transitionTo(mDriverStoppedState);
6182                    }
6183                    break;
6184                    /* Queue driver commands */
6185                case CMD_START_DRIVER:
6186                case CMD_STOP_DRIVER:
6187                case CMD_SET_COUNTRY_CODE:
6188                case CMD_SET_FREQUENCY_BAND:
6189                case CMD_START_PACKET_FILTERING:
6190                case CMD_STOP_PACKET_FILTERING:
6191                case CMD_START_SCAN:
6192                case CMD_DISCONNECT:
6193                case CMD_REASSOCIATE:
6194                case CMD_RECONNECT:
6195                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
6196                    deferMessage(message);
6197                    break;
6198                default:
6199                    return NOT_HANDLED;
6200            }
6201            return HANDLED;
6202        }
6203    }
6204
6205    class DriverStoppedState extends State {
6206        @Override
6207        public boolean processMessage(Message message) {
6208            logStateAndMessage(message, this);
6209            switch (message.what) {
6210                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6211                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
6212                    SupplicantState state = stateChangeResult.state;
6213                    // A WEXT bug means that we can be back to driver started state
6214                    // unexpectedly
6215                    if (SupplicantState.isDriverActive(state)) {
6216                        transitionTo(mDriverStartedState);
6217                    }
6218                    break;
6219                case CMD_START_DRIVER:
6220                    mWakeLock.acquire();
6221                    mWifiNative.startDriver();
6222                    mWakeLock.release();
6223                    transitionTo(mDriverStartingState);
6224                    break;
6225                default:
6226                    return NOT_HANDLED;
6227            }
6228            return HANDLED;
6229        }
6230    }
6231
6232    class ScanModeState extends State {
6233        private int mLastOperationMode;
6234        @Override
6235        public void enter() {
6236            mLastOperationMode = mOperationalMode;
6237        }
6238        @Override
6239        public boolean processMessage(Message message) {
6240            logStateAndMessage(message, this);
6241
6242            switch(message.what) {
6243                case CMD_SET_OPERATIONAL_MODE:
6244                    if (message.arg1 == CONNECT_MODE) {
6245
6246                        if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
6247                            setWifiState(WIFI_STATE_ENABLED);
6248                            // Load and re-enable networks when going back to enabled state
6249                            // This is essential for networks to show up after restore
6250                            mWifiConfigManager.loadAndEnableAllNetworks();
6251                            mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
6252                        } else {
6253                            mWifiConfigManager.enableAllNetworks();
6254                        }
6255                        // start a scan to trigger Quality network selection
6256                        startScan(ENABLE_WIFI, 0, null, null);
6257
6258                        // Loose last selection choice since user toggled WiFi
6259                        mWifiConfigManager.
6260                                setAndEnableLastSelectedConfiguration(
6261                                        WifiConfiguration.INVALID_NETWORK_ID);
6262
6263                        mOperationalMode = CONNECT_MODE;
6264                        transitionTo(mDisconnectedState);
6265                    } else {
6266                        // Nothing to do
6267                        return HANDLED;
6268                    }
6269                    break;
6270                // Handle scan. All the connection related commands are
6271                // handled only in ConnectModeState
6272                case CMD_START_SCAN:
6273                    handleScanRequest(message);
6274                    break;
6275                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6276                    SupplicantState state = handleSupplicantStateChange(message);
6277                    if(DBG) log("SupplicantState= " + state);
6278                    break;
6279                default:
6280                    return NOT_HANDLED;
6281            }
6282            return HANDLED;
6283        }
6284    }
6285
6286
6287    String smToString(Message message) {
6288        return smToString(message.what);
6289    }
6290
6291    String smToString(int what) {
6292        String s = sSmToString.get(what);
6293        if (s != null) {
6294            return s;
6295        }
6296        switch (what) {
6297            case WifiMonitor.DRIVER_HUNG_EVENT:
6298                s = "DRIVER_HUNG_EVENT";
6299                break;
6300            case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
6301                s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED";
6302                break;
6303            case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
6304                s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED";
6305                break;
6306            case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
6307                s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST";
6308                break;
6309            case WifiManager.DISABLE_NETWORK:
6310                s = "WifiManager.DISABLE_NETWORK";
6311                break;
6312            case WifiManager.CONNECT_NETWORK:
6313                s = "CONNECT_NETWORK";
6314                break;
6315            case WifiManager.SAVE_NETWORK:
6316                s = "SAVE_NETWORK";
6317                break;
6318            case WifiManager.FORGET_NETWORK:
6319                s = "FORGET_NETWORK";
6320                break;
6321            case WifiMonitor.SUP_CONNECTION_EVENT:
6322                s = "SUP_CONNECTION_EVENT";
6323                break;
6324            case WifiMonitor.SUP_DISCONNECTION_EVENT:
6325                s = "SUP_DISCONNECTION_EVENT";
6326                break;
6327            case WifiMonitor.SCAN_RESULTS_EVENT:
6328                s = "SCAN_RESULTS_EVENT";
6329                break;
6330            case WifiMonitor.SCAN_FAILED_EVENT:
6331                s = "SCAN_FAILED_EVENT";
6332                break;
6333            case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6334                s = "SUPPLICANT_STATE_CHANGE_EVENT";
6335                break;
6336            case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
6337                s = "AUTHENTICATION_FAILURE_EVENT";
6338                break;
6339            case WifiMonitor.SSID_TEMP_DISABLED:
6340                s = "SSID_TEMP_DISABLED";
6341                break;
6342            case WifiMonitor.SSID_REENABLED:
6343                s = "SSID_REENABLED";
6344                break;
6345            case WifiMonitor.WPS_SUCCESS_EVENT:
6346                s = "WPS_SUCCESS_EVENT";
6347                break;
6348            case WifiMonitor.WPS_FAIL_EVENT:
6349                s = "WPS_FAIL_EVENT";
6350                break;
6351            case WifiMonitor.SUP_REQUEST_IDENTITY:
6352                s = "SUP_REQUEST_IDENTITY";
6353                break;
6354            case WifiMonitor.NETWORK_CONNECTION_EVENT:
6355                s = "NETWORK_CONNECTION_EVENT";
6356                break;
6357            case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
6358                s = "NETWORK_DISCONNECTION_EVENT";
6359                break;
6360            case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
6361                s = "ASSOCIATION_REJECTION_EVENT";
6362                break;
6363            case WifiMonitor.ANQP_DONE_EVENT:
6364                s = "WifiMonitor.ANQP_DONE_EVENT";
6365                break;
6366            case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
6367                s = "WifiMonitor.RX_HS20_ANQP_ICON_EVENT";
6368                break;
6369            case WifiMonitor.GAS_QUERY_DONE_EVENT:
6370                s = "WifiMonitor.GAS_QUERY_DONE_EVENT";
6371                break;
6372            case WifiMonitor.HS20_REMEDIATION_EVENT:
6373                s = "WifiMonitor.HS20_REMEDIATION_EVENT";
6374                break;
6375            case WifiMonitor.GAS_QUERY_START_EVENT:
6376                s = "WifiMonitor.GAS_QUERY_START_EVENT";
6377                break;
6378            case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT:
6379                s = "GROUP_CREATING_TIMED_OUT";
6380                break;
6381            case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
6382                s = "P2P_CONNECTION_CHANGED";
6383                break;
6384            case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE:
6385                s = "P2P.DISCONNECT_WIFI_RESPONSE";
6386                break;
6387            case WifiP2pServiceImpl.SET_MIRACAST_MODE:
6388                s = "P2P.SET_MIRACAST_MODE";
6389                break;
6390            case WifiP2pServiceImpl.BLOCK_DISCOVERY:
6391                s = "P2P.BLOCK_DISCOVERY";
6392                break;
6393            case WifiP2pServiceImpl.SET_COUNTRY_CODE:
6394                s = "P2P.SET_COUNTRY_CODE";
6395                break;
6396            case WifiManager.CANCEL_WPS:
6397                s = "CANCEL_WPS";
6398                break;
6399            case WifiManager.CANCEL_WPS_FAILED:
6400                s = "CANCEL_WPS_FAILED";
6401                break;
6402            case WifiManager.CANCEL_WPS_SUCCEDED:
6403                s = "CANCEL_WPS_SUCCEDED";
6404                break;
6405            case WifiManager.START_WPS:
6406                s = "START_WPS";
6407                break;
6408            case WifiManager.START_WPS_SUCCEEDED:
6409                s = "START_WPS_SUCCEEDED";
6410                break;
6411            case WifiManager.WPS_FAILED:
6412                s = "WPS_FAILED";
6413                break;
6414            case WifiManager.WPS_COMPLETED:
6415                s = "WPS_COMPLETED";
6416                break;
6417            case WifiManager.RSSI_PKTCNT_FETCH:
6418                s = "RSSI_PKTCNT_FETCH";
6419                break;
6420            default:
6421                s = "what:" + Integer.toString(what);
6422                break;
6423        }
6424        return s;
6425    }
6426
6427    void registerConnected() {
6428        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6429            WifiConfiguration config = mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
6430            if (config != null) {
6431                //Here we will clear all disable counters once a network is connected
6432                //records how long this network is connected in future
6433                config.lastConnected = System.currentTimeMillis();
6434                config.getNetworkSelectionStatus().clearDisableReasonCounter();
6435                config.numAssociation++;
6436            }
6437            mBadLinkspeedcount = 0;
6438       }
6439    }
6440
6441    void registerDisconnected() {
6442        if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6443            long now_ms = System.currentTimeMillis();
6444            // We are switching away from this configuration,
6445            // hence record the time we were connected last
6446            WifiConfiguration config = mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
6447            if (config != null) {
6448                config.lastDisconnected = System.currentTimeMillis();
6449                if (config.ephemeral) {
6450                    // Remove ephemeral WifiConfigurations from file
6451                    mWifiConfigManager.forgetNetwork(mLastNetworkId);
6452                }
6453            }
6454        }
6455    }
6456
6457    void noteWifiDisabledWhileAssociated() {
6458        // We got disabled by user while we were associated, make note of it
6459        int rssi = mWifiInfo.getRssi();
6460        WifiConfiguration config = getCurrentWifiConfiguration();
6461        if (getCurrentState() == mConnectedState
6462                && rssi != WifiInfo.INVALID_RSSI
6463                && config != null) {
6464            boolean is24GHz = mWifiInfo.is24GHz();
6465            boolean isBadRSSI = (is24GHz && rssi < mWifiConfigManager.thresholdMinimumRssi24.get())
6466                    || (!is24GHz && rssi < mWifiConfigManager.thresholdMinimumRssi5.get());
6467            boolean isLowRSSI =
6468                    (is24GHz && rssi < mWifiConfigManager.thresholdQualifiedRssi24.get())
6469                            || (!is24GHz && mWifiInfo.getRssi() <
6470                                    mWifiConfigManager.thresholdQualifiedRssi5.get());
6471            boolean isHighRSSI = (is24GHz && rssi
6472                    >= mWifiConfigManager.thresholdSaturatedRssi24.get())
6473                    || (!is24GHz && mWifiInfo.getRssi()
6474                    >= mWifiConfigManager.thresholdSaturatedRssi5.get());
6475            if (isBadRSSI) {
6476                // Take note that we got disabled while RSSI was Bad
6477                config.numUserTriggeredWifiDisableLowRSSI++;
6478            } else if (isLowRSSI) {
6479                // Take note that we got disabled while RSSI was Low
6480                config.numUserTriggeredWifiDisableBadRSSI++;
6481            } else if (!isHighRSSI) {
6482                // Take note that we got disabled while RSSI was Not high
6483                config.numUserTriggeredWifiDisableNotHighRSSI++;
6484            }
6485        }
6486    }
6487
6488    WifiConfiguration getCurrentWifiConfiguration() {
6489        if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) {
6490            return null;
6491        }
6492        return mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
6493    }
6494
6495    ScanResult getCurrentScanResult() {
6496        WifiConfiguration config = getCurrentWifiConfiguration();
6497        if (config == null) {
6498            return null;
6499        }
6500        String BSSID = mWifiInfo.getBSSID();
6501        if (BSSID == null) {
6502            BSSID = mTargetRoamBSSID;
6503        }
6504        ScanDetailCache scanDetailCache =
6505                mWifiConfigManager.getScanDetailCache(config);
6506
6507        if (scanDetailCache == null) {
6508            return null;
6509        }
6510
6511        return scanDetailCache.get(BSSID);
6512    }
6513
6514    String getCurrentBSSID() {
6515        if (linkDebouncing) {
6516            return null;
6517        }
6518        return mLastBssid;
6519    }
6520
6521    class ConnectModeState extends State {
6522
6523        @Override
6524        public void enter() {
6525            connectScanningService();
6526        }
6527
6528        @Override
6529        public boolean processMessage(Message message) {
6530            WifiConfiguration config;
6531            int netId;
6532            boolean ok;
6533            boolean didDisconnect;
6534            String bssid;
6535            String ssid;
6536            NetworkUpdateResult result;
6537            logStateAndMessage(message, this);
6538
6539            switch (message.what) {
6540                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
6541                    mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_ASSOC_FAILURE);
6542                    didBlackListBSSID = false;
6543                    bssid = (String) message.obj;
6544                    if (bssid == null || TextUtils.isEmpty(bssid)) {
6545                        // If BSSID is null, use the target roam BSSID
6546                        bssid = mTargetRoamBSSID;
6547                    }
6548                    if (bssid != null) {
6549                        // If we have a BSSID, tell configStore to black list it
6550                        synchronized(mScanResultCache) {
6551                            didBlackListBSSID = mWifiQualifiedNetworkSelector
6552                                    .enableBssidForQualityNetworkSelection(bssid, false);
6553                        }
6554                    }
6555
6556                    mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
6557                            WifiConfiguration.NetworkSelectionStatus
6558                            .DISABLED_ASSOCIATION_REJECTION);
6559
6560                    mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
6561                    //If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
6562                    mWifiMetrics.endConnectionEvent(
6563                            WifiMetrics.ConnectionEvent.LLF_ASSOCIATION_REJECTION,
6564                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6565                    break;
6566                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
6567                    mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTH_FAILURE);
6568                    mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
6569                    if (mTargetNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
6570                        mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
6571                                WifiConfiguration.NetworkSelectionStatus
6572                                        .DISABLED_AUTHENTICATION_FAILURE);
6573                    }
6574                    //If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
6575                    mWifiMetrics.endConnectionEvent(
6576                            WifiMetrics.ConnectionEvent.LLF_AUTHENTICATION_FAILURE,
6577                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6578                    break;
6579                case WifiMonitor.SSID_TEMP_DISABLED:
6580                    Log.e(TAG, "Supplicant SSID temporary disabled:"
6581                            + mWifiConfigManager.getWifiConfiguration(message.arg1));
6582                    mWifiConfigManager.updateNetworkSelectionStatus(
6583                            message.arg1,
6584                            WifiConfiguration.NetworkSelectionStatus
6585                            .DISABLED_AUTHENTICATION_FAILURE);
6586                    mWifiMetrics.endConnectionEvent(
6587                            WifiMetrics.ConnectionEvent.LLF_SSID_TEMP_DISABLED,
6588                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
6589                    break;
6590                case WifiMonitor.SSID_REENABLED:
6591                    Log.d(TAG, "Supplicant SSID reenable:"
6592                            + mWifiConfigManager.getWifiConfiguration(message.arg1));
6593                    // Do not re-enable it in Quality Network Selection since framework has its own
6594                    // Algorithm of disable/enable
6595                    break;
6596                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
6597                    SupplicantState state = handleSupplicantStateChange(message);
6598                    // A driver/firmware hang can now put the interface in a down state.
6599                    // We detect the interface going down and recover from it
6600                    if (!SupplicantState.isDriverActive(state)) {
6601                        if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
6602                            handleNetworkDisconnect();
6603                        }
6604                        log("Detected an interface down, restart driver");
6605                        transitionTo(mDriverStoppedState);
6606                        sendMessage(CMD_START_DRIVER);
6607                        break;
6608                    }
6609
6610                    // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT
6611                    // when authentication times out after a successful connection,
6612                    // we can figure this from the supplicant state. If supplicant
6613                    // state is DISCONNECTED, but the mNetworkInfo says we are not
6614                    // disconnected, we need to handle a disconnection
6615                    if (!linkDebouncing && state == SupplicantState.DISCONNECTED &&
6616                            mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
6617                        if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
6618                        handleNetworkDisconnect();
6619                        transitionTo(mDisconnectedState);
6620                    }
6621
6622                    // If we have COMPLETED a connection to a BSSID, start doing
6623                    // DNAv4/DNAv6 -style probing for on-link neighbors of
6624                    // interest (e.g. routers); harmless if none are configured.
6625                    if (state == SupplicantState.COMPLETED) {
6626                        mIpManager.confirmConfiguration();
6627                    }
6628                    break;
6629                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
6630                    if (message.arg1 == 1) {
6631                        mWifiNative.disconnect();
6632                        mTemporarilyDisconnectWifi = true;
6633                    } else {
6634                        mWifiNative.reconnect();
6635                        mTemporarilyDisconnectWifi = false;
6636                    }
6637                    break;
6638                case CMD_ADD_OR_UPDATE_NETWORK:
6639                    // Only the current foreground user can modify networks.
6640                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
6641                        loge("Only the current foreground user can modify networks "
6642                                + " currentUserId=" + mCurrentUserId
6643                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6644                        replyToMessage(message, message.what, FAILURE);
6645                        break;
6646                    }
6647
6648                    config = (WifiConfiguration) message.obj;
6649
6650                    if (!recordUidIfAuthorized(config, message.sendingUid,
6651                            /* onlyAnnotate */ false)) {
6652                        logw("Not authorized to update network "
6653                             + " config=" + config.SSID
6654                             + " cnid=" + config.networkId
6655                             + " uid=" + message.sendingUid);
6656                        replyToMessage(message, message.what, FAILURE);
6657                        break;
6658                    }
6659
6660                    int res = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
6661                    if (res < 0) {
6662                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6663                    } else {
6664                        WifiConfiguration curConfig = getCurrentWifiConfiguration();
6665                        if (curConfig != null && config != null) {
6666                            if (curConfig.priority < config.priority
6667                                    && config.status == WifiConfiguration.Status.ENABLED) {
6668                                // Interpret this as a connect attempt
6669                                // Set the last selected configuration so as to allow the system to
6670                                // stick the last user choice without persisting the choice
6671                                mWifiConfigManager.setAndEnableLastSelectedConfiguration(res);
6672                                mWifiConfigManager.updateLastConnectUid(config, message.sendingUid);
6673                                boolean persist = mWifiConfigManager
6674                                        .checkConfigOverridePermission(message.sendingUid);
6675                                mWifiQualifiedNetworkSelector
6676                                        .userSelectNetwork(res, persist);
6677
6678                                // Remember time of last connection attempt
6679                                lastConnectAttemptTimestamp = System.currentTimeMillis();
6680                                mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
6681
6682                                // As a courtesy to the caller, trigger a scan now
6683                                startScan(ADD_OR_UPDATE_SOURCE, 0, null, null);
6684                            }
6685                        }
6686                    }
6687                    replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res);
6688                    break;
6689                case CMD_REMOVE_NETWORK:
6690                    // Only the current foreground user can modify networks.
6691                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
6692                        loge("Only the current foreground user can modify networks "
6693                                + " currentUserId=" + mCurrentUserId
6694                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6695                        replyToMessage(message, message.what, FAILURE);
6696                        break;
6697                    }
6698                    netId = message.arg1;
6699
6700                    if (!mWifiConfigManager.canModifyNetwork(message.sendingUid, netId,
6701                            /* onlyAnnotate */ false)) {
6702                        logw("Not authorized to remove network "
6703                             + " cnid=" + netId
6704                             + " uid=" + message.sendingUid);
6705                        replyToMessage(message, message.what, FAILURE);
6706                        break;
6707                    }
6708
6709                    ok = mWifiConfigManager.removeNetwork(message.arg1);
6710                    if (!ok) {
6711                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6712                    }
6713                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
6714                    break;
6715                case CMD_ENABLE_NETWORK:
6716                    // Only the current foreground user can modify networks.
6717                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
6718                        loge("Only the current foreground user can modify networks "
6719                                + " currentUserId=" + mCurrentUserId
6720                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
6721                        replyToMessage(message, message.what, FAILURE);
6722                        break;
6723                    }
6724
6725                    boolean disableOthers = message.arg2 == 1;
6726                    netId = message.arg1;
6727                    config = mWifiConfigManager.getWifiConfiguration(netId);
6728                    if (config == null) {
6729                        loge("No network with id = " + netId);
6730                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6731                        replyToMessage(message, message.what, FAILURE);
6732                        break;
6733                    }
6734
6735                    // disable other only means select this network, does not mean all other
6736                    // networks need to be disabled
6737                    if (disableOthers) {
6738                        mWifiQualifiedNetworkSelector.enableNetworkByUser(config);
6739                        // Remember time of last connection attempt
6740                        lastConnectAttemptTimestamp = System.currentTimeMillis();
6741                        mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
6742                    }
6743                    // Cancel auto roam requests
6744                    autoRoamSetBSSID(netId, "any");
6745
6746                    int uid = message.sendingUid;
6747                    mWifiQualifiedNetworkSelector.enableNetworkByUser(config);
6748                    ok = mWifiConfigManager.enableNetwork(netId, disableOthers, uid);
6749                    if (!ok) {
6750                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6751                    } else if (disableOthers) {
6752                        mTargetNetworkId = netId;
6753                    }
6754
6755                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
6756                    break;
6757                case CMD_ENABLE_ALL_NETWORKS:
6758                    long time = android.os.SystemClock.elapsedRealtime();
6759                    if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
6760                        mWifiConfigManager.enableAllNetworks();
6761                        mLastEnableAllNetworksTime = time;
6762                    }
6763                    break;
6764                case WifiManager.DISABLE_NETWORK:
6765                    if (mWifiConfigManager.updateNetworkSelectionStatus(message.arg1,
6766                            WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER)) {
6767                        replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
6768                    } else {
6769                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
6770                        replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
6771                                WifiManager.ERROR);
6772                    }
6773                    break;
6774                case CMD_DISABLE_EPHEMERAL_NETWORK:
6775                    config = mWifiConfigManager.disableEphemeralNetwork((String)message.obj);
6776                    if (config != null) {
6777                        if (config.networkId == mLastNetworkId) {
6778                            // Disconnect and let autojoin reselect a new network
6779                            sendMessage(CMD_DISCONNECT);
6780                        }
6781                    }
6782                    break;
6783                case CMD_BLACKLIST_NETWORK:
6784                    mWifiConfigManager.blackListBssid((String) message.obj);
6785                    break;
6786                case CMD_CLEAR_BLACKLIST:
6787                    mWifiConfigManager.clearBssidBlacklist();
6788                    break;
6789                case CMD_SAVE_CONFIG:
6790                    ok = mWifiConfigManager.saveConfig();
6791
6792                    if (DBG) logd("did save config " + ok);
6793                    replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
6794
6795                    // Inform the backup manager about a data change
6796                    IBackupManager ibm = IBackupManager.Stub.asInterface(
6797                            mFacade.getService(Context.BACKUP_SERVICE));
6798                    if (ibm != null) {
6799                        try {
6800                            ibm.dataChanged("com.android.providers.settings");
6801                        } catch (Exception e) {
6802                            // Try again later
6803                        }
6804                    }
6805                    break;
6806                case CMD_GET_CONFIGURED_NETWORKS:
6807                    replyToMessage(message, message.what,
6808                            mWifiConfigManager.getConfiguredNetworks());
6809                    break;
6810                case WifiMonitor.SUP_REQUEST_IDENTITY:
6811                    int networkId = message.arg2;
6812                    boolean identitySent = false;
6813                    int eapMethod = WifiEnterpriseConfig.Eap.NONE;
6814
6815                    if (targetWificonfiguration != null
6816                            && targetWificonfiguration.enterpriseConfig != null) {
6817                        eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod();
6818                    }
6819
6820                    // For SIM & AKA/AKA' EAP method Only, get identity from ICC
6821                    if (targetWificonfiguration != null
6822                            && targetWificonfiguration.networkId == networkId
6823                            && targetWificonfiguration.allowedKeyManagement
6824                                    .get(WifiConfiguration.KeyMgmt.IEEE8021X)
6825                            &&  (eapMethod == WifiEnterpriseConfig.Eap.SIM
6826                            || eapMethod == WifiEnterpriseConfig.Eap.AKA
6827                            || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)) {
6828                        TelephonyManager tm = (TelephonyManager)
6829                                mContext.getSystemService(Context.TELEPHONY_SERVICE);
6830                        if (tm != null) {
6831                            String imsi = tm.getSubscriberId();
6832                            String mccMnc = "";
6833
6834                            if (tm.getSimState() == TelephonyManager.SIM_STATE_READY)
6835                                 mccMnc = tm.getSimOperator();
6836
6837                            String identity = buildIdentity(eapMethod, imsi, mccMnc);
6838
6839                            if (!identity.isEmpty()) {
6840                                mWifiNative.simIdentityResponse(networkId, identity);
6841                                identitySent = true;
6842                            }
6843                        }
6844                    }
6845                    if (!identitySent) {
6846                        // Supplicant lacks credentials to connect to that network, hence black list
6847                        ssid = (String) message.obj;
6848                        if (targetWificonfiguration != null && ssid != null
6849                                && targetWificonfiguration.SSID != null
6850                                && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
6851                            mWifiConfigManager.updateNetworkSelectionStatus(targetWificonfiguration,
6852                                    WifiConfiguration.NetworkSelectionStatus
6853                                            .DISABLED_AUTHENTICATION_NO_CREDENTIALS);
6854                        }
6855                        // Disconnect now, as we don't have any way to fullfill
6856                        // the  supplicant request.
6857                        mWifiConfigManager.setAndEnableLastSelectedConfiguration(
6858                                WifiConfiguration.INVALID_NETWORK_ID);
6859                        mWifiNative.disconnect();
6860                    }
6861                    break;
6862                case WifiMonitor.SUP_REQUEST_SIM_AUTH:
6863                    logd("Received SUP_REQUEST_SIM_AUTH");
6864                    SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
6865                    if (requestData != null) {
6866                        if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
6867                            handleGsmAuthRequest(requestData);
6868                        } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
6869                            || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
6870                            handle3GAuthRequest(requestData);
6871                        }
6872                    } else {
6873                        loge("Invalid sim auth request");
6874                    }
6875                    break;
6876                case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS:
6877                    replyToMessage(message, message.what,
6878                            mWifiConfigManager.getPrivilegedConfiguredNetworks());
6879                    break;
6880                case CMD_GET_MATCHING_CONFIG:
6881                    replyToMessage(message, message.what,
6882                            mWifiConfigManager.getMatchingConfig((ScanResult)message.obj));
6883                    break;
6884                /* Do a redundant disconnect without transition */
6885                case CMD_DISCONNECT:
6886                    mWifiConfigManager.setAndEnableLastSelectedConfiguration
6887                            (WifiConfiguration.INVALID_NETWORK_ID);
6888                    mWifiNative.disconnect();
6889                    break;
6890                case CMD_RECONNECT:
6891                    WifiConfiguration candidate =
6892                            mWifiQualifiedNetworkSelector.selectQualifiedNetwork(true,
6893                            mAllowUntrustedConnections, mScanResults, linkDebouncing,
6894                            isConnected(), isDisconnected(), isSupplicantTransientState());
6895                    tryToConnectToNetwork(candidate);
6896                    break;
6897                case CMD_REASSOCIATE:
6898                    lastConnectAttemptTimestamp = System.currentTimeMillis();
6899                    mWifiNative.reassociate();
6900                    break;
6901                case CMD_RELOAD_TLS_AND_RECONNECT:
6902                    if (mWifiConfigManager.needsUnlockedKeyStore()) {
6903                        logd("Reconnecting to give a chance to un-connected TLS networks");
6904                        mWifiNative.disconnect();
6905                        lastConnectAttemptTimestamp = System.currentTimeMillis();
6906                        mWifiNative.reconnect();
6907                    }
6908                    break;
6909                case CMD_AUTO_ROAM:
6910                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
6911                    return HANDLED;
6912                case CMD_AUTO_CONNECT:
6913                    /* Work Around: wpa_supplicant can get in a bad state where it returns a non
6914                     * associated status to the STATUS command but somehow-someplace still thinks
6915                     * it is associated and thus will ignore select/reconnect command with
6916                     * following message:
6917                     * "Already associated with the selected network - do nothing"
6918                     *
6919                     * Hence, sends a disconnect to supplicant first.
6920                     */
6921                    didDisconnect = false;
6922                    if (getCurrentState() != mDisconnectedState) {
6923                        /** Supplicant will ignore the reconnect if we are currently associated,
6924                         * hence trigger a disconnect
6925                         */
6926                        didDisconnect = true;
6927                        mWifiNative.disconnect();
6928                    }
6929
6930                    /* connect command coming from auto-join */
6931                    netId = message.arg1;
6932                    mTargetNetworkId = netId;
6933                    mTargetRoamBSSID = (String) message.obj;
6934                    config = mWifiConfigManager.getWifiConfiguration(netId);
6935                    logd("CMD_AUTO_CONNECT sup state "
6936                            + mSupplicantStateTracker.getSupplicantStateName()
6937                            + " my state " + getCurrentState().getName()
6938                            + " nid=" + Integer.toString(netId)
6939                            + " roam=" + Boolean.toString(mAutoRoaming));
6940                    if (config == null) {
6941                        loge("AUTO_CONNECT and no config, bail out...");
6942                        break;
6943                    }
6944
6945                    /* Make sure we cancel any previous roam request */
6946                    setTargetBssid(config, mTargetRoamBSSID);
6947
6948                    /* Save the network config */
6949                    logd("CMD_AUTO_CONNECT will save config -> " + config.SSID
6950                            + " nid=" + Integer.toString(netId));
6951                    result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
6952                    netId = result.getNetworkId();
6953                    logd("CMD_AUTO_CONNECT did save config -> "
6954                            + " nid=" + Integer.toString(netId));
6955
6956                    // Since we updated the config,read it back from config store:
6957                    config = mWifiConfigManager.getWifiConfiguration(netId);
6958                    if (config == null) {
6959                        loge("CMD_AUTO_CONNECT couldn't update the config, got null config");
6960                        break;
6961                    }
6962                    if (netId != config.networkId) {
6963                        loge("CMD_AUTO_CONNECT couldn't update the config, want"
6964                                + " nid=" + Integer.toString(netId) + " but got" + config.networkId);
6965                        break;
6966                    }
6967
6968                    if (deferForUserInput(message, netId, false)) {
6969                        break;
6970                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
6971                                                                   WifiConfiguration.USER_BANNED) {
6972                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
6973                                WifiManager.NOT_AUTHORIZED);
6974                        break;
6975                    }
6976
6977                    // Make sure the network is enabled, since supplicant will not reenable it
6978                    mWifiConfigManager.enableNetworkWithoutBroadcast(netId, false);
6979
6980                    // If we're autojoining a network that the user or an app explicitly selected,
6981                    // keep track of the UID that selected it.
6982                    // TODO(b/26786318): Keep track of the lastSelectedConfiguration and the
6983                    // lastConnectUid on a per-user basis.
6984                    int lastConnectUid = WifiConfiguration.UNKNOWN_UID;
6985                    mWifiMetrics.startConnectionEvent(mWifiInfo, config,
6986                            WifiMetricsProto.ConnectionEvent.ROAM_NONE);
6987                    if (mWifiConfigManager.isLastSelectedConfiguration(config)
6988                            && isCurrentUserProfile(UserHandle.getUserId(config.lastConnectUid))) {
6989                        lastConnectUid = config.lastConnectUid;
6990                        mWifiMetrics.setConnectionEventRoamType(
6991                                WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED);
6992                    }
6993                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
6994                            lastConnectUid) && mWifiNative.reconnect()) {
6995                        lastConnectAttemptTimestamp = System.currentTimeMillis();
6996                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
6997                        config = mWifiConfigManager.getWifiConfiguration(netId);
6998                        if (config != null
6999                                && !mWifiConfigManager.isLastSelectedConfiguration(config)) {
7000                            // If we autojoined a different config than the user selected one,
7001                            // it means we could not see the last user selection,
7002                            // or that the last user selection was faulty and ended up blacklisted
7003                            // for some reason (in which case the user is notified with an error
7004                            // message in the Wifi picker), and thus we managed to auto-join away
7005                            // from the selected  config. -> in that case we need to forget
7006                            // the selection because we don't want to abruptly switch back to it.
7007                            //
7008                            // Note that the user selection is also forgotten after a period of time
7009                            // during which the device has been disconnected.
7010                            // The default value is 30 minutes : see the code path at bottom of
7011                            // setScanResults() function.
7012                            mWifiConfigManager.
7013                                 setAndEnableLastSelectedConfiguration(
7014                                         WifiConfiguration.INVALID_NETWORK_ID);
7015                        }
7016                        mAutoRoaming = false;
7017                        if (isRoaming() || linkDebouncing) {
7018                            transitionTo(mRoamingState);
7019                        } else if (didDisconnect) {
7020                            transitionTo(mDisconnectingState);
7021                        } else {
7022                            /* Already in disconnected state, nothing to change */
7023                            if (!mScreenOn && mLegacyPnoEnabled && mBackgroundScanSupported) {
7024                                int delay = 60 * 1000;
7025                                if (VDBG) {
7026                                    logd("Starting PNO alarm: " + delay);
7027                                }
7028                                mAlarmManager.set(AlarmManager.RTC_WAKEUP,
7029                                       System.currentTimeMillis() + delay,
7030                                       mPnoIntent);
7031                            }
7032                            mRestartAutoJoinOffloadCounter++;
7033                        }
7034                    } else {
7035                        loge("Failed to connect config: " + config + " netId: " + netId);
7036                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7037                                WifiManager.ERROR);
7038                        mWifiMetrics.endConnectionEvent(
7039                                WifiMetrics.ConnectionEvent.LLF_CONNECT_NETWORK_FAILED,
7040                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
7041                        break;
7042                    }
7043                    break;
7044                case CMD_REMOVE_APP_CONFIGURATIONS:
7045                    mWifiConfigManager.removeNetworksForApp((ApplicationInfo) message.obj);
7046                    break;
7047                case CMD_REMOVE_USER_CONFIGURATIONS:
7048                    mWifiConfigManager.removeNetworksForUser(message.arg1);
7049                    break;
7050                case WifiManager.CONNECT_NETWORK:
7051                    // Only the current foreground user can modify networks.
7052                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
7053                        loge("Only the current foreground user can modify networks "
7054                                + " currentUserId=" + mCurrentUserId
7055                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
7056                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7057                                       WifiManager.NOT_AUTHORIZED);
7058                        break;
7059                    }
7060
7061                    /**
7062                     *  The connect message can contain a network id passed as arg1 on message or
7063                     * or a config passed as obj on message.
7064                     * For a new network, a config is passed to create and connect.
7065                     * For an existing network, a network id is passed
7066                     */
7067                    netId = message.arg1;
7068                    config = (WifiConfiguration) message.obj;
7069                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
7070                    boolean updatedExisting = false;
7071
7072                    /* Save the network config */
7073                    if (config != null) {
7074                        // When connecting to an access point, WifiStateMachine wants to update the
7075                        // relevant config with administrative data. This update should not be
7076                        // considered a 'real' update, therefore lockdown by Device Owner must be
7077                        // disregarded.
7078                        if (!recordUidIfAuthorized(config, message.sendingUid,
7079                                /* onlyAnnotate */ true)) {
7080                            logw("Not authorized to update network "
7081                                 + " config=" + config.SSID
7082                                 + " cnid=" + config.networkId
7083                                 + " uid=" + message.sendingUid);
7084                            replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7085                                           WifiManager.NOT_AUTHORIZED);
7086                            break;
7087                        }
7088
7089                        String configKey = config.configKey(true /* allowCached */);
7090                        WifiConfiguration savedConfig =
7091                                mWifiConfigManager.getWifiConfiguration(configKey);
7092                        if (savedConfig != null) {
7093                            // There is an existing config with this netId, but it wasn't exposed
7094                            // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigManager#
7095                            // getConfiguredNetworks). Remove those bits and update the config.
7096                            config = savedConfig;
7097                            logd("CONNECT_NETWORK updating existing config with id=" +
7098                                    config.networkId + " configKey=" + configKey);
7099                            config.ephemeral = false;
7100                            mWifiConfigManager.updateNetworkSelectionStatus(config,
7101                                    WifiConfiguration.NetworkSelectionStatus
7102                                    .NETWORK_SELECTION_ENABLE);
7103                            updatedExisting = true;
7104                        }
7105
7106                        result = mWifiConfigManager.saveNetwork(config, message.sendingUid);
7107                        netId = result.getNetworkId();
7108                    }
7109                    config = mWifiConfigManager.getWifiConfiguration(netId);
7110
7111                    if (config == null) {
7112                        logd("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " "
7113                                + mSupplicantStateTracker.getSupplicantStateName() + " my state "
7114                                + getCurrentState().getName());
7115                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7116                                WifiManager.ERROR);
7117                        break;
7118                    }
7119                    mTargetNetworkId = netId;
7120                    autoRoamSetBSSID(netId, "any");
7121
7122                    if (message.sendingUid == Process.WIFI_UID
7123                        || message.sendingUid == Process.SYSTEM_UID) {
7124                        // As a sanity measure, clear the BSSID in the supplicant network block.
7125                        // If system or Wifi Settings want to connect, they will not
7126                        // specify the BSSID.
7127                        // If an app however had added a BSSID to this configuration, and the BSSID
7128                        // was wrong, Then we would forever fail to connect until that BSSID
7129                        // is cleaned up.
7130                        clearConfigBSSID(config, "CONNECT_NETWORK");
7131                    }
7132
7133                    if (deferForUserInput(message, netId, true)) {
7134                        break;
7135                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
7136                                                                    WifiConfiguration.USER_BANNED) {
7137                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7138                                WifiManager.NOT_AUTHORIZED);
7139                        break;
7140                    }
7141
7142                    mAutoRoaming = false;
7143
7144                    /* Tell network selection the user did try to connect to that network if from
7145                    settings */
7146                    boolean persist =
7147                        mWifiConfigManager.checkConfigOverridePermission(message.sendingUid);
7148
7149
7150                    mWifiConfigManager.setAndEnableLastSelectedConfiguration(netId);
7151                    mWifiQualifiedNetworkSelector.userSelectNetwork(netId, persist);
7152                    didDisconnect = false;
7153                    if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
7154                            && mLastNetworkId != netId) {
7155                        /** Supplicant will ignore the reconnect if we are currently associated,
7156                         * hence trigger a disconnect
7157                         */
7158                        didDisconnect = true;
7159                        mWifiNative.disconnect();
7160                    }
7161
7162                    // Make sure the network is enabled, since supplicant will not reenable it
7163                    mWifiConfigManager.enableNetworkWithoutBroadcast(netId, false);
7164
7165                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ true,
7166                            message.sendingUid) && mWifiNative.reconnect()) {
7167                        lastConnectAttemptTimestamp = System.currentTimeMillis();
7168                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
7169
7170                        /* The state tracker handles enabling networks upon completion/failure */
7171                        mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK);
7172                        replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
7173                        if (didDisconnect) {
7174                            /* Expect a disconnection from the old connection */
7175                            transitionTo(mDisconnectingState);
7176                        } else if (updatedExisting && getCurrentState() == mConnectedState &&
7177                                getCurrentWifiConfiguration().networkId == netId) {
7178                            // Update the current set of network capabilities, but stay in the
7179                            // current state.
7180                            updateCapabilities(config);
7181                        } else {
7182                            /**
7183                             * Directly go to disconnected state where we
7184                             * process the connection events from supplicant
7185                             */
7186                            transitionTo(mDisconnectedState);
7187                        }
7188                    } else {
7189                        loge("Failed to connect config: " + config + " netId: " + netId);
7190                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
7191                                WifiManager.ERROR);
7192                        break;
7193                    }
7194                    break;
7195                case WifiManager.SAVE_NETWORK:
7196                    mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
7197                    // Fall thru
7198                case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
7199                    // Only the current foreground user can modify networks.
7200                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
7201                        loge("Only the current foreground user can modify networks "
7202                                + " currentUserId=" + mCurrentUserId
7203                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
7204                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
7205                                WifiManager.NOT_AUTHORIZED);
7206                        break;
7207                    }
7208
7209                    lastSavedConfigurationAttempt = null; // Used for debug
7210                    config = (WifiConfiguration) message.obj;
7211                    if (config == null) {
7212                        loge("ERROR: SAVE_NETWORK with null configuration"
7213                                + mSupplicantStateTracker.getSupplicantStateName()
7214                                + " my state " + getCurrentState().getName());
7215                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7216                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
7217                                WifiManager.ERROR);
7218                        break;
7219                    }
7220                    lastSavedConfigurationAttempt = new WifiConfiguration(config);
7221                    int nid = config.networkId;
7222                    logd("SAVE_NETWORK id=" + Integer.toString(nid)
7223                                + " config=" + config.SSID
7224                                + " nid=" + config.networkId
7225                                + " supstate=" + mSupplicantStateTracker.getSupplicantStateName()
7226                                + " my state " + getCurrentState().getName());
7227
7228                    // Only record the uid if this is user initiated
7229                    boolean checkUid = (message.what == WifiManager.SAVE_NETWORK);
7230                    if (checkUid && !recordUidIfAuthorized(config, message.sendingUid,
7231                            /* onlyAnnotate */ false)) {
7232                        logw("Not authorized to update network "
7233                             + " config=" + config.SSID
7234                             + " cnid=" + config.networkId
7235                             + " uid=" + message.sendingUid);
7236                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
7237                                       WifiManager.NOT_AUTHORIZED);
7238                        break;
7239                    }
7240
7241                    result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
7242                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
7243                        if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
7244                            if (result.hasIpChanged()) {
7245                                // The currently connection configuration was changed
7246                                // We switched from DHCP to static or from static to DHCP, or the
7247                                // static IP address has changed.
7248                                log("Reconfiguring IP on connection");
7249                                // TODO: clear addresses and disable IPv6
7250                                // to simplify obtainingIpState.
7251                                transitionTo(mObtainingIpState);
7252                            }
7253                            if (result.hasProxyChanged()) {
7254                                log("Reconfiguring proxy on connection");
7255                                notifyLinkProperties();
7256                            }
7257                        }
7258                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
7259                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
7260
7261                        if (VDBG) {
7262                           logd("Success save network nid="
7263                                    + Integer.toString(result.getNetworkId()));
7264                        }
7265
7266                        synchronized(mScanResultCache) {
7267                            /**
7268                             * If the command comes from WifiManager, then
7269                             * tell autojoin the user did try to modify and save that network,
7270                             * and interpret the SAVE_NETWORK as a request to connect
7271                             */
7272                            boolean user = message.what == WifiManager.SAVE_NETWORK;
7273
7274                            // Did this connect come from settings
7275                            boolean persistConnect =
7276                                mWifiConfigManager.checkConfigOverridePermission(
7277                                        message.sendingUid);
7278
7279                            if (user) {
7280                                mWifiConfigManager.updateLastConnectUid(config, message.sendingUid);
7281                                mWifiConfigManager.writeKnownNetworkHistory();
7282                            }
7283                            //Fixme, CMD_AUTO_SAVE_NETWORK can be cleaned
7284                            mWifiQualifiedNetworkSelector.userSelectNetwork(
7285                                    result.getNetworkId(), persistConnect);
7286                            candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(true,
7287                                    mAllowUntrustedConnections, mScanResults, linkDebouncing,
7288                                    isConnected(), isDisconnected(), isSupplicantTransientState());
7289                            tryToConnectToNetwork(candidate);
7290                        }
7291                    } else {
7292                        loge("Failed to save network");
7293                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
7294                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
7295                                WifiManager.ERROR);
7296                    }
7297                    break;
7298                case WifiManager.FORGET_NETWORK:
7299                    // Only the current foreground user can modify networks.
7300                    if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) {
7301                        loge("Only the current foreground user can modify networks "
7302                                + " currentUserId=" + mCurrentUserId
7303                                + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
7304                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
7305                                WifiManager.NOT_AUTHORIZED);
7306                        break;
7307                    }
7308
7309                    // Debug only, remember last configuration that was forgotten
7310                    WifiConfiguration toRemove
7311                            = mWifiConfigManager.getWifiConfiguration(message.arg1);
7312                    if (toRemove == null) {
7313                        lastForgetConfigurationAttempt = null;
7314                    } else {
7315                        lastForgetConfigurationAttempt = new WifiConfiguration(toRemove);
7316                    }
7317                    // check that the caller owns this network
7318                    netId = message.arg1;
7319
7320                    if (!mWifiConfigManager.canModifyNetwork(message.sendingUid, netId,
7321                            /* onlyAnnotate */ false)) {
7322                        logw("Not authorized to forget network "
7323                             + " cnid=" + netId
7324                             + " uid=" + message.sendingUid);
7325                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
7326                                WifiManager.NOT_AUTHORIZED);
7327                        break;
7328                    }
7329
7330                    if (mWifiConfigManager.forgetNetwork(message.arg1)) {
7331                        replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
7332                        broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT,
7333                                (WifiConfiguration) message.obj);
7334                    } else {
7335                        loge("Failed to forget network");
7336                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
7337                                WifiManager.ERROR);
7338                    }
7339                    break;
7340                case WifiManager.START_WPS:
7341                    WpsInfo wpsInfo = (WpsInfo) message.obj;
7342                    WpsResult wpsResult;
7343                    switch (wpsInfo.setup) {
7344                        case WpsInfo.PBC:
7345                            wpsResult = mWifiConfigManager.startWpsPbc(wpsInfo);
7346                            break;
7347                        case WpsInfo.KEYPAD:
7348                            wpsResult = mWifiConfigManager.startWpsWithPinFromAccessPoint(wpsInfo);
7349                            break;
7350                        case WpsInfo.DISPLAY:
7351                            wpsResult = mWifiConfigManager.startWpsWithPinFromDevice(wpsInfo);
7352                            break;
7353                        default:
7354                            wpsResult = new WpsResult(Status.FAILURE);
7355                            loge("Invalid setup for WPS");
7356                            break;
7357                    }
7358                    mWifiConfigManager.setAndEnableLastSelectedConfiguration
7359                            (WifiConfiguration.INVALID_NETWORK_ID);
7360                    if (wpsResult.status == Status.SUCCESS) {
7361                        replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
7362                        transitionTo(mWpsRunningState);
7363                    } else {
7364                        loge("Failed to start WPS with config " + wpsInfo.toString());
7365                        replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
7366                    }
7367                    break;
7368                case WifiMonitor.NETWORK_CONNECTION_EVENT:
7369                    if (DBG) log("Network connection established");
7370                    mLastNetworkId = message.arg1;
7371                    mLastBssid = (String) message.obj;
7372
7373                    mWifiInfo.setBSSID(mLastBssid);
7374                    mWifiInfo.setNetworkId(mLastNetworkId);
7375                    mWifiQualifiedNetworkSelector
7376                            .enableBssidForQualityNetworkSelection(mLastBssid, true);
7377                    sendNetworkStateChangeBroadcast(mLastBssid);
7378                    transitionTo(mObtainingIpState);
7379                    break;
7380                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
7381                    // Calling handleNetworkDisconnect here is redundant because we might already
7382                    // have called it when leaving L2ConnectedState to go to disconnecting state
7383                    // or thru other path
7384                    // We should normally check the mWifiInfo or mLastNetworkId so as to check
7385                    // if they are valid, and only in this case call handleNEtworkDisconnect,
7386                    // TODO: this should be fixed for a L MR release
7387                    // The side effect of calling handleNetworkDisconnect twice is that a bunch of
7388                    // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
7389                    // at the chip etc...
7390                    if (DBG) log("ConnectModeState: Network connection lost ");
7391                    handleNetworkDisconnect();
7392                    transitionTo(mDisconnectedState);
7393                    break;
7394                case CMD_PNO_NETWORK_FOUND:
7395                    processPnoNetworkFound((ScanResult[]) message.obj);
7396                    break;
7397                case CMD_ADD_PASSPOINT_MO:
7398                    res = mWifiConfigManager.addPasspointManagementObject((String) message.obj);
7399                    replyToMessage(message, message.what, res);
7400                    break;
7401                case CMD_MODIFY_PASSPOINT_MO:
7402                    if (message.obj != null) {
7403                        Bundle bundle = (Bundle) message.obj;
7404                        ArrayList<PasspointManagementObjectDefinition> mos =
7405                                bundle.getParcelableArrayList("MOS");
7406                        res = mWifiConfigManager.modifyPasspointMo(bundle.getString("FQDN"), mos);
7407                    } else {
7408                        res = 0;
7409                    }
7410                    replyToMessage(message, message.what, res);
7411
7412                    break;
7413                case CMD_QUERY_OSU_ICON:
7414                    if (mWifiConfigManager.queryPasspointIcon(
7415                            ((Bundle) message.obj).getLong("BSSID"),
7416                            ((Bundle) message.obj).getString("FILENAME"))) {
7417                        res = 1;
7418                    } else {
7419                        res = 0;
7420                    }
7421                    replyToMessage(message, message.what, res);
7422                    break;
7423                case CMD_MATCH_PROVIDER_NETWORK:
7424                    res = mWifiConfigManager.matchProviderWithCurrentNetwork((String) message.obj);
7425                    replyToMessage(message, message.what, res);
7426                    break;
7427                default:
7428                    return NOT_HANDLED;
7429            }
7430            return HANDLED;
7431        }
7432    }
7433
7434    private void updateCapabilities(WifiConfiguration config) {
7435        NetworkCapabilities networkCapabilities = new NetworkCapabilities(mDfltNetworkCapabilities);
7436        if (config != null) {
7437            if (config.ephemeral) {
7438                networkCapabilities.removeCapability(
7439                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
7440            } else {
7441                networkCapabilities.addCapability(
7442                        NetworkCapabilities.NET_CAPABILITY_TRUSTED);
7443            }
7444            networkCapabilities.setSignalStrength(mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI ?
7445                    mWifiInfo.getRssi() : NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
7446        }
7447        mNetworkAgent.sendNetworkCapabilities(networkCapabilities);
7448    }
7449
7450    private class WifiNetworkAgent extends NetworkAgent {
7451        public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
7452                NetworkCapabilities nc, LinkProperties lp, int score) {
7453            super(l, c, TAG, ni, nc, lp, score);
7454        }
7455        protected void unwanted() {
7456            // Ignore if we're not the current networkAgent.
7457            if (this != mNetworkAgent) return;
7458            if (DBG) log("WifiNetworkAgent -> Wifi unwanted score "
7459                    + Integer.toString(mWifiInfo.score));
7460            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISCONNECT);
7461        }
7462
7463        @Override
7464        protected void networkStatus(int status) {
7465            if (this != mNetworkAgent) return;
7466            if (status == NetworkAgent.INVALID_NETWORK) {
7467                if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid, score="
7468                        + Integer.toString(mWifiInfo.score));
7469                unwantedNetwork(NETWORK_STATUS_UNWANTED_VALIDATION_FAILED);
7470            } else if (status == NetworkAgent.VALID_NETWORK) {
7471                if (DBG && mWifiInfo != null) log("WifiNetworkAgent -> Wifi networkStatus valid, score= "
7472                        + Integer.toString(mWifiInfo.score));
7473                doNetworkStatus(status);
7474            }
7475        }
7476
7477        @Override
7478        protected void saveAcceptUnvalidated(boolean accept) {
7479            if (this != mNetworkAgent) return;
7480            WifiStateMachine.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0);
7481        }
7482
7483        @Override
7484        protected void startPacketKeepalive(Message msg) {
7485            WifiStateMachine.this.sendMessage(
7486                    CMD_START_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
7487        }
7488
7489        @Override
7490        protected void stopPacketKeepalive(Message msg) {
7491            WifiStateMachine.this.sendMessage(
7492                    CMD_STOP_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
7493        }
7494
7495        @Override
7496        protected void setSignalStrengthThresholds(int[] thresholds) {
7497            // 0. If there are no thresholds, or if the thresholds are invalid, stop RSSI monitoring.
7498            // 1. Tell the hardware to start RSSI monitoring here, possibly adding MIN_VALUE and
7499            //    MAX_VALUE at the start/end of the thresholds array if necessary.
7500            // 2. Ensure that when the hardware event fires, we fetch the RSSI from the hardware
7501            //    event, call mWifiInfo.setRssi() with it, and call updateCapabilities(), and then
7502            //    re-arm the hardware event. This needs to be done on the state machine thread to
7503            //    avoid race conditions. The RSSI used to re-arm the event (and perhaps also the one
7504            //    sent in the NetworkCapabilities) must be the one received from the hardware event
7505            //    received, or we might skip callbacks.
7506            // 3. Ensure that when we disconnect, RSSI monitoring is stopped.
7507            log("Received signal strength thresholds: " + Arrays.toString(thresholds));
7508            if (thresholds.length == 0) {
7509                WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
7510                        mWifiInfo.getRssi());
7511                return;
7512            }
7513            int [] rssiVals = Arrays.copyOf(thresholds, thresholds.length + 2);
7514            rssiVals[rssiVals.length - 2] = Byte.MIN_VALUE;
7515            rssiVals[rssiVals.length - 1] = Byte.MAX_VALUE;
7516            Arrays.sort(rssiVals);
7517            byte[] rssiRange = new byte[rssiVals.length];
7518            for (int i = 0; i < rssiVals.length; i++) {
7519                int val = rssiVals[i];
7520                if (val <= Byte.MAX_VALUE && val >= Byte.MIN_VALUE) {
7521                    rssiRange[i] = (byte) val;
7522                } else {
7523                    Log.e(TAG, "Illegal value " + val + " for RSSI thresholds: "
7524                            + Arrays.toString(rssiVals));
7525                    WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD,
7526                            mWifiInfo.getRssi());
7527                    return;
7528                }
7529            }
7530            // TODO: Do we quash rssi values in this sorted array which are very close?
7531            mRssiRanges = rssiRange;
7532            WifiStateMachine.this.sendMessage(CMD_START_RSSI_MONITORING_OFFLOAD,
7533                    mWifiInfo.getRssi());
7534        }
7535
7536        @Override
7537        protected void preventAutomaticReconnect() {
7538            if (this != mNetworkAgent) return;
7539            unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN);
7540        }
7541    }
7542
7543    void unwantedNetwork(int reason) {
7544        sendMessage(CMD_UNWANTED_NETWORK, reason);
7545    }
7546
7547    void doNetworkStatus(int status) {
7548        sendMessage(CMD_NETWORK_STATUS, status);
7549    }
7550
7551    // rfc4186 & rfc4187:
7552    // create Permanent Identity base on IMSI,
7553    // identity = usernam@realm
7554    // with username = prefix | IMSI
7555    // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003)
7556    private String buildIdentity(int eapMethod, String imsi, String mccMnc) {
7557        String mcc;
7558        String mnc;
7559        String prefix;
7560
7561        if (imsi == null || imsi.isEmpty())
7562            return "";
7563
7564        if (eapMethod == WifiEnterpriseConfig.Eap.SIM)
7565            prefix = "1";
7566        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA)
7567            prefix = "0";
7568        else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)
7569            prefix = "6";
7570        else  // not a valide EapMethod
7571            return "";
7572
7573        /* extract mcc & mnc from mccMnc */
7574        if (mccMnc != null && !mccMnc.isEmpty()) {
7575            mcc = mccMnc.substring(0, 3);
7576            mnc = mccMnc.substring(3);
7577            if (mnc.length() == 2)
7578                mnc = "0" + mnc;
7579        } else {
7580            // extract mcc & mnc from IMSI, assume mnc size is 3
7581            mcc = imsi.substring(0, 3);
7582            mnc = imsi.substring(3, 6);
7583        }
7584
7585        return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org";
7586    }
7587
7588    boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) {
7589        if (config == null)
7590            return false;
7591
7592        // We are still seeing a fairly high power consumption triggered by autojoin scans
7593        // Hence do partial scans only for PSK configuration that are roamable since the
7594        // primary purpose of the partial scans is roaming.
7595        // Full badn scans with exponential backoff for the purpose or extended roaming and
7596        // network switching are performed unconditionally.
7597        ScanDetailCache scanDetailCache =
7598                mWifiConfigManager.getScanDetailCache(config);
7599        if (scanDetailCache == null
7600                || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
7601                || scanDetailCache.size() > 6) {
7602            //return true but to not trigger the scan
7603            return true;
7604        }
7605        HashSet<Integer> freqs = mWifiConfigManager.makeChannelList(config,
7606                ONE_HOUR_MILLI, restrictChannelList);
7607        if (freqs != null && freqs.size() != 0) {
7608            //if (DBG) {
7609            logd("starting scan for " + config.configKey() + " with " + freqs);
7610            //}
7611            // Call wifi native to start the scan
7612            if (startScanNative(freqs)) {
7613                // Only count battery consumption if scan request is accepted
7614                noteScanStart(SCAN_ALARM_SOURCE, null);
7615                messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
7616            } else {
7617                // used for debug only, mark scan as failed
7618                messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
7619            }
7620            return true;
7621        } else {
7622            if (DBG) logd("no channels for " + config.configKey());
7623            return false;
7624        }
7625    }
7626
7627    void clearCurrentConfigBSSID(String dbg) {
7628        // Clear the bssid in the current config's network block
7629        WifiConfiguration config = getCurrentWifiConfiguration();
7630        if (config == null)
7631            return;
7632        clearConfigBSSID(config, dbg);
7633    }
7634    void clearConfigBSSID(WifiConfiguration config, String dbg) {
7635        if (config == null)
7636            return;
7637        if (DBG) {
7638            logd(dbg + " " + mTargetRoamBSSID + " config " + config.configKey()
7639                    + " config.NetworkSelectionStatus.mNetworkSelectionBSSID "
7640                    + config.getNetworkSelectionStatus().getNetworkSelectionBSSID());
7641        }
7642        config.getNetworkSelectionStatus().setNetworkSelectionBSSID("any");
7643        if (DBG) {
7644           logd(dbg + " " + config.SSID
7645                    + " nid=" + Integer.toString(config.networkId));
7646        }
7647        mWifiConfigManager.saveWifiConfigBSSID(config);
7648    }
7649
7650    class L2ConnectedState extends State {
7651        @Override
7652        public void enter() {
7653            mRssiPollToken++;
7654            if (mEnableRssiPolling) {
7655                sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
7656            }
7657            if (mNetworkAgent != null) {
7658                loge("Have NetworkAgent when entering L2Connected");
7659                setNetworkDetailedState(DetailedState.DISCONNECTED);
7660            }
7661            setNetworkDetailedState(DetailedState.CONNECTING);
7662
7663            if (!TextUtils.isEmpty(mTcpBufferSizes)) {
7664                mLinkProperties.setTcpBufferSizes(mTcpBufferSizes);
7665            }
7666            mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
7667                    "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
7668                    mLinkProperties, 60);
7669
7670            // We must clear the config BSSID, as the wifi chipset may decide to roam
7671            // from this point on and having the BSSID specified in the network block would
7672            // cause the roam to faile and the device to disconnect
7673            clearCurrentConfigBSSID("L2ConnectedState");
7674        }
7675
7676        @Override
7677        public void exit() {
7678            mIpManager.stop();
7679
7680            // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
7681            // Bug: 15347363
7682            // For paranoia's sake, call handleNetworkDisconnect
7683            // only if BSSID is null or last networkId
7684            // is not invalid.
7685            if (DBG) {
7686                StringBuilder sb = new StringBuilder();
7687                sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
7688                if (mLastBssid !=null) {
7689                    sb.append(" ").append(mLastBssid);
7690                }
7691            }
7692            if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
7693                handleNetworkDisconnect();
7694            }
7695        }
7696
7697        @Override
7698        public boolean processMessage(Message message) {
7699            logStateAndMessage(message, this);
7700
7701            switch (message.what) {
7702                case DhcpClient.CMD_PRE_DHCP_ACTION:
7703                    handlePreDhcpSetup();
7704                    break;
7705                case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
7706                    mIpManager.completedPreDhcpAction();
7707                    break;
7708                case DhcpClient.CMD_POST_DHCP_ACTION:
7709                    handlePostDhcpSetup();
7710                    // We advance to mConnectedState because IpManager will also send a
7711                    // CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
7712                    // which calls updateLinkProperties, which then sends
7713                    // CMD_IP_CONFIGURATION_SUCCESSFUL.
7714                    //
7715                    // In the event of failure, we transition to mDisconnectingState
7716                    // similarly--via messages sent back from IpManager.
7717                    break;
7718                case CMD_IPV4_PROVISIONING_SUCCESS: {
7719                    handleIPv4Success((DhcpResults) message.obj);
7720                    break;
7721                }
7722                case CMD_IPV4_PROVISIONING_FAILURE: {
7723                    handleIPv4Failure();
7724                    break;
7725                }
7726                case CMD_IP_CONFIGURATION_SUCCESSFUL:
7727                    handleSuccessfulIpConfiguration();
7728                    mWifiMetrics.endConnectionEvent(
7729                            WifiMetrics.ConnectionEvent.LLF_NONE,
7730                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
7731                    sendConnectedState();
7732                    transitionTo(mConnectedState);
7733                    break;
7734                case CMD_IP_CONFIGURATION_LOST:
7735                    // Get Link layer stats so that we get fresh tx packet counters.
7736                    getWifiLinkLayerStats(true);
7737                    handleIpConfigurationLost();
7738                    transitionTo(mDisconnectingState);
7739                    break;
7740                case CMD_IP_REACHABILITY_LOST:
7741                    if (DBG && message.obj != null) log((String) message.obj);
7742                    handleIpReachabilityLost();
7743                    transitionTo(mDisconnectingState);
7744                    break;
7745                case CMD_DISCONNECT:
7746                    mWifiNative.disconnect();
7747                    transitionTo(mDisconnectingState);
7748                    break;
7749                case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
7750                    if (message.arg1 == 1) {
7751                        mWifiNative.disconnect();
7752                        mTemporarilyDisconnectWifi = true;
7753                        transitionTo(mDisconnectingState);
7754                    }
7755                    break;
7756                case CMD_SET_OPERATIONAL_MODE:
7757                    if (message.arg1 != CONNECT_MODE) {
7758                        sendMessage(CMD_DISCONNECT);
7759                        deferMessage(message);
7760                        if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
7761                            noteWifiDisabledWhileAssociated();
7762                        }
7763                    }
7764                    mWifiConfigManager.
7765                                setAndEnableLastSelectedConfiguration(
7766                                        WifiConfiguration.INVALID_NETWORK_ID);
7767                    break;
7768                case CMD_SET_COUNTRY_CODE:
7769                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
7770                    deferMessage(message);
7771                    break;
7772                case CMD_START_SCAN:
7773                    if (DBG) {
7774                        logd("CMD_START_SCAN source " + message.arg1
7775                              + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate)
7776                              + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate)
7777                              + " targetRoamBSSID=" + mTargetRoamBSSID
7778                              + " RSSI=" + mWifiInfo.getRssi());
7779                    }
7780                    if (message.arg1 == SCAN_ALARM_SOURCE) {
7781                        // Check if the CMD_START_SCAN message is obsolete (and thus if it should
7782                        // not be processed) and restart the scan if neede
7783                        if (!getEnableAutoJoinWhenAssociated()) {
7784                            return HANDLED;
7785                        }
7786                        boolean shouldScan = mScreenOn;
7787
7788                        if (!checkAndRestartDelayedScan(message.arg2,
7789                                shouldScan,
7790                                mWifiConfigManager.wifiAssociatedShortScanIntervalMilli.get(),
7791                                null, null)) {
7792                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
7793                            logd("L2Connected CMD_START_SCAN source "
7794                                    + message.arg1
7795                                    + " " + message.arg2 + ", " + mDelayedScanCounter
7796                                    + " -> obsolete");
7797                            return HANDLED;
7798                        }
7799                        if (mP2pConnected.get()) {
7800                            logd("L2Connected CMD_START_SCAN source "
7801                                    + message.arg1
7802                                    + " " + message.arg2 + ", " + mDelayedScanCounter
7803                                    + " ignore because P2P is connected");
7804                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
7805                            return HANDLED;
7806                        }
7807                        boolean tryFullBandScan = false;
7808                        boolean restrictChannelList = false;
7809                        long now_ms = System.currentTimeMillis();
7810                        if (DBG) {
7811                            logd("CMD_START_SCAN with age="
7812                                    + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
7813                                    + " interval=" + fullBandConnectedTimeIntervalMilli
7814                                    + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
7815                        }
7816                        if (mWifiInfo != null) {
7817                            if (mWifiConfigManager.enableFullBandScanWhenAssociated.get() &&
7818                                    (now_ms - lastFullBandConnectedTimeMilli)
7819                                    > fullBandConnectedTimeIntervalMilli) {
7820                                if (DBG) {
7821                                    logd("CMD_START_SCAN try full band scan age="
7822                                         + Long.toString(now_ms - lastFullBandConnectedTimeMilli)
7823                                         + " interval=" + fullBandConnectedTimeIntervalMilli
7824                                         + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli);
7825                                }
7826                                tryFullBandScan = true;
7827                            }
7828
7829                            if (mWifiInfo.txSuccessRate >
7830                                    mWifiConfigManager.maxTxPacketForFullScans
7831                                    || mWifiInfo.rxSuccessRate >
7832                                    mWifiConfigManager.maxRxPacketForFullScans) {
7833                                // Too much traffic at the interface, hence no full band scan
7834                                if (DBG) {
7835                                    logd("CMD_START_SCAN " +
7836                                            "prevent full band scan due to pkt rate");
7837                                }
7838                                tryFullBandScan = false;
7839                            }
7840
7841                            if (mWifiInfo.txSuccessRate >
7842                                    mWifiConfigManager.maxTxPacketForPartialScans
7843                                    || mWifiInfo.rxSuccessRate >
7844                                    mWifiConfigManager.maxRxPacketForPartialScans) {
7845                                // Don't scan if lots of packets are being sent
7846                                restrictChannelList = true;
7847                                if (mWifiConfigManager.alwaysEnableScansWhileAssociated.get() ==
7848                                        0) {
7849                                    if (DBG) {
7850                                     logd("CMD_START_SCAN source " + message.arg1
7851                                        + " ...and ignore scans"
7852                                        + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate)
7853                                        + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate));
7854                                    }
7855                                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
7856                                    return HANDLED;
7857                                }
7858                            }
7859                        }
7860
7861                        WifiConfiguration currentConfiguration = getCurrentWifiConfiguration();
7862                        if (DBG) {
7863                            logd("CMD_START_SCAN full=" +
7864                                    tryFullBandScan);
7865                        }
7866                        if (currentConfiguration != null) {
7867                            if (fullBandConnectedTimeIntervalMilli <
7868                                    mWifiConfigManager.wifiAssociatedShortScanIntervalMilli.get()) {
7869                                // Sanity
7870                                fullBandConnectedTimeIntervalMilli =
7871                                        mWifiConfigManager
7872                                                .wifiAssociatedShortScanIntervalMilli.get();
7873                            }
7874                            if (tryFullBandScan) {
7875                                lastFullBandConnectedTimeMilli = now_ms;
7876                                if (fullBandConnectedTimeIntervalMilli
7877                                        < mWifiConfigManager.associatedFullScanMaxIntervalMilli) {
7878                                    // Increase the interval
7879                                    fullBandConnectedTimeIntervalMilli =
7880                                            fullBandConnectedTimeIntervalMilli *
7881                                                    mWifiConfigManager
7882                                                            .associatedFullScanBackoff.get() / 8;
7883
7884                                    if (DBG) {
7885                                        logd("CMD_START_SCAN bump interval ="
7886                                        + fullBandConnectedTimeIntervalMilli);
7887                                    }
7888                                }
7889                                handleScanRequest(message);
7890                            } else {
7891                                if (!startScanForConfiguration(
7892                                        currentConfiguration, restrictChannelList)) {
7893                                    if (DBG) {
7894                                        logd("starting scan, " +
7895                                                " did not find channels -> full");
7896                                    }
7897                                    lastFullBandConnectedTimeMilli = now_ms;
7898                                    if (fullBandConnectedTimeIntervalMilli
7899                                            < mWifiConfigManager
7900                                            .associatedFullScanMaxIntervalMilli) {
7901                                        // Increase the interval
7902                                        fullBandConnectedTimeIntervalMilli =
7903                                                fullBandConnectedTimeIntervalMilli *
7904                                                        mWifiConfigManager
7905                                                                .associatedFullScanBackoff.get() / 8;
7906
7907                                        if (DBG) {
7908                                            logd("CMD_START_SCAN bump interval ="
7909                                                    + fullBandConnectedTimeIntervalMilli);
7910                                        }
7911                                    }
7912                                    handleScanRequest(message);
7913                                }
7914                            }
7915
7916                        } else {
7917                            logd("CMD_START_SCAN : connected mode and no configuration");
7918                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR;
7919                        }
7920                    } else {
7921                        // Not scan alarm source
7922                        return NOT_HANDLED;
7923                    }
7924                    break;
7925                    /* Ignore connection to same network */
7926                case WifiManager.CONNECT_NETWORK:
7927                    int netId = message.arg1;
7928                    if (mWifiInfo.getNetworkId() == netId) {
7929                        break;
7930                    }
7931                    return NOT_HANDLED;
7932                case WifiMonitor.NETWORK_CONNECTION_EVENT:
7933                    mWifiInfo.setBSSID((String) message.obj);
7934                    mLastNetworkId = message.arg1;
7935                    mWifiInfo.setNetworkId(mLastNetworkId);
7936                    if(!mLastBssid.equals((String) message.obj)) {
7937                        mLastBssid = (String) message.obj;
7938                        sendNetworkStateChangeBroadcast(mLastBssid);
7939                    }
7940                    break;
7941                case CMD_RSSI_POLL:
7942                    if (message.arg1 == mRssiPollToken) {
7943                        if (mWifiConfigManager.enableChipWakeUpWhenAssociated.get()) {
7944                            if (VVDBG) log(" get link layer stats " + mWifiLinkLayerStatsSupported);
7945                            WifiLinkLayerStats stats = getWifiLinkLayerStats(VDBG);
7946                            if (stats != null) {
7947                                // Sanity check the results provided by driver
7948                                if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI
7949                                        && (stats.rssi_mgmt == 0
7950                                        || stats.beacon_rx == 0)) {
7951                                    stats = null;
7952                                }
7953                            }
7954                            // Get Info and continue polling
7955                            fetchRssiLinkSpeedAndFrequencyNative();
7956                            calculateWifiScore(stats);
7957                        }
7958                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
7959                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
7960                        if (DBG) sendRssiChangeBroadcast(mWifiInfo.getRssi());
7961                    } else {
7962                        // Polling has completed
7963                    }
7964                    break;
7965                case CMD_ENABLE_RSSI_POLL:
7966                    cleanWifiScore();
7967                    if (mWifiConfigManager.enableRssiPollWhenAssociated.get()) {
7968                        mEnableRssiPolling = (message.arg1 == 1);
7969                    } else {
7970                        mEnableRssiPolling = false;
7971                    }
7972                    mRssiPollToken++;
7973                    if (mEnableRssiPolling) {
7974                        // First poll
7975                        fetchRssiLinkSpeedAndFrequencyNative();
7976                        sendMessageDelayed(obtainMessage(CMD_RSSI_POLL,
7977                                mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
7978                    }
7979                    break;
7980                case WifiManager.RSSI_PKTCNT_FETCH:
7981                    RssiPacketCountInfo info = new RssiPacketCountInfo();
7982                    fetchRssiLinkSpeedAndFrequencyNative();
7983                    info.rssi = mWifiInfo.getRssi();
7984                    fetchPktcntNative(info);
7985                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
7986                    break;
7987                case CMD_DELAYED_NETWORK_DISCONNECT:
7988                    if (!linkDebouncing && mWifiConfigManager.enableLinkDebouncing) {
7989
7990                        // Ignore if we are not debouncing
7991                        logd("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore "
7992                                + message.arg1);
7993                        return HANDLED;
7994                    } else {
7995                        logd("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect "
7996                                + message.arg1);
7997
7998                        linkDebouncing = false;
7999                        // If we are still debouncing while this message comes,
8000                        // it means we were not able to reconnect within the alloted time
8001                        // = LINK_FLAPPING_DEBOUNCE_MSEC
8002                        // and thus, trigger a real disconnect
8003                        handleNetworkDisconnect();
8004                        transitionTo(mDisconnectedState);
8005                    }
8006                    break;
8007                case CMD_ASSOCIATED_BSSID:
8008                    if ((String) message.obj == null) {
8009                        logw("Associated command w/o BSSID");
8010                        break;
8011                    }
8012                    mLastBssid = (String) message.obj;
8013                    if (mLastBssid != null
8014                            && (mWifiInfo.getBSSID() == null
8015                            || !mLastBssid.equals(mWifiInfo.getBSSID()))) {
8016                        mWifiInfo.setBSSID((String) message.obj);
8017                        sendNetworkStateChangeBroadcast(mLastBssid);
8018                    }
8019                    break;
8020                case CMD_START_RSSI_MONITORING_OFFLOAD:
8021                case CMD_RSSI_THRESHOLD_BREACH:
8022                    byte currRssi = (byte) message.arg1;
8023                    processRssiThreshold(currRssi, message.what);
8024                    break;
8025                case CMD_STOP_RSSI_MONITORING_OFFLOAD:
8026                    stopRssiMonitoringOffload();
8027                    break;
8028                case CMD_RESET_SIM_NETWORKS:
8029                    if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
8030                        WifiConfiguration config =
8031                                mWifiConfigManager.getWifiConfiguration(mLastNetworkId);
8032                        if (mWifiConfigManager.isSimConfig(config)) {
8033                            mWifiNative.disconnect();
8034                            transitionTo(mDisconnectingState);
8035                        }
8036                    }
8037                    /* allow parent state to reset data for other networks */
8038                    return NOT_HANDLED;
8039                default:
8040                    return NOT_HANDLED;
8041            }
8042
8043            return HANDLED;
8044        }
8045    }
8046
8047    class ObtainingIpState extends State {
8048        @Override
8049        public void enter() {
8050            if (DBG) {
8051                String key = "";
8052                if (getCurrentWifiConfiguration() != null) {
8053                    key = getCurrentWifiConfiguration().configKey();
8054                }
8055                log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId)
8056                        + " " + key + " "
8057                        + " roam=" + mAutoRoaming
8058                        + " static=" + mWifiConfigManager.isUsingStaticIp(mLastNetworkId)
8059                        + " watchdog= " + obtainingIpWatchdogCount);
8060            }
8061
8062            // Reset link Debouncing, indicating we have successfully re-connected to the AP
8063            // We might still be roaming
8064            linkDebouncing = false;
8065
8066            // Send event to CM & network change broadcast
8067            setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
8068
8069            // We must clear the config BSSID, as the wifi chipset may decide to roam
8070            // from this point on and having the BSSID specified in the network block would
8071            // cause the roam to fail and the device to disconnect.
8072            clearCurrentConfigBSSID("ObtainingIpAddress");
8073
8074            // Stop IpManager in case we're switching from DHCP to static
8075            // configuration or vice versa.
8076            //
8077            // TODO: Only ever enter this state the first time we connect to a
8078            // network, never on switching between static configuration and
8079            // DHCP. When we transition from static configuration to DHCP in
8080            // particular, we must tell ConnectivityService that we're
8081            // disconnected, because DHCP might take a long time during which
8082            // connectivity APIs such as getActiveNetworkInfo should not return
8083            // CONNECTED.
8084            stopIpManager();
8085
8086            if (!mWifiConfigManager.isUsingStaticIp(mLastNetworkId)) {
8087                final IpManager.ProvisioningConfiguration prov =
8088                        mIpManager.buildProvisioningConfiguration()
8089                            .withPreDhcpAction()
8090                            .build();
8091                mIpManager.startProvisioning(prov);
8092                obtainingIpWatchdogCount++;
8093                logd("Start Dhcp Watchdog " + obtainingIpWatchdogCount);
8094                // Get Link layer stats so as we get fresh tx packet counters
8095                getWifiLinkLayerStats(true);
8096                sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER,
8097                        obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC);
8098            } else {
8099                StaticIpConfiguration config = mWifiConfigManager.getStaticIpConfiguration(
8100                        mLastNetworkId);
8101                if (config.ipAddress == null) {
8102                    logd("Static IP lacks address");
8103                    sendMessage(CMD_IPV4_PROVISIONING_FAILURE);
8104                } else {
8105                    final IpManager.ProvisioningConfiguration prov =
8106                            mIpManager.buildProvisioningConfiguration()
8107                                .withStaticConfiguration(config)
8108                                .build();
8109                    mIpManager.startProvisioning(prov);
8110                }
8111            }
8112        }
8113
8114        @Override
8115        public boolean processMessage(Message message) {
8116            logStateAndMessage(message, this);
8117
8118            switch(message.what) {
8119                case CMD_AUTO_CONNECT:
8120                case CMD_AUTO_ROAM:
8121                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8122                    break;
8123                case WifiManager.SAVE_NETWORK:
8124                case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
8125                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
8126                    deferMessage(message);
8127                    break;
8128                    /* Defer any power mode changes since we must keep active power mode at DHCP */
8129
8130                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
8131                    mWifiMetrics.endConnectionEvent(
8132                            WifiMetrics.ConnectionEvent.LLF_NETWORK_DISCONNECTION,
8133                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
8134                    return NOT_HANDLED;
8135                case CMD_SET_HIGH_PERF_MODE:
8136                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
8137                    deferMessage(message);
8138                    break;
8139                    /* Defer scan request since we should not switch to other channels at DHCP */
8140                case CMD_START_SCAN:
8141                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
8142                    deferMessage(message);
8143                    break;
8144                case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER:
8145                    if (message.arg1 == obtainingIpWatchdogCount) {
8146                        logd("ObtainingIpAddress: Watchdog Triggered, count="
8147                                + obtainingIpWatchdogCount);
8148                        handleIpConfigurationLost();
8149                        transitionTo(mDisconnectingState);
8150                        break;
8151                    }
8152                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8153                    break;
8154                default:
8155                    return NOT_HANDLED;
8156            }
8157            return HANDLED;
8158        }
8159    }
8160
8161    private void sendConnectedState() {
8162        // If this network was explicitly selected by the user, evaluate whether to call
8163        // explicitlySelected() so the system can treat it appropriately.
8164        WifiConfiguration config = getCurrentWifiConfiguration();
8165        if (mWifiConfigManager.isLastSelectedConfiguration(config)) {
8166            boolean prompt =
8167                    mWifiConfigManager.checkConfigOverridePermission(config.lastConnectUid);
8168            if (DBG) {
8169                log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt);
8170            }
8171            if (prompt) {
8172                // Selected by the user via Settings or QuickSettings. If this network has Internet
8173                // access, switch to it. Otherwise, switch to it only if the user confirms that they
8174                // really want to switch, or has already confirmed and selected "Don't ask again".
8175                if (DBG) {
8176                    log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected);
8177                }
8178                mNetworkAgent.explicitlySelected(config.noInternetAccessExpected);
8179            }
8180        }
8181
8182        setNetworkDetailedState(DetailedState.CONNECTED);
8183        mWifiConfigManager.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
8184        sendNetworkStateChangeBroadcast(mLastBssid);
8185    }
8186
8187    class RoamingState extends State {
8188        boolean mAssociated;
8189        @Override
8190        public void enter() {
8191            if (DBG) {
8192                log("RoamingState Enter"
8193                        + " mScreenOn=" + mScreenOn );
8194            }
8195            setScanAlarm(false);
8196
8197            // Make sure we disconnect if roaming fails
8198            roamWatchdogCount++;
8199            logd("Start Roam Watchdog " + roamWatchdogCount);
8200            sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER,
8201                    roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC);
8202            mAssociated = false;
8203        }
8204        @Override
8205        public boolean processMessage(Message message) {
8206            logStateAndMessage(message, this);
8207            WifiConfiguration config;
8208            switch (message.what) {
8209                case CMD_IP_CONFIGURATION_LOST:
8210                    config = getCurrentWifiConfiguration();
8211                    if (config != null) {
8212                        mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
8213                        mWifiConfigManager.noteRoamingFailure(config,
8214                                WifiConfiguration.ROAMING_FAILURE_IP_CONFIG);
8215                    }
8216                    return NOT_HANDLED;
8217                case CMD_UNWANTED_NETWORK:
8218                    if (DBG) log("Roaming and CS doesnt want the network -> ignore");
8219                    return HANDLED;
8220                case CMD_SET_OPERATIONAL_MODE:
8221                    if (message.arg1 != CONNECT_MODE) {
8222                        deferMessage(message);
8223                    }
8224                    break;
8225                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
8226                    /**
8227                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
8228                     * before NETWORK_DISCONNECTION_EVENT
8229                     * And there is an associated BSSID corresponding to our target BSSID, then
8230                     * we have missed the network disconnection, transition to mDisconnectedState
8231                     * and handle the rest of the events there.
8232                     */
8233                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
8234                    if (stateChangeResult.state == SupplicantState.DISCONNECTED
8235                            || stateChangeResult.state == SupplicantState.INACTIVE
8236                            || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
8237                        if (DBG) {
8238                            log("STATE_CHANGE_EVENT in roaming state "
8239                                    + stateChangeResult.toString() );
8240                        }
8241                        if (stateChangeResult.BSSID != null
8242                                && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
8243                            handleNetworkDisconnect();
8244                            transitionTo(mDisconnectedState);
8245                        }
8246                    }
8247                    if (stateChangeResult.state == SupplicantState.ASSOCIATED) {
8248                        // We completed the layer2 roaming part
8249                        mAssociated = true;
8250                        if (stateChangeResult.BSSID != null) {
8251                            mTargetRoamBSSID = (String) stateChangeResult.BSSID;
8252                        }
8253                    }
8254                    break;
8255                case CMD_ROAM_WATCHDOG_TIMER:
8256                    if (roamWatchdogCount == message.arg1) {
8257                        if (DBG) log("roaming watchdog! -> disconnect");
8258                        mRoamFailCount++;
8259                        handleNetworkDisconnect();
8260                        mWifiNative.disconnect();
8261                        transitionTo(mDisconnectedState);
8262                    }
8263                    break;
8264                case WifiMonitor.NETWORK_CONNECTION_EVENT:
8265                    if (mAssociated) {
8266                        if (DBG) log("roaming and Network connection established");
8267                        mLastNetworkId = message.arg1;
8268                        mLastBssid = (String) message.obj;
8269                        mWifiInfo.setBSSID(mLastBssid);
8270                        mWifiInfo.setNetworkId(mLastNetworkId);
8271                        mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(
8272                                mLastBssid, true);
8273                        sendNetworkStateChangeBroadcast(mLastBssid);
8274
8275                        // We used to transition to ObtainingIpState in an
8276                        // attempt to do DHCPv4 RENEWs on framework roams.
8277                        // DHCP can take too long to time out, and we now rely
8278                        // upon IpManager's use of IpReachabilityMonitor to
8279                        // confirm our current network configuration.
8280                        //
8281                        // mIpManager.confirmConfiguration() is called within
8282                        // the handling of SupplicantState.COMPLETED.
8283                        transitionTo(mConnectedState);
8284                    } else {
8285                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
8286                    }
8287                    break;
8288                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
8289                    // Throw away but only if it corresponds to the network we're roaming to
8290                    String bssid = (String) message.obj;
8291                    if (true) {
8292                        String target = "";
8293                        if (mTargetRoamBSSID != null) target = mTargetRoamBSSID;
8294                        log("NETWORK_DISCONNECTION_EVENT in roaming state"
8295                                + " BSSID=" + bssid
8296                                + " target=" + target);
8297                    }
8298                    if (bssid != null && bssid.equals(mTargetRoamBSSID)) {
8299                        handleNetworkDisconnect();
8300                        transitionTo(mDisconnectedState);
8301                    }
8302                    break;
8303                case WifiMonitor.SSID_TEMP_DISABLED:
8304                    // Auth error while roaming
8305                    logd("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId)
8306                            + " id=" + Integer.toString(message.arg1)
8307                            + " isRoaming=" + isRoaming()
8308                            + " roam=" + mAutoRoaming);
8309                    if (message.arg1 == mLastNetworkId) {
8310                        config = getCurrentWifiConfiguration();
8311                        if (config != null) {
8312                            mWifiLogger.captureBugReportData(
8313                                    WifiLogger.REPORT_REASON_AUTOROAM_FAILURE);
8314                            mWifiConfigManager.noteRoamingFailure(config,
8315                                    WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE);
8316                        }
8317                        handleNetworkDisconnect();
8318                        transitionTo(mDisconnectingState);
8319                    }
8320                    return NOT_HANDLED;
8321                case CMD_START_SCAN:
8322                    deferMessage(message);
8323                    break;
8324                default:
8325                    return NOT_HANDLED;
8326            }
8327            return HANDLED;
8328        }
8329
8330        @Override
8331        public void exit() {
8332            logd("WifiStateMachine: Leaving Roaming state");
8333        }
8334    }
8335
8336    class ConnectedState extends State {
8337        @Override
8338        public void enter() {
8339            String address;
8340            updateDefaultRouteMacAddress(1000);
8341            if (DBG) {
8342                log("Enter ConnectedState "
8343                       + " mScreenOn=" + mScreenOn
8344                       + " scanperiod="
8345                       + Integer.toString(
8346                            mWifiConfigManager.wifiAssociatedShortScanIntervalMilli.get())
8347                       + " useGscan=" + mHalBasedPnoDriverSupported + "/"
8348                        + mWifiConfigManager.enableHalBasedPno.get()
8349                        + " mHalBasedPnoEnableInDevSettings " + mHalBasedPnoEnableInDevSettings);
8350            }
8351            if (mScreenOn
8352                    && getEnableAutoJoinWhenAssociated()) {
8353                if (useHalBasedAutoJoinOffload()) {
8354                    startGScanConnectedModeOffload("connectedEnter");
8355                } else {
8356                    // restart scan alarm
8357                    startDelayedScan(mWifiConfigManager.wifiAssociatedShortScanIntervalMilli.get(),
8358                            null, null);
8359                }
8360            }
8361            registerConnected();
8362            lastConnectAttemptTimestamp = 0;
8363            targetWificonfiguration = null;
8364            // Paranoia
8365            linkDebouncing = false;
8366
8367            // Not roaming anymore
8368            mAutoRoaming = false;
8369
8370            if (testNetworkDisconnect) {
8371                testNetworkDisconnectCounter++;
8372                logd("ConnectedState Enter start disconnect test " +
8373                        testNetworkDisconnectCounter);
8374                sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT,
8375                        testNetworkDisconnectCounter, 0), 15000);
8376            }
8377
8378            // Reenable all networks, allow for hidden networks to be scanned
8379            mWifiConfigManager.enableAllNetworks();
8380
8381            mLastDriverRoamAttempt = 0;
8382            mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
8383            //startLazyRoam();
8384        }
8385        @Override
8386        public boolean processMessage(Message message) {
8387            WifiConfiguration config = null;
8388            logStateAndMessage(message, this);
8389
8390            switch (message.what) {
8391                case CMD_RESTART_AUTOJOIN_OFFLOAD:
8392                    if ( (int)message.arg2 < mRestartAutoJoinOffloadCounter ) {
8393                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
8394                        return HANDLED;
8395                    }
8396                    /* If we are still in Disconnected state after having discovered a valid
8397                     * network this means autojoin didnt managed to associate to the network,
8398                     * then restart PNO so as we will try associating to it again.
8399                     */
8400                    if (useHalBasedAutoJoinOffload()) {
8401                        if (mGScanStartTimeMilli == 0) {
8402                            // If offload is not started, then start it...
8403                            startGScanConnectedModeOffload("connectedRestart");
8404                        } else {
8405                            // If offload is already started, then check if we need to increase
8406                            // the scan period and restart the Gscan
8407                            long now = System.currentTimeMillis();
8408                            if (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
8409                                    && ((now - mGScanStartTimeMilli)
8410                                    > DISCONNECTED_SHORT_SCANS_DURATION_MILLI)
8411                                && (mGScanPeriodMilli
8412                                    < mWifiConfigManager
8413                                    .wifiDisconnectedLongScanIntervalMilli.get()))
8414                            {
8415                                startConnectedGScan("Connected restart gscan");
8416                            }
8417                        }
8418                    }
8419                    break;
8420                case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION:
8421                    updateAssociatedScanPermission();
8422                    break;
8423                case CMD_UNWANTED_NETWORK:
8424                    if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
8425                        mWifiConfigManager.handleBadNetworkDisconnectReport(
8426                                mLastNetworkId, mWifiInfo);
8427                        mWifiNative.disconnect();
8428                        transitionTo(mDisconnectingState);
8429                    } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
8430                            message.arg1 == NETWORK_STATUS_UNWANTED_VALIDATION_FAILED) {
8431                        Log.d(TAG, (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN
8432                                ? "NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN"
8433                                : "NETWORK_STATUS_UNWANTED_VALIDATION_FAILED"));
8434                        config = getCurrentWifiConfiguration();
8435                        if (config != null) {
8436                            // Disable autojoin
8437                            if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN) {
8438                                config.validatedInternetAccess = false;
8439                                // Clear last-selected status, as being last-selected also avoids
8440                                // disabling auto-join.
8441                                if (mWifiConfigManager.isLastSelectedConfiguration(config)) {
8442                                    mWifiConfigManager.setAndEnableLastSelectedConfiguration(
8443                                        WifiConfiguration.INVALID_NETWORK_ID);
8444                                }
8445                                mWifiConfigManager.updateNetworkSelectionStatus(config,
8446                                        WifiConfiguration.NetworkSelectionStatus
8447                                        .DISABLED_NO_INTERNET);
8448                            }
8449                            config.numNoInternetAccessReports += 1;
8450                            mWifiConfigManager.writeKnownNetworkHistory();
8451                        }
8452                    }
8453                    return HANDLED;
8454                case CMD_NETWORK_STATUS:
8455                    if (message.arg1 == NetworkAgent.VALID_NETWORK) {
8456                        config = getCurrentWifiConfiguration();
8457                        if (config != null) {
8458                            // re-enable autojoin
8459                            config.numNoInternetAccessReports = 0;
8460                            config.validatedInternetAccess = true;
8461                            mWifiConfigManager.writeKnownNetworkHistory();
8462                        }
8463                    }
8464                    return HANDLED;
8465                case CMD_ACCEPT_UNVALIDATED:
8466                    boolean accept = (message.arg1 != 0);
8467                    config = getCurrentWifiConfiguration();
8468                    if (config != null) {
8469                        config.noInternetAccessExpected = accept;
8470                    }
8471                    return HANDLED;
8472                case CMD_TEST_NETWORK_DISCONNECT:
8473                    // Force a disconnect
8474                    if (message.arg1 == testNetworkDisconnectCounter) {
8475                        mWifiNative.disconnect();
8476                    }
8477                    break;
8478                case CMD_ASSOCIATED_BSSID:
8479                    // ASSOCIATING to a new BSSID while already connected, indicates
8480                    // that driver is roaming
8481                    mLastDriverRoamAttempt = System.currentTimeMillis();
8482                    String toBSSID = (String)message.obj;
8483                    if (toBSSID != null && !toBSSID.equals(mWifiInfo.getBSSID())) {
8484                        mWifiConfigManager.driverRoamedFrom(mWifiInfo);
8485                    }
8486                    return NOT_HANDLED;
8487                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
8488                    long lastRoam = 0;
8489                    mWifiMetrics.endConnectionEvent(
8490                            WifiMetrics.ConnectionEvent.LLF_NETWORK_DISCONNECTION,
8491                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
8492                    if (mLastDriverRoamAttempt != 0) {
8493                        // Calculate time since last driver roam attempt
8494                        lastRoam = System.currentTimeMillis() - mLastDriverRoamAttempt;
8495                        mLastDriverRoamAttempt = 0;
8496                    }
8497                    if (unexpectedDisconnectedReason(message.arg2)) {
8498                        mWifiLogger.captureBugReportData(
8499                                WifiLogger.REPORT_REASON_UNEXPECTED_DISCONNECT);
8500                    }
8501                    config = getCurrentWifiConfiguration();
8502                    if (mScreenOn
8503                            && !linkDebouncing
8504                            && config != null
8505                            && config.getNetworkSelectionStatus().isNetworkEnabled()
8506                            && !mWifiConfigManager.isLastSelectedConfiguration(config)
8507                            && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */
8508                                || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
8509                            && ((ScanResult.is24GHz(mWifiInfo.getFrequency())
8510                                    && mWifiInfo.getRssi() >
8511                                    WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND)
8512                                    || (ScanResult.is5GHz(mWifiInfo.getFrequency())
8513                                    && mWifiInfo.getRssi() >
8514                                    mWifiConfigManager.thresholdQualifiedRssi5.get()))) {
8515                        // Start de-bouncing the L2 disconnection:
8516                        // this L2 disconnection might be spurious.
8517                        // Hence we allow 7 seconds for the state machine to try
8518                        // to reconnect, go thru the
8519                        // roaming cycle and enter Obtaining IP address
8520                        // before signalling the disconnect to ConnectivityService and L3
8521                        startScanForConfiguration(getCurrentWifiConfiguration(), false);
8522                        linkDebouncing = true;
8523
8524                        sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT,
8525                                0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC);
8526                        if (DBG) {
8527                            log("NETWORK_DISCONNECTION_EVENT in connected state"
8528                                    + " BSSID=" + mWifiInfo.getBSSID()
8529                                    + " RSSI=" + mWifiInfo.getRssi()
8530                                    + " freq=" + mWifiInfo.getFrequency()
8531                                    + " reason=" + message.arg2
8532                                    + " -> debounce");
8533                        }
8534                        return HANDLED;
8535                    } else {
8536                        if (DBG) {
8537                            log("NETWORK_DISCONNECTION_EVENT in connected state"
8538                                    + " BSSID=" + mWifiInfo.getBSSID()
8539                                    + " RSSI=" + mWifiInfo.getRssi()
8540                                    + " freq=" + mWifiInfo.getFrequency()
8541                                    + " was debouncing=" + linkDebouncing
8542                                    + " reason=" + message.arg2
8543                                    + " Network Selection Status=" + (config == null ? "Unavailable"
8544                                    : config.getNetworkSelectionStatus().getNetworkStatusString()));
8545                        }
8546                    }
8547                    break;
8548                case CMD_AUTO_ROAM:
8549                    // Clear the driver roam indication since we are attempting a framework roam
8550                    mLastDriverRoamAttempt = 0;
8551
8552                    /* Connect command coming from auto-join */
8553                    ScanResult candidate = (ScanResult)message.obj;
8554                    String bssid = "any";
8555                    if (candidate != null) {
8556                        bssid = candidate.BSSID;
8557                    }
8558                    int netId = mLastNetworkId;
8559                    config = getCurrentWifiConfiguration();
8560
8561
8562                    if (config == null) {
8563                        loge("AUTO_ROAM and no config, bail out...");
8564                        break;
8565                    }
8566
8567                    logd("CMD_AUTO_ROAM sup state "
8568                            + mSupplicantStateTracker.getSupplicantStateName()
8569                            + " my state " + getCurrentState().getName()
8570                            + " nid=" + Integer.toString(netId)
8571                            + " config " + config.configKey()
8572                            + " roam=" + Integer.toString(message.arg2)
8573                            + " to " + bssid
8574                            + " targetRoamBSSID " + mTargetRoamBSSID);
8575
8576                    setTargetBssid(config, bssid);
8577                    mTargetNetworkId = netId;
8578                    // Make sure the network is enabled, since supplicant will not re-enable it
8579                    mWifiConfigManager.enableNetworkWithoutBroadcast(netId, false);
8580
8581                    if (deferForUserInput(message, netId, false)) {
8582                        break;
8583                    } else if (mWifiConfigManager.getWifiConfiguration(netId).userApproved ==
8584                            WifiConfiguration.USER_BANNED) {
8585                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
8586                                WifiManager.NOT_AUTHORIZED);
8587                        break;
8588                    }
8589
8590                    boolean ret = false;
8591                    if (mLastNetworkId != netId) {
8592                        mWifiMetrics.startConnectionEvent(mWifiInfo, config,
8593                                WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
8594                        if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
8595                                WifiConfiguration.UNKNOWN_UID) && mWifiNative.reconnect()) {
8596                            ret = true;
8597                        }
8598                    } else {
8599                        mWifiMetrics.startConnectionEvent(mWifiInfo, config,
8600                                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
8601                        ret = mWifiNative.reassociate();
8602                    }
8603                    if (ret) {
8604                        lastConnectAttemptTimestamp = System.currentTimeMillis();
8605                        targetWificonfiguration = mWifiConfigManager.getWifiConfiguration(netId);
8606
8607                        // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
8608                        mAutoRoaming = true;
8609                        transitionTo(mRoamingState);
8610
8611                    } else {
8612                        loge("Failed to connect config: " + config + " netId: " + netId);
8613                        replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
8614                                WifiManager.ERROR);
8615                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
8616                        mWifiMetrics.endConnectionEvent(
8617                                WifiMetrics.ConnectionEvent.LLF_CONNECT_NETWORK_FAILED,
8618                                WifiMetricsProto.ConnectionEvent.HLF_NONE);
8619                        break;
8620                    }
8621                    break;
8622                case CMD_START_IP_PACKET_OFFLOAD: {
8623                        int slot = message.arg1;
8624                        int intervalSeconds = message.arg2;
8625                        KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
8626                        byte[] dstMac;
8627                        try {
8628                            InetAddress gateway = RouteInfo.selectBestRoute(
8629                                    mLinkProperties.getRoutes(), pkt.dstAddress).getGateway();
8630                            String dstMacStr = macAddressFromRoute(gateway.getHostAddress());
8631                            dstMac = macAddressFromString(dstMacStr);
8632                        } catch (NullPointerException|IllegalArgumentException e) {
8633                            loge("Can't find MAC address for next hop to " + pkt.dstAddress);
8634                            mNetworkAgent.onPacketKeepaliveEvent(slot,
8635                                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
8636                            break;
8637                        }
8638                        pkt.dstMac = dstMac;
8639                        int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
8640                        mNetworkAgent.onPacketKeepaliveEvent(slot, result);
8641                        break;
8642                    }
8643                default:
8644                    return NOT_HANDLED;
8645            }
8646            return HANDLED;
8647        }
8648
8649        @Override
8650        public void exit() {
8651            logd("WifiStateMachine: Leaving Connected state");
8652            setScanAlarm(false);
8653            mLastDriverRoamAttempt = 0;
8654
8655            stopLazyRoam();
8656
8657            mWhiteListedSsids = null;
8658        }
8659    }
8660
8661    class DisconnectingState extends State {
8662
8663        @Override
8664        public void enter() {
8665
8666            if (PDBG) {
8667                logd(" Enter DisconnectingState State scan interval "
8668                        + mWifiConfigManager.wifiDisconnectedShortScanIntervalMilli.get()
8669                        + " mLegacyPnoEnabled= " + mLegacyPnoEnabled
8670                        + " screenOn=" + mScreenOn);
8671            }
8672
8673            // Make sure we disconnect: we enter this state prior to connecting to a new
8674            // network, waiting for either a DISCONNECT event or a SUPPLICANT_STATE_CHANGE
8675            // event which in this case will be indicating that supplicant started to associate.
8676            // In some cases supplicant doesn't ignore the connect requests (it might not
8677            // find the target SSID in its cache),
8678            // Therefore we end up stuck that state, hence the need for the watchdog.
8679            disconnectingWatchdogCount++;
8680            logd("Start Disconnecting Watchdog " + disconnectingWatchdogCount);
8681            sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER,
8682                    disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC);
8683        }
8684
8685        @Override
8686        public boolean processMessage(Message message) {
8687            logStateAndMessage(message, this);
8688            switch (message.what) {
8689                case CMD_SET_OPERATIONAL_MODE:
8690                    if (message.arg1 != CONNECT_MODE) {
8691                        deferMessage(message);
8692                    }
8693                    break;
8694                case CMD_START_SCAN:
8695                    deferMessage(message);
8696                    return HANDLED;
8697                case CMD_DISCONNECTING_WATCHDOG_TIMER:
8698                    if (disconnectingWatchdogCount == message.arg1) {
8699                        if (DBG) log("disconnecting watchdog! -> disconnect");
8700                        handleNetworkDisconnect();
8701                        transitionTo(mDisconnectedState);
8702                    }
8703                    break;
8704                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
8705                    /**
8706                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
8707                     * we have missed the network disconnection, transition to mDisconnectedState
8708                     * and handle the rest of the events there
8709                     */
8710                    deferMessage(message);
8711                    handleNetworkDisconnect();
8712                    transitionTo(mDisconnectedState);
8713                    break;
8714                default:
8715                    return NOT_HANDLED;
8716            }
8717            return HANDLED;
8718        }
8719    }
8720
8721    class DisconnectedState extends State {
8722        @Override
8723        public void enter() {
8724            // We dont scan frequently if this is a temporary disconnect
8725            // due to p2p
8726            if (mTemporarilyDisconnectWifi) {
8727                mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
8728                return;
8729            }
8730
8731            if (PDBG) {
8732                logd(" Enter DisconnectedState scan interval "
8733                        + mWifiConfigManager.wifiDisconnectedShortScanIntervalMilli.get()
8734                        + " mLegacyPnoEnabled= " + mLegacyPnoEnabled
8735                        + " screenOn=" + mScreenOn
8736                        + " useGscan=" + mHalBasedPnoDriverSupported + "/"
8737                        + mWifiConfigManager.enableHalBasedPno.get());
8738            }
8739
8740            /** clear the roaming state, if we were roaming, we failed */
8741            mAutoRoaming = false;
8742
8743            if (useHalBasedAutoJoinOffload()) {
8744                startGScanDisconnectedModeOffload("disconnectedEnter");
8745            } else {
8746                if (mScreenOn) {
8747                    /**
8748                     * screen lit and => start scan immediately
8749                     */
8750                    startScan(UNKNOWN_SCAN_SOURCE, 0, null, null);
8751                } else {
8752                    /**
8753                     * screen dark and PNO supported => scan alarm disabled
8754                     */
8755                    if (mBackgroundScanSupported) {
8756                        /* If a regular scan result is pending, do not initiate background
8757                         * scan until the scan results are returned. This is needed because
8758                        * initiating a background scan will cancel the regular scan and
8759                        * scan results will not be returned until background scanning is
8760                        * cleared
8761                        */
8762                        if (!mIsScanOngoing) {
8763                            enableBackgroundScan(true);
8764                        }
8765                    } else {
8766                        setScanAlarm(true);
8767                    }
8768                }
8769            }
8770
8771            /**
8772             * If we have no networks saved, the supplicant stops doing the periodic scan.
8773             * The scans are useful to notify the user of the presence of an open network.
8774             * Note that these are not wake up scans.
8775             */
8776            if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
8777                    && mWifiConfigManager.getConfiguredNetworks().size() == 0) {
8778                sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
8779                        ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
8780            }
8781
8782            mDisconnectedTimeStamp = System.currentTimeMillis();
8783            mDisconnectedPnoAlarmCount = 0;
8784        }
8785        @Override
8786        public boolean processMessage(Message message) {
8787            boolean ret = HANDLED;
8788
8789            logStateAndMessage(message, this);
8790
8791            switch (message.what) {
8792                case CMD_NO_NETWORKS_PERIODIC_SCAN:
8793                    if (mP2pConnected.get()) break;
8794                    if (mNoNetworksPeriodicScan != 0 && message.arg1 == mPeriodicScanToken &&
8795                            mWifiConfigManager.getConfiguredNetworks().size() == 0) {
8796                        startScan(UNKNOWN_SCAN_SOURCE, -1, null, null);
8797                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
8798                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
8799                    }
8800                    break;
8801                case WifiManager.FORGET_NETWORK:
8802                case CMD_REMOVE_NETWORK:
8803                case CMD_REMOVE_APP_CONFIGURATIONS:
8804                case CMD_REMOVE_USER_CONFIGURATIONS:
8805                    // Set up a delayed message here. After the forget/remove is handled
8806                    // the handled delayed message will determine if there is a need to
8807                    // scan and continue
8808                    sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
8809                                ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
8810                    ret = NOT_HANDLED;
8811                    break;
8812                case CMD_SET_OPERATIONAL_MODE:
8813                    if (message.arg1 != CONNECT_MODE) {
8814                        mOperationalMode = message.arg1;
8815
8816                        mWifiConfigManager.disableAllNetworks();
8817                        if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
8818                            mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
8819                            setWifiState(WIFI_STATE_DISABLED);
8820                        }
8821                        transitionTo(mScanModeState);
8822                    }
8823                    mWifiConfigManager.
8824                            setAndEnableLastSelectedConfiguration(
8825                                    WifiConfiguration.INVALID_NETWORK_ID);
8826                    break;
8827                    /* Ignore network disconnect */
8828                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
8829                    // Interpret this as an L2 connection failure
8830                    break;
8831                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
8832                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
8833                    if (DBG) {
8834                        logd("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state +
8835                                " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state)
8836                                + " debouncing=" + linkDebouncing);
8837                    }
8838                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
8839                    /* ConnectModeState does the rest of the handling */
8840                    ret = NOT_HANDLED;
8841                    break;
8842                case CMD_START_SCAN:
8843                    if (!checkOrDeferScanAllowed(message)) {
8844                        // The scan request was rescheduled
8845                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED;
8846                        return HANDLED;
8847                    }
8848                    if (message.arg1 == SCAN_ALARM_SOURCE) {
8849                        // Check if the CMD_START_SCAN message is obsolete (and thus if it should
8850                        // not be processed) and restart the scan
8851                        int period =
8852                                mWifiConfigManager.wifiDisconnectedShortScanIntervalMilli.get();
8853                        if (mP2pConnected.get()) {
8854                            period = (int) mFacade.getLongSetting(mContext,
8855                                    Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
8856                                    period);
8857                        }
8858                        if (!checkAndRestartDelayedScan(message.arg2,
8859                                true, period, null, null)) {
8860                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
8861                            logd("Disconnected CMD_START_SCAN source "
8862                                    + message.arg1
8863                                    + " " + message.arg2 + ", " + mDelayedScanCounter
8864                                    + " -> obsolete");
8865                            return HANDLED;
8866                        }
8867                        /* Disable background scan temporarily during a regular scan */
8868                        enableBackgroundScan(false);
8869                        handleScanRequest(message);
8870                        ret = HANDLED;
8871                    } else {
8872
8873                        /*
8874                         * The SCAN request is not handled in this state and
8875                         * would eventually might/will get handled in the
8876                         * parent's state. The PNO, if already enabled had to
8877                         * get disabled before the SCAN trigger. Hence, stop
8878                         * the PNO if already enabled in this state, though the
8879                         * SCAN request is not handled(PNO disable before the
8880                         * SCAN trigger in any other state is not the right
8881                         * place to issue).
8882                         */
8883
8884                        enableBackgroundScan(false);
8885                        ret = NOT_HANDLED;
8886                    }
8887                    break;
8888                case CMD_RESTART_AUTOJOIN_OFFLOAD:
8889                    if ( (int)message.arg2 < mRestartAutoJoinOffloadCounter ) {
8890                        messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
8891                        return HANDLED;
8892                    }
8893                    /* If we are still in Disconnected state after having discovered a valid
8894                     * network this means autojoin didnt managed to associate to the network,
8895                     * then restart PNO so as we will try associating to it again.
8896                     */
8897                    if (useHalBasedAutoJoinOffload()) {
8898                        if (mGScanStartTimeMilli == 0) {
8899                            // If offload is not started, then start it...
8900                            startGScanDisconnectedModeOffload("disconnectedRestart");
8901                        } else {
8902                            // If offload is already started, then check if we need to increase
8903                            // the scan period and restart the Gscan
8904                            long now = System.currentTimeMillis();
8905                            if (mGScanStartTimeMilli != 0 && now > mGScanStartTimeMilli
8906                                    && ((now - mGScanStartTimeMilli)
8907                                    > DISCONNECTED_SHORT_SCANS_DURATION_MILLI)
8908                                    && (mGScanPeriodMilli
8909                                    < mWifiConfigManager
8910                                    .wifiDisconnectedLongScanIntervalMilli.get()))
8911                            {
8912                                startDisconnectedGScan("disconnected restart gscan");
8913                            }
8914                        }
8915                    } else {
8916                        // If we are still disconnected for a short while after having found a
8917                        // network thru PNO, then something went wrong, and for some reason we
8918                        // couldn't join this network.
8919                        // It might be due to a SW bug in supplicant or the wifi stack, or an
8920                        // interoperability issue, or we try to join a bad bss and failed
8921                        // In that case we want to restart pno so as to make sure that we will
8922                        // attempt again to join that network.
8923                        if (!mScreenOn && !mIsScanOngoing && mBackgroundScanSupported) {
8924                            enableBackgroundScan(false);
8925                            enableBackgroundScan(true);
8926                        }
8927                        return HANDLED;
8928                    }
8929                    break;
8930                case WifiMonitor.SCAN_RESULTS_EVENT:
8931                case WifiMonitor.SCAN_FAILED_EVENT:
8932                    /* Re-enable background scan when a pending scan result is received */
8933                    if (!mScreenOn && mIsScanOngoing
8934                            && mBackgroundScanSupported
8935                            && !useHalBasedAutoJoinOffload()) {
8936                        enableBackgroundScan(true);
8937                    } else if (!mScreenOn
8938                            && !mIsScanOngoing
8939                            && mBackgroundScanSupported
8940                            && !useHalBasedAutoJoinOffload()) {
8941                        // We receive scan results from legacy PNO, hence restart the PNO alarm
8942                        int delay;
8943                        if (mDisconnectedPnoAlarmCount < 1) {
8944                            delay = 30 * 1000;
8945                        } else if (mDisconnectedPnoAlarmCount < 3) {
8946                            delay = 60 * 1000;
8947                        } else {
8948                            delay = 360 * 1000;
8949                        }
8950                        mDisconnectedPnoAlarmCount++;
8951                        if (VDBG) {
8952                            logd("Starting PNO alarm " + delay);
8953                        }
8954                        mAlarmManager.set(AlarmManager.RTC_WAKEUP,
8955                                System.currentTimeMillis() + delay,
8956                                mPnoIntent);
8957                    }
8958                    /* Handled in parent state */
8959                    ret = NOT_HANDLED;
8960                    break;
8961                case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED:
8962                    NetworkInfo info = (NetworkInfo) message.obj;
8963                    mP2pConnected.set(info.isConnected());
8964                    if (mP2pConnected.get()) {
8965                        int defaultInterval = mContext.getResources().getInteger(
8966                                R.integer.config_wifi_scan_interval_p2p_connected);
8967                        long scanIntervalMs = mFacade.getLongSetting(mContext,
8968                                Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
8969                                defaultInterval);
8970                        mWifiNative.setScanInterval((int) scanIntervalMs/1000);
8971                    } else if (mWifiConfigManager.getConfiguredNetworks().size() == 0) {
8972                        if (DBG) log("Turn on scanning after p2p disconnected");
8973                        sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
8974                                    ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
8975                    } else {
8976                        // If P2P is not connected and there are saved networks, then restart
8977                        // scanning at the normal period. This is necessary because scanning might
8978                        // have been disabled altogether if WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS
8979                        // was set to zero.
8980                        if (useHalBasedAutoJoinOffload()) {
8981                            startGScanDisconnectedModeOffload("p2pRestart");
8982                        } else {
8983                            startDelayedScan(
8984                                    mWifiConfigManager.wifiDisconnectedShortScanIntervalMilli.get(),
8985                                    null, null);
8986                        }
8987                    }
8988                    break;
8989                case CMD_RECONNECT:
8990                case CMD_REASSOCIATE:
8991                    if (mTemporarilyDisconnectWifi) {
8992                        // Drop a third party reconnect/reassociate if STA is
8993                        // temporarily disconnected for p2p
8994                        break;
8995                    } else {
8996                        // ConnectModeState handles it
8997                        ret = NOT_HANDLED;
8998                    }
8999                    break;
9000                case CMD_SCREEN_STATE_CHANGED:
9001                    handleScreenStateChanged(message.arg1 != 0);
9002                    break;
9003                default:
9004                    ret = NOT_HANDLED;
9005            }
9006            return ret;
9007        }
9008
9009        @Override
9010        public void exit() {
9011            mDisconnectedPnoAlarmCount = 0;
9012            /* No need for a background scan upon exit from a disconnected state */
9013            enableBackgroundScan(false);
9014            setScanAlarm(false);
9015            mAlarmManager.cancel(mPnoIntent);
9016        }
9017    }
9018
9019    class WpsRunningState extends State {
9020        // Tracks the source to provide a reply
9021        private Message mSourceMessage;
9022        @Override
9023        public void enter() {
9024            mSourceMessage = Message.obtain(getCurrentMessage());
9025        }
9026        @Override
9027        public boolean processMessage(Message message) {
9028            logStateAndMessage(message, this);
9029
9030            switch (message.what) {
9031                case WifiMonitor.WPS_SUCCESS_EVENT:
9032                    // Ignore intermediate success, wait for full connection
9033                    break;
9034                case WifiMonitor.NETWORK_CONNECTION_EVENT:
9035                    replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
9036                    mSourceMessage.recycle();
9037                    mSourceMessage = null;
9038                    deferMessage(message);
9039                    transitionTo(mDisconnectedState);
9040                    break;
9041                case WifiMonitor.WPS_OVERLAP_EVENT:
9042                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
9043                            WifiManager.WPS_OVERLAP_ERROR);
9044                    mSourceMessage.recycle();
9045                    mSourceMessage = null;
9046                    transitionTo(mDisconnectedState);
9047                    break;
9048                case WifiMonitor.WPS_FAIL_EVENT:
9049                    // Arg1 has the reason for the failure
9050                    if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
9051                        replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
9052                        mSourceMessage.recycle();
9053                        mSourceMessage = null;
9054                        transitionTo(mDisconnectedState);
9055                    } else {
9056                        if (DBG) log("Ignore unspecified fail event during WPS connection");
9057                    }
9058                    break;
9059                case WifiMonitor.WPS_TIMEOUT_EVENT:
9060                    replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
9061                            WifiManager.WPS_TIMED_OUT);
9062                    mSourceMessage.recycle();
9063                    mSourceMessage = null;
9064                    transitionTo(mDisconnectedState);
9065                    break;
9066                case WifiManager.START_WPS:
9067                    replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
9068                    break;
9069                case WifiManager.CANCEL_WPS:
9070                    if (mWifiNative.cancelWps()) {
9071                        replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
9072                    } else {
9073                        replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR);
9074                    }
9075                    transitionTo(mDisconnectedState);
9076                    break;
9077                /**
9078                 * Defer all commands that can cause connections to a different network
9079                 * or put the state machine out of connect mode
9080                 */
9081                case CMD_STOP_DRIVER:
9082                case CMD_SET_OPERATIONAL_MODE:
9083                case WifiManager.CONNECT_NETWORK:
9084                case CMD_ENABLE_NETWORK:
9085                case CMD_RECONNECT:
9086                case CMD_REASSOCIATE:
9087                case CMD_ENABLE_ALL_NETWORKS:
9088                    deferMessage(message);
9089                    break;
9090                case CMD_AUTO_CONNECT:
9091                case CMD_AUTO_ROAM:
9092                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
9093                    return HANDLED;
9094                case CMD_START_SCAN:
9095                    messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
9096                    return HANDLED;
9097                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
9098                    if (DBG) log("Network connection lost");
9099                    handleNetworkDisconnect();
9100                    break;
9101                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
9102                    if (DBG) log("Ignore Assoc reject event during WPS Connection");
9103                    break;
9104                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
9105                    // Disregard auth failure events during WPS connection. The
9106                    // EAP sequence is retried several times, and there might be
9107                    // failures (especially for wps pin). We will get a WPS_XXX
9108                    // event at the end of the sequence anyway.
9109                    if (DBG) log("Ignore auth failure during WPS connection");
9110                    break;
9111                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
9112                    // Throw away supplicant state changes when WPS is running.
9113                    // We will start getting supplicant state changes once we get
9114                    // a WPS success or failure
9115                    break;
9116                default:
9117                    return NOT_HANDLED;
9118            }
9119            return HANDLED;
9120        }
9121
9122        @Override
9123        public void exit() {
9124            mWifiConfigManager.enableAllNetworks();
9125            mWifiConfigManager.loadConfiguredNetworks();
9126        }
9127    }
9128
9129    class SoftApState extends State {
9130        private SoftApManager mSoftApManager;
9131
9132        private class SoftApListener implements SoftApManager.Listener {
9133            @Override
9134            public void onStateChanged(int state, int reason) {
9135                if (state == WIFI_AP_STATE_DISABLED) {
9136                    sendMessage(CMD_AP_STOPPED);
9137                } else if (state == WIFI_AP_STATE_FAILED) {
9138                    sendMessage(CMD_START_AP_FAILURE);
9139                }
9140
9141                setWifiApState(state, reason);
9142            }
9143        }
9144
9145        @Override
9146        public void enter() {
9147            final Message message = getCurrentMessage();
9148            if (message.what == CMD_START_AP) {
9149                WifiConfiguration config = (WifiConfiguration) message.obj;
9150
9151                if (config == null) {
9152                    /**
9153                     * Configuration not provided in the command, fallback to use the current
9154                     * configuration.
9155                     */
9156                    config = mWifiApConfigStore.getApConfiguration();
9157                } else {
9158                    /* Update AP configuration. */
9159                    mWifiApConfigStore.setApConfiguration(config);
9160                }
9161
9162                checkAndSetConnectivityInstance();
9163                mSoftApManager = mFacade.makeSoftApManager(
9164                        mContext, getHandler().getLooper(), mWifiNative, mNwService,
9165                        mCm, getCurrentCountryCode(),
9166                        mWifiApConfigStore.getAllowed2GChannel(),
9167                        new SoftApListener());
9168                mSoftApManager.start(config);
9169            } else {
9170                throw new RuntimeException("Illegal transition to SoftApState: " + message);
9171            }
9172        }
9173
9174        @Override
9175        public void exit() {
9176            mSoftApManager = null;
9177        }
9178
9179        @Override
9180        public boolean processMessage(Message message) {
9181            logStateAndMessage(message, this);
9182
9183            switch(message.what) {
9184                case CMD_START_AP:
9185                    /* Ignore start command when it is starting/started. */
9186                    break;
9187                case CMD_STOP_AP:
9188                    mSoftApManager.stop();
9189                    break;
9190                case CMD_START_AP_FAILURE:
9191                    transitionTo(mInitialState);
9192                    break;
9193                case CMD_AP_STOPPED:
9194                    transitionTo(mInitialState);
9195                    break;
9196                default:
9197                    return NOT_HANDLED;
9198            }
9199            return HANDLED;
9200        }
9201    }
9202
9203    /**
9204     * State machine initiated requests can have replyTo set to null indicating
9205     * there are no recepients, we ignore those reply actions.
9206     */
9207    private void replyToMessage(Message msg, int what) {
9208        if (msg.replyTo == null) return;
9209        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
9210        mReplyChannel.replyToMessage(msg, dstMsg);
9211    }
9212
9213    private void replyToMessage(Message msg, int what, int arg1) {
9214        if (msg.replyTo == null) return;
9215        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
9216        dstMsg.arg1 = arg1;
9217        mReplyChannel.replyToMessage(msg, dstMsg);
9218    }
9219
9220    private void replyToMessage(Message msg, int what, Object obj) {
9221        if (msg.replyTo == null) return;
9222        Message dstMsg = obtainMessageWithWhatAndArg2(msg, what);
9223        dstMsg.obj = obj;
9224        mReplyChannel.replyToMessage(msg, dstMsg);
9225    }
9226
9227    /**
9228     * arg2 on the source message has a unique id that needs to be retained in replies
9229     * to match the request
9230     * <p>see WifiManager for details
9231     */
9232    private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
9233        Message msg = Message.obtain();
9234        msg.what = what;
9235        msg.arg2 = srcMsg.arg2;
9236        return msg;
9237    }
9238
9239    /**
9240     * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
9241     * @param msg Must have a WifiConfiguration obj to succeed
9242     */
9243    private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
9244            WifiConfiguration config) {
9245        if (config != null && config.preSharedKey != null) {
9246            Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
9247            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
9248            intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
9249                    wifiCredentialEventType);
9250            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT,
9251                    android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE);
9252        }
9253    }
9254
9255    private static int parseHex(char ch) {
9256        if ('0' <= ch && ch <= '9') {
9257            return ch - '0';
9258        } else if ('a' <= ch && ch <= 'f') {
9259            return ch - 'a' + 10;
9260        } else if ('A' <= ch && ch <= 'F') {
9261            return ch - 'A' + 10;
9262        } else {
9263            throw new NumberFormatException("" + ch + " is not a valid hex digit");
9264        }
9265    }
9266
9267    private byte[] parseHex(String hex) {
9268        /* This only works for good input; don't throw bad data at it */
9269        if (hex == null) {
9270            return new byte[0];
9271        }
9272
9273        if (hex.length() % 2 != 0) {
9274            throw new NumberFormatException(hex + " is not a valid hex string");
9275        }
9276
9277        byte[] result = new byte[(hex.length())/2 + 1];
9278        result[0] = (byte) ((hex.length())/2);
9279        for (int i = 0, j = 1; i < hex.length(); i += 2, j++) {
9280            int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1));
9281            byte b = (byte) (val & 0xFF);
9282            result[j] = b;
9283        }
9284
9285        return result;
9286    }
9287
9288    private static String makeHex(byte[] bytes) {
9289        StringBuilder sb = new StringBuilder();
9290        for (byte b : bytes) {
9291            sb.append(String.format("%02x", b));
9292        }
9293        return sb.toString();
9294    }
9295
9296    private static String makeHex(byte[] bytes, int from, int len) {
9297        StringBuilder sb = new StringBuilder();
9298        for (int i = 0; i < len; i++) {
9299            sb.append(String.format("%02x", bytes[from+i]));
9300        }
9301        return sb.toString();
9302    }
9303
9304    private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) {
9305
9306        int len = array1.length + array2.length + array3.length;
9307
9308        if (array1.length != 0) {
9309            len++;                      /* add another byte for size */
9310        }
9311
9312        if (array2.length != 0) {
9313            len++;                      /* add another byte for size */
9314        }
9315
9316        if (array3.length != 0) {
9317            len++;                      /* add another byte for size */
9318        }
9319
9320        byte[] result = new byte[len];
9321
9322        int index = 0;
9323        if (array1.length != 0) {
9324            result[index] = (byte) (array1.length & 0xFF);
9325            index++;
9326            for (byte b : array1) {
9327                result[index] = b;
9328                index++;
9329            }
9330        }
9331
9332        if (array2.length != 0) {
9333            result[index] = (byte) (array2.length & 0xFF);
9334            index++;
9335            for (byte b : array2) {
9336                result[index] = b;
9337                index++;
9338            }
9339        }
9340
9341        if (array3.length != 0) {
9342            result[index] = (byte) (array3.length & 0xFF);
9343            index++;
9344            for (byte b : array3) {
9345                result[index] = b;
9346                index++;
9347            }
9348        }
9349        return result;
9350    }
9351
9352    private static byte[] concatHex(byte[] array1, byte[] array2) {
9353
9354        int len = array1.length + array2.length;
9355
9356        byte[] result = new byte[len];
9357
9358        int index = 0;
9359        if (array1.length != 0) {
9360            for (byte b : array1) {
9361                result[index] = b;
9362                index++;
9363            }
9364        }
9365
9366        if (array2.length != 0) {
9367            for (byte b : array2) {
9368                result[index] = b;
9369                index++;
9370            }
9371        }
9372
9373        return result;
9374    }
9375
9376    void handleGsmAuthRequest(SimAuthRequestData requestData) {
9377        if (targetWificonfiguration == null
9378                || targetWificonfiguration.networkId == requestData.networkId) {
9379            logd("id matches targetWifiConfiguration");
9380        } else {
9381            logd("id does not match targetWifiConfiguration");
9382            return;
9383        }
9384
9385        TelephonyManager tm = (TelephonyManager)
9386                mContext.getSystemService(Context.TELEPHONY_SERVICE);
9387
9388        if (tm != null) {
9389            StringBuilder sb = new StringBuilder();
9390            for (String challenge : requestData.data) {
9391
9392                if (challenge == null || challenge.isEmpty())
9393                    continue;
9394                logd("RAND = " + challenge);
9395
9396                byte[] rand = null;
9397                try {
9398                    rand = parseHex(challenge);
9399                } catch (NumberFormatException e) {
9400                    loge("malformed challenge");
9401                    continue;
9402                }
9403
9404                String base64Challenge = android.util.Base64.encodeToString(
9405                        rand, android.util.Base64.NO_WRAP);
9406                /*
9407                 * First, try with appType = 2 => USIM according to
9408                 * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx
9409                 */
9410                int appType = 2;
9411                String tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
9412                if (tmResponse == null) {
9413                    /* Then, in case of failure, issue may be due to sim type, retry as a simple sim
9414                     * appType = 1 => SIM
9415                     */
9416                    appType = 1;
9417                    tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
9418                }
9419                logv("Raw Response - " + tmResponse);
9420
9421                if (tmResponse != null && tmResponse.length() > 4) {
9422                    byte[] result = android.util.Base64.decode(tmResponse,
9423                            android.util.Base64.DEFAULT);
9424                    logv("Hex Response -" + makeHex(result));
9425                    int sres_len = result[0];
9426                    String sres = makeHex(result, 1, sres_len);
9427                    int kc_offset = 1+sres_len;
9428                    int kc_len = result[kc_offset];
9429                    String kc = makeHex(result, 1 + kc_offset, kc_len);
9430                    sb.append(":" + kc + ":" + sres);
9431                    logv("kc:" + kc + " sres:" + sres);
9432
9433                    String response = sb.toString();
9434                    logv("Supplicant Response -" + response);
9435                    mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response);
9436                } else {
9437                    loge("bad response - " + tmResponse);
9438                    mWifiNative.simAuthFailedResponse(requestData.networkId);
9439                }
9440            }
9441
9442        } else {
9443            loge("could not get telephony manager");
9444            mWifiNative.simAuthFailedResponse(requestData.networkId);
9445        }
9446    }
9447
9448    void handle3GAuthRequest(SimAuthRequestData requestData) {
9449        StringBuilder sb = new StringBuilder();
9450        byte[] rand = null;
9451        byte[] authn = null;
9452        String res_type = "UMTS-AUTH";
9453
9454        if (targetWificonfiguration == null
9455                || targetWificonfiguration.networkId == requestData.networkId) {
9456            logd("id matches targetWifiConfiguration");
9457        } else {
9458            logd("id does not match targetWifiConfiguration");
9459            return;
9460        }
9461        if (requestData.data.length == 2) {
9462            try {
9463                rand = parseHex(requestData.data[0]);
9464                authn = parseHex(requestData.data[1]);
9465            } catch (NumberFormatException e) {
9466                loge("malformed challenge");
9467            }
9468        } else {
9469               loge("malformed challenge");
9470        }
9471
9472        String tmResponse = "";
9473        if (rand != null && authn != null) {
9474            String base64Challenge = android.util.Base64.encodeToString(
9475                    concatHex(rand,authn), android.util.Base64.NO_WRAP);
9476
9477            TelephonyManager tm = (TelephonyManager)
9478                    mContext.getSystemService(Context.TELEPHONY_SERVICE);
9479            if (tm != null) {
9480                int appType = 2; // 2 => USIM
9481                tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge);
9482                logv("Raw Response - " + tmResponse);
9483            } else {
9484                loge("could not get telephony manager");
9485            }
9486        }
9487
9488        boolean good_response = false;
9489        if (tmResponse != null && tmResponse.length() > 4) {
9490            byte[] result = android.util.Base64.decode(tmResponse,
9491                    android.util.Base64.DEFAULT);
9492            loge("Hex Response - " + makeHex(result));
9493            byte tag = result[0];
9494            if (tag == (byte) 0xdb) {
9495                logv("successful 3G authentication ");
9496                int res_len = result[1];
9497                String res = makeHex(result, 2, res_len);
9498                int ck_len = result[res_len + 2];
9499                String ck = makeHex(result, res_len + 3, ck_len);
9500                int ik_len = result[res_len + ck_len + 3];
9501                String ik = makeHex(result, res_len + ck_len + 4, ik_len);
9502                sb.append(":" + ik + ":" + ck + ":" + res);
9503                logv("ik:" + ik + "ck:" + ck + " res:" + res);
9504                good_response = true;
9505            } else if (tag == (byte) 0xdc) {
9506                loge("synchronisation failure");
9507                int auts_len = result[1];
9508                String auts = makeHex(result, 2, auts_len);
9509                res_type = "UMTS-AUTS";
9510                sb.append(":" + auts);
9511                logv("auts:" + auts);
9512                good_response = true;
9513            } else {
9514                loge("bad response - unknown tag = " + tag);
9515            }
9516        } else {
9517            loge("bad response - " + tmResponse);
9518        }
9519
9520        if (good_response) {
9521            String response = sb.toString();
9522            logv("Supplicant Response -" + response);
9523            mWifiNative.simAuthResponse(requestData.networkId, res_type, response);
9524        } else {
9525            mWifiNative.umtsAuthFailedResponse(requestData.networkId);
9526        }
9527    }
9528
9529    public int getCurrentUserId() {
9530        return mCurrentUserId;
9531    }
9532
9533    private boolean isCurrentUserProfile(int userId) {
9534        if (userId == mCurrentUserId) {
9535            return true;
9536        }
9537        final UserInfo parent = mUserManager.getProfileParent(userId);
9538        return parent != null && parent.id == mCurrentUserId;
9539    }
9540
9541    public List<UserInfo> getCurrentUserProfiles() {
9542        return mUserManager.getProfiles(mCurrentUserId);
9543    }
9544
9545    /**
9546     * @param reason reason code from supplicant on network disconnected event
9547     * @return true if this is a suspicious disconnect
9548     */
9549    static boolean unexpectedDisconnectedReason(int reason) {
9550        return reason == 2              // PREV_AUTH_NOT_VALID
9551                || reason == 6          // CLASS2_FRAME_FROM_NONAUTH_STA
9552                || reason == 7          // FRAME_FROM_NONASSOC_STA
9553                || reason == 8          // STA_HAS_LEFT
9554                || reason == 9          // STA_REQ_ASSOC_WITHOUT_AUTH
9555                || reason == 14         // MICHAEL_MIC_FAILURE
9556                || reason == 15         // 4WAY_HANDSHAKE_TIMEOUT
9557                || reason == 16         // GROUP_KEY_UPDATE_TIMEOUT
9558                || reason == 18         // GROUP_CIPHER_NOT_VALID
9559                || reason == 19         // PAIRWISE_CIPHER_NOT_VALID
9560                || reason == 23         // IEEE_802_1X_AUTH_FAILED
9561                || reason == 34;        // DISASSOC_LOW_ACK
9562    }
9563
9564    /**
9565     * Update WifiMetrics before dumping
9566     */
9567    void updateWifiMetrics() {
9568        int numSavedNetworks = mWifiConfigManager.getConfiguredNetworksSize();
9569        int numOpenNetworks = 0;
9570        int numPersonalNetworks = 0;
9571        int numEnterpriseNetworks = 0;
9572        int numNetworksAddedByUser = 0;
9573        int numNetworksAddedByApps = 0;
9574        for (WifiConfiguration config : mWifiConfigManager.getConfiguredNetworks()) {
9575            if (config.allowedAuthAlgorithms.get(WifiConfiguration.AuthAlgorithm.OPEN)) {
9576                numOpenNetworks++;
9577            } else if (config.isEnterprise()) {
9578                numEnterpriseNetworks++;
9579            } else {
9580                numPersonalNetworks++;
9581            }
9582            if (config.selfAdded) {
9583                numNetworksAddedByUser++;
9584            } else {
9585                numNetworksAddedByApps++;
9586            }
9587        }
9588        mWifiMetrics.setNumSavedNetworks(numSavedNetworks);
9589        mWifiMetrics.setNumOpenNetworks(numOpenNetworks);
9590        mWifiMetrics.setNumPersonalNetworks(numPersonalNetworks);
9591        mWifiMetrics.setNumEnterpriseNetworks(numEnterpriseNetworks);
9592        mWifiMetrics.setNumNetworksAddedByUser(numNetworksAddedByUser);
9593        mWifiMetrics.setNumNetworksAddedByApps(numNetworksAddedByApps);
9594
9595        /* <TODO> decide how to access WifiServiecImpl.isLocationEnabled() or if to do it manually
9596        mWifiMetrics.setIsLocationEnabled(Settings.Secure.getInt(
9597                mContext.getContentResolver(),
9598                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF)
9599                != Settings.Secure.LOCATION_MODE_OFF);
9600                */
9601
9602        /* <TODO> decide how statemachine will access WifiSettingsStore
9603        mWifiMetrics.setIsScanningAlwaysEnabled(mSettingsStore.isScanningAlwaysAvailable());
9604         */
9605    }
9606
9607    private static String getLinkPropertiesSummary(LinkProperties lp) {
9608        List<String> attributes = new ArrayList(6);
9609        if (lp.hasIPv4Address()) {
9610            attributes.add("v4");
9611        }
9612        if (lp.hasIPv4DefaultRoute()) {
9613            attributes.add("v4r");
9614        }
9615        if (lp.hasIPv4DnsServer()) {
9616            attributes.add("v4dns");
9617        }
9618        if (lp.hasGlobalIPv6Address()) {
9619            attributes.add("v6");
9620        }
9621        if (lp.hasIPv6DefaultRoute()) {
9622            attributes.add("v6r");
9623        }
9624        if (lp.hasIPv6DnsServer()) {
9625            attributes.add("v6dns");
9626        }
9627
9628        // TODO: Replace with String.join(" ", attributes) once we're fully on JDK 8.
9629        StringBuilder sb = new StringBuilder();
9630        boolean first = true;
9631        for (String attr : attributes) {
9632            if (!first) {
9633                sb.append(" ");
9634            } else {
9635                first = false;
9636            }
9637            sb.append(attr);
9638        }
9639        return sb.toString();
9640    }
9641
9642    /**
9643     * Try to connect to the network of candidate. According to the current connected network, this
9644     * API determines whether no action, disconnect and connect, or roaming.
9645     *
9646     * @param candidate the candidate network to connect to
9647     */
9648    private void tryToConnectToNetwork(WifiConfiguration candidate) {
9649        if (candidate == null) {
9650            if (DBG) {
9651                Log.d(TAG, "Try to connect to null, give up");
9652            }
9653            return;
9654        }
9655
9656        ScanResult scanResultCandidate = candidate.getNetworkSelectionStatus().getCandidate();
9657        if (scanResultCandidate == null) {
9658            Log.e(TAG, "tryToConnectToNetwork: bad candidate. Network:"  + candidate
9659                    + " scanresult: " + scanResultCandidate);
9660            return;
9661        }
9662
9663        String targetBssid = scanResultCandidate.BSSID;
9664        String  targetAssociationId = candidate.SSID + " : " + targetBssid;
9665        if (targetBssid != null && targetBssid.equals(mWifiInfo.getBSSID())) {
9666            if (DBG) {
9667                Log.d(TAG, "tryToConnectToNetwork: Already connect to" + targetAssociationId);
9668            }
9669            return;
9670        }
9671
9672        WifiConfiguration currentConnectedNetwork = mWifiConfigManager
9673                .getWifiConfiguration(mWifiInfo.getNetworkId());
9674        String currentAssociationId = (currentConnectedNetwork == null) ? "Disconnected" :
9675                (mWifiInfo.getSSID() + " : " + mWifiInfo.getBSSID());
9676
9677        if (currentConnectedNetwork != null
9678                && (currentConnectedNetwork.networkId == candidate.networkId
9679                || currentConnectedNetwork.isLinked(candidate))) {
9680            if (DBG) {
9681                Log.d(TAG, "tryToConnectToNetwork: Roaming from " + currentAssociationId + " to "
9682                        + targetAssociationId);
9683            }
9684            sendMessage(CMD_AUTO_ROAM, candidate.networkId, 0, scanResultCandidate);
9685        } else {
9686            if (DBG) {
9687                Log.d(TAG, "tryToConnectToNetwork: Reconnect from " + currentAssociationId + " to "
9688                        + targetAssociationId);
9689            }
9690
9691            sendMessage(CMD_AUTO_CONNECT, candidate.networkId, 0, scanResultCandidate.BSSID);
9692        }
9693    }
9694}
9695