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