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