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