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