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