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