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