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