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