FileDocCategorySizeDatePackage
WifiService.javaAPI DocAndroid 1.5 API73238Wed May 06 22:42:00 BST 2009com.android.server

WifiService

public class WifiService extends IWifiManager.Stub
WifiService handles remote WiFi operation requests by implementing the IWifiManager interface. It also creates a WifiMonitor to listen for Wifi-related events.
hide

Fields Summary
private static final String
TAG
private static final boolean
DBG
private static final Pattern
scanResultPattern
private final android.net.wifi.WifiStateTracker
mWifiStateTracker
private android.content.Context
mContext
private int
mWifiState
private android.app.AlarmManager
mAlarmManager
private android.app.PendingIntent
mIdleIntent
private static final int
IDLE_REQUEST
private boolean
mScreenOff
private boolean
mDeviceIdle
private int
mPluggedType
private final LockList
mLocks
private int
mFullLocksAcquired
private int
mFullLocksReleased
private int
mScanLocksAcquired
private int
mScanLocksReleased
private final com.android.internal.app.IBatteryStats
mBatteryStats
private static final long
DEFAULT_IDLE_MILLIS
See {@link Settings.Gservices#WIFI_IDLE_MS}. This is the default value if a Settings.Gservices value is not present. This timeout value is chosen as the approximate point at which the battery drain caused by Wi-Fi being enabled but not active exceeds the battery drain caused by re-establishing a connection to the mobile data network.
private static final String
WAKELOCK_TAG
private static final int
DEFAULT_WAKELOCK_TIMEOUT
The maximum amount of time to hold the wake lock after a disconnect caused by stopping the driver. Establishing an EDGE connection has been observed to take about 5 seconds under normal circumstances. This provides a bit of extra margin.

See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}. This is the default value if a Settings.Secure value is not present.

private static PowerManager.WakeLock
sDriverStopWakeLock
private static PowerManager.WakeLock
sWakeLock
private static final int
MESSAGE_ENABLE_WIFI
private static final int
MESSAGE_DISABLE_WIFI
private static final int
MESSAGE_STOP_WIFI
private static final int
MESSAGE_START_WIFI
private static final int
MESSAGE_RELEASE_WAKELOCK
private final WifiHandler
mWifiHandler
private final Map
mIsHiddenNetworkPresent
private int
mNumHiddenNetworkPresent
private static final boolean
SET_DUE_TO_A_HIDDEN_NETWORK
private static final int
SCAN_RESULT_CACHE_SIZE
private final LinkedHashMap
mScanResultCache
private static final int
SCAN_RESULT_BUFFER_SIZE
private char[]
mScanResultBuffer
private boolean
mNeedReconfig
private int
mLastEnableUid
private static int[]
sValidRegulatoryChannelCounts
Number of allowed radio frequency channels in various regulatory domains. This list is sufficient for 802.11b/g networks (2.4GHz range).
private static final String
ACTION_DEVICE_IDLE
private final android.content.BroadcastReceiver
mReceiver
Constructors Summary
WifiService(android.content.Context context, android.net.wifi.WifiStateTracker tracker)


        
        mContext = context;
        mWifiStateTracker = tracker;
        mBatteryStats = BatteryStatsService.getService();
        
        /*
         * Initialize the hidden-networks state
         */
        mIsHiddenNetworkPresent = new HashMap<Integer, Boolean>();
        mNumHiddenNetworkPresent = 0;

        mScanResultCache = new LinkedHashMap<String, ScanResult>(
            SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
                /*
                 * Limit the cache size by SCAN_RESULT_CACHE_SIZE
                 * elements
                 */
                public boolean removeEldestEntry(Map.Entry eldest) {
                    return SCAN_RESULT_CACHE_SIZE < this.size();
                }
            };

        mScanResultBuffer = new char [SCAN_RESULT_BUFFER_SIZE];

        HandlerThread wifiThread = new HandlerThread("WifiService");
        wifiThread.start();
        mWifiHandler = new WifiHandler(wifiThread.getLooper());

        mWifiState = WIFI_STATE_DISABLED;
        boolean wifiEnabled = getPersistedWifiEnabled();

        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
        Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
        mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);

        PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
        sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
        sDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
        mWifiStateTracker.setReleaseWakeLockCallback(
                new Runnable() {
                    public void run() {
                        mWifiHandler.removeMessages(MESSAGE_RELEASE_WAKELOCK);
                        synchronized (sDriverStopWakeLock) {
                            if (sDriverStopWakeLock.isHeld()) {
                                sDriverStopWakeLock.release();
                            }
                        }
                    }
                }
        );

        Log.i(TAG, "WifiService starting up with Wi-Fi " +
                (wifiEnabled ? "enabled" : "disabled"));

        mContext.registerReceiver(
                new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        updateWifiState();
                    }
                },
                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));

        setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
    
Methods Summary
public booleanacquireWifiLock(android.os.IBinder binder, int lockMode, java.lang.String tag)

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
        if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) {
            return false;
        }
        WifiLock wifiLock = new WifiLock(lockMode, tag, binder);
        synchronized (mLocks) {
            return acquireWifiLockLocked(wifiLock);
        }
    
private booleanacquireWifiLockLocked(com.android.server.WifiService$WifiLock wifiLock)

        mLocks.addLock(wifiLock);
        
        int uid = Binder.getCallingUid();
        long ident = Binder.clearCallingIdentity();
        try {
            switch(wifiLock.mLockMode) {
            case WifiManager.WIFI_MODE_FULL:
                ++mFullLocksAcquired;
                mBatteryStats.noteFullWifiLockAcquired(uid);
                break;
            case WifiManager.WIFI_MODE_SCAN_ONLY:
                ++mScanLocksAcquired;
                mBatteryStats.noteScanWifiLockAcquired(uid);
                break;
            }
        } catch (RemoteException e) {
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        
        updateWifiState();
        return true;
    
private synchronized voidaddOrUpdateHiddenNetwork(int netId, boolean present)
Updates the netId network presence status if netId is an existing hidden network. If the network does not exist, adds the network.

        if (0 <= netId) {

            // If we are adding a new entry or modifying an existing one
            Boolean isPresent = mIsHiddenNetworkPresent.get(netId);
            if (isPresent == null || isPresent != present) {
                if (present) {
                    incrementHiddentNetworkPresentCounter();
                } else {
                    // If we add a new hidden network, no need to change
                    // the counter (it must be 0)
                    if (isPresent != null) {
                        decrementHiddentNetworkPresentCounter();
                    }
                }
                mIsHiddenNetworkPresent.put(netId, present);
            }
        } else {
            Log.e(TAG, "addOrUpdateHiddenNetwork(): Invalid (negative) network id!");
        }
    
public synchronized intaddOrUpdateNetwork(android.net.wifi.WifiConfiguration config)
see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}

return
the supplicant-assigned identifier for the new or updated network if the operation succeeds, or {@code -1} if it fails

        enforceChangePermission();
        /*
         * If the supplied networkId is -1, we create a new empty
         * network configuration. Otherwise, the networkId should
         * refer to an existing configuration.
         */
        int netId = config.networkId;
        boolean newNetwork = netId == -1;
        boolean doReconfig;
        int currentPriority;
        // networkId of -1 means we want to create a new network
        if (newNetwork) {
            netId = WifiNative.addNetworkCommand();
            if (netId < 0) {
                if (DBG) {
                    Log.d(TAG, "Failed to add a network!");
                }
                return -1;
            }
            doReconfig = true;
        } else {
            String priorityVal = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName);
            currentPriority = -1;
            if (!TextUtils.isEmpty(priorityVal)) {
                try {
                    currentPriority = Integer.parseInt(priorityVal);
                } catch (NumberFormatException ignore) {
                }
            }
            doReconfig = currentPriority != config.priority;
        }
        mNeedReconfig = mNeedReconfig || doReconfig;

        /*
         * If we have hidden networks, we may have to change the scan mode
         */
        if (config.hiddenSSID) {
            // Mark the network as present unless it is disabled
            addOrUpdateHiddenNetwork(
                netId, config.status != WifiConfiguration.Status.DISABLED);
        }

        setVariables: {
            /*
             * Note that if a networkId for a non-existent network
             * was supplied, then the first setNetworkVariableCommand()
             * will fail, so we don't bother to make a separate check
             * for the validity of the ID up front.
             */

            if (config.SSID != null &&
                !WifiNative.setNetworkVariableCommand(
                    netId,
                    WifiConfiguration.ssidVarName,
                    config.SSID)) {
                if (DBG) {
                    Log.d(TAG, "failed to set SSID: "+config.SSID);
                }
                break setVariables;
            }

            if (config.BSSID != null &&
                !WifiNative.setNetworkVariableCommand(
                    netId,
                    WifiConfiguration.bssidVarName,
                    config.BSSID)) {
                if (DBG) {
                    Log.d(TAG, "failed to set BSSID: "+config.BSSID);
                }
                break setVariables;
            }

            String allowedKeyManagementString =
                makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings);
            if (config.allowedKeyManagement.cardinality() != 0 &&
                !WifiNative.setNetworkVariableCommand(
                    netId,
                    WifiConfiguration.KeyMgmt.varName,
                    allowedKeyManagementString)) {
                if (DBG) {
                    Log.d(TAG, "failed to set key_mgmt: "+
                          allowedKeyManagementString);
                }
                break setVariables;
            }

            String allowedProtocolsString =
                makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings);
            if (config.allowedProtocols.cardinality() != 0 &&
                !WifiNative.setNetworkVariableCommand(
                    netId,
                    WifiConfiguration.Protocol.varName,
                    allowedProtocolsString)) {
                if (DBG) {
                    Log.d(TAG, "failed to set proto: "+
                          allowedProtocolsString);
                }
                break setVariables;
            }

            String allowedAuthAlgorithmsString =
                makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings);
            if (config.allowedAuthAlgorithms.cardinality() != 0 &&
                !WifiNative.setNetworkVariableCommand(
                    netId,
                    WifiConfiguration.AuthAlgorithm.varName,
                    allowedAuthAlgorithmsString)) {
                if (DBG) {
                    Log.d(TAG, "failed to set auth_alg: "+
                          allowedAuthAlgorithmsString);
                }
                break setVariables;
            }

            String allowedPairwiseCiphersString =
                makeString(config.allowedPairwiseCiphers, WifiConfiguration.PairwiseCipher.strings);
            if (config.allowedPairwiseCiphers.cardinality() != 0 &&
                !WifiNative.setNetworkVariableCommand(
                    netId,
                    WifiConfiguration.PairwiseCipher.varName,
                    allowedPairwiseCiphersString)) {
                if (DBG) {
                    Log.d(TAG, "failed to set pairwise: "+
                          allowedPairwiseCiphersString);
                }
                break setVariables;
            }

            String allowedGroupCiphersString =
                makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings);
            if (config.allowedGroupCiphers.cardinality() != 0 &&
                !WifiNative.setNetworkVariableCommand(
                    netId,
                    WifiConfiguration.GroupCipher.varName,
                    allowedGroupCiphersString)) {
                if (DBG) {
                    Log.d(TAG, "failed to set group: "+
                          allowedGroupCiphersString);
                }
                break setVariables;
            }

            // Prevent client screw-up by passing in a WifiConfiguration we gave it
            // by preventing "*" as a key.
            if (config.preSharedKey != null && !config.preSharedKey.equals("*") &&
                !WifiNative.setNetworkVariableCommand(
                    netId,
                    WifiConfiguration.pskVarName,
                    config.preSharedKey)) {
                if (DBG) {
                    Log.d(TAG, "failed to set psk: "+config.preSharedKey);
                }
                break setVariables;
            }

            boolean hasSetKey = false;
            if (config.wepKeys != null) {
                for (int i = 0; i < config.wepKeys.length; i++) {
                    // Prevent client screw-up by passing in a WifiConfiguration we gave it
                    // by preventing "*" as a key.
                    if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) {
                        if (!WifiNative.setNetworkVariableCommand(
                                netId,
                                WifiConfiguration.wepKeyVarNames[i],
                                config.wepKeys[i])) {
                            if (DBG) {
                                Log.d(TAG,
                                      "failed to set wep_key"+i+": " +
                                      config.wepKeys[i]);
                            }
                            break setVariables;
                        }
                        hasSetKey = true;
                    }
                }
            }

            if (hasSetKey) {
                if (!WifiNative.setNetworkVariableCommand(
                        netId,
                        WifiConfiguration.wepTxKeyIdxVarName,
                        Integer.toString(config.wepTxKeyIndex))) {
                    if (DBG) {
                        Log.d(TAG,
                              "failed to set wep_tx_keyidx: "+
                              config.wepTxKeyIndex);
                    }
                    break setVariables;
                }
            }

            if (!WifiNative.setNetworkVariableCommand(
                    netId,
                    WifiConfiguration.priorityVarName,
                    Integer.toString(config.priority))) {
                if (DBG) {
                    Log.d(TAG, config.SSID + ": failed to set priority: "
                          +config.priority);
                }
                break setVariables;
            }

            if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand(
                    netId,
                    WifiConfiguration.hiddenSSIDVarName,
                    Integer.toString(config.hiddenSSID ? 1 : 0))) {
                if (DBG) {
                    Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+
                          config.hiddenSSID);
                }
                break setVariables;
            }

            return netId;
        }

        /*
         * For an update, if one of the setNetworkVariable operations fails,
         * we might want to roll back all the changes already made. But the
         * chances are that if anything is going to go wrong, it'll happen
         * the first time we try to set one of the variables.
         */
        if (newNetwork) {
            removeNetwork(netId);
            if (DBG) {
                Log.d(TAG,
                      "Failed to set a network variable, removed network: "
                      + netId);
            }
        }
        return -1;
    
private voiddecrementHiddentNetworkPresentCounter()
Decrements the present (enabled) hidden networks counter. If the counter goes from 1 to 0, changes the scan mode back to passive.

        if (0 < mNumHiddenNetworkPresent) {
            --mNumHiddenNetworkPresent;
            if (0 == mNumHiddenNetworkPresent) {
                // Switch the scan mode to "passive"
                mWifiStateTracker.setScanMode(false, SET_DUE_TO_A_HIDDEN_NETWORK);
            }
        } else {
            Log.e(TAG, "Hidden-network counter invariant violation!");
        }
    
public booleandisableNetwork(int netId)
See {@link android.net.wifi.WifiManager#disableNetwork(int)}

param
netId the integer that identifies the network configuration to the supplicant
return
{@code true} if the operation succeeded

        enforceChangePermission();

        /*
         * If we have hidden networks, we may have to change the scan mode
         */
        updateNetworkIfHidden(netId, false);

        synchronized (mWifiStateTracker) {
            return WifiNative.disableNetworkCommand(netId);
        }
    
public booleandisconnect()
see {@link android.net.wifi.WifiManager#disconnect()}

return
{@code true} if the operation succeeds

        enforceChangePermission();
        synchronized (mWifiStateTracker) {
            return WifiNative.disconnectCommand();
        }
    
protected voiddump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)

        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                != PackageManager.PERMISSION_GRANTED) {
            pw.println("Permission Denial: can't dump WifiService from from pid="
                    + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid());
            return;
        }
        pw.println("Wi-Fi is " + stateName(mWifiState));
        pw.println("Stay-awake conditions: " +
                Settings.System.getInt(mContext.getContentResolver(),
                                       Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
        pw.println();

        pw.println("Internal state:");
        pw.println(mWifiStateTracker);
        pw.println();
        pw.println("Latest scan results:");
        List<ScanResult> scanResults = mWifiStateTracker.getScanResultsList();
        if (scanResults != null && scanResults.size() != 0) {
            pw.println("  BSSID              Frequency   RSSI  Flags             SSID");
            for (ScanResult r : scanResults) {
                pw.printf("  %17s  %9d  %5d  %-16s  %s%n",
                                         r.BSSID,
                                         r.frequency,
                                         r.level,
                                         r.capabilities,
                                         r.SSID == null ? "" : r.SSID);
            }
        }
        pw.println();
        pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
                mScanLocksAcquired + " scan");
        pw.println("Locks released: " + mFullLocksReleased + " full, " +
                mScanLocksReleased + " scan");
        pw.println();
        pw.println("Locks held:");
        mLocks.dump(pw);
    
public booleanenableNetwork(int netId, boolean disableOthers)
See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}

param
netId the integer that identifies the network configuration to the supplicant
param
disableOthers if true, disable all other networks.
return
{@code true} if the operation succeeded

        enforceChangePermission();

        /*
         * If we have hidden networks, we may have to change the scan mode
         */
         synchronized(this) {
             if (disableOthers) {
                 markAllHiddenNetworksButOneAsNotPresent(netId);
             }
             updateNetworkIfHidden(netId, true);
         }

        synchronized (mWifiStateTracker) {
            return WifiNative.enableNetworkCommand(netId, disableOthers);
        }
    
private voidenforceAccessPermission()

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
                                                "WifiService");
    
private voidenforceChangePermission()

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
                                                "WifiService");

    
public java.util.ListgetConfiguredNetworks()
see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}

return
the list of configured networks

        enforceAccessPermission();
        String listStr;
        /*
         * We don't cache the list, because we want to allow
         * for the possibility that the configuration file
         * has been modified through some external means,
         * such as the wpa_cli command line program.
         */
        synchronized (mWifiStateTracker) {
            listStr = WifiNative.listNetworksCommand();
        }
        List<WifiConfiguration> networks =
            new ArrayList<WifiConfiguration>();
        if (listStr == null)
            return networks;

        String[] lines = listStr.split("\n");
        // Skip the first line, which is a header
       for (int i = 1; i < lines.length; i++) {
           String[] result = lines[i].split("\t");
           // network-id | ssid | bssid | flags
           WifiConfiguration config = new WifiConfiguration();
           try {
               config.networkId = Integer.parseInt(result[0]);
           } catch(NumberFormatException e) {
               continue;
           }
           if (result.length > 3) {
               if (result[3].indexOf("[CURRENT]") != -1)
                   config.status = WifiConfiguration.Status.CURRENT;
               else if (result[3].indexOf("[DISABLED]") != -1)
                   config.status = WifiConfiguration.Status.DISABLED;
               else
                   config.status = WifiConfiguration.Status.ENABLED;
           } else
               config.status = WifiConfiguration.Status.ENABLED;
           synchronized (mWifiStateTracker) {
               readNetworkVariables(config);
           }
           networks.add(config);
       }

        return networks;
    
public android.net.wifi.WifiInfogetConnectionInfo()
See {@link android.net.wifi.WifiManager#getConnectionInfo()}

return
the Wi-Fi information, contained in {@link WifiInfo}.

        enforceAccessPermission();
        /*
         * Make sure we have the latest information, by sending
         * a status request to the supplicant.
         */
        return mWifiStateTracker.requestConnectionInfo();
    
public android.net.DhcpInfogetDhcpInfo()
Return the DHCP-assigned addresses from the last successful DHCP request, if any.

return
the DHCP information

        enforceAccessPermission();
        return mWifiStateTracker.getDhcpInfo();
    
android.net.NetworkStateTrackergetNetworkStateTracker()

        return mWifiStateTracker;
    
public intgetNumAllowedChannels()
Return the number of frequency channels that are allowed to be used in the current regulatory domain.

return
the number of allowed channels, or {@code -1} if an error occurs

        int numChannels;

        enforceAccessPermission();
        synchronized (mWifiStateTracker) {
            /*
             * If we can't get the value from the driver (e.g., because
             * Wi-Fi is not currently enabled), get the value from
             * Settings.
             */
            numChannels = WifiNative.getNumAllowedChannelsCommand();
            if (numChannels < 0) {
                numChannels = Settings.Secure.getInt(mContext.getContentResolver(),
                                                     Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
                                                     -1);
            }
        }
        return numChannels;
    
private booleangetPersistedWifiEnabled()

        final ContentResolver cr = mContext.getContentResolver();
        try {
            return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1;
        } catch (Settings.SettingNotFoundException e) {
            Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0);
            return false;
        }
    
public java.util.ListgetScanResults()
Return the results of the most recent access point scan, in the form of a list of {@link ScanResult} objects.

return
the list of results

        enforceAccessPermission();
        String reply;
        synchronized (mWifiStateTracker) {
            reply = WifiNative.scanResultsCommand();
        }
        if (reply == null) {
            return null;
        }

        List<ScanResult> scanList = new ArrayList<ScanResult>();

        int lineCount = 0;

        int replyLen = reply.length();
        // Parse the result string, keeping in mind that the last line does
        // not end with a newline.
        for (int lineBeg = 0, lineEnd = 0; lineEnd <= replyLen; ++lineEnd) {
            if (lineEnd == replyLen || reply.charAt(lineEnd) == '\n") {
                ++lineCount;
                /*
                 * Skip the first line, which is a header
                 */
                if (lineCount == 1) {
                    lineBeg = lineEnd + 1;
                    continue;
                }
                int lineLen = lineEnd - lineBeg;
                if (0 < lineLen && lineLen <= SCAN_RESULT_BUFFER_SIZE) {
                    int scanResultLevel = 0;
                    /*
                     * At most one thread should have access to the buffer at a time!
                     */
                    synchronized(mScanResultBuffer) {
                        boolean parsingScanResultLevel = false;
                        for (int i = lineBeg; i < lineEnd; ++i) {
                            char ch = reply.charAt(i);
                            /*
                             * Assume that the signal level starts with a '-'
                             */
                            if (ch == '-") {
                                /*
                                 * Skip whatever instances of '-' we may have
                                 * after we parse the signal level
                                 */
                                parsingScanResultLevel = (scanResultLevel == 0);
                            } else if (parsingScanResultLevel) {
                                int digit = Character.digit(ch, 10);
                                if (0 <= digit) {
                                    scanResultLevel =
                                        10 * scanResultLevel + digit;
                                    /*
                                     * Replace the signal level number in
                                     * the string with 0's for caching
                                     */
                                    ch = '0";
                                } else {
                                    /*
                                     * Reset the flag if we meet a non-digit
                                     * character
                                     */
                                    parsingScanResultLevel = false;
                                }
                            }
                            mScanResultBuffer[i - lineBeg] = ch;
                        }
                        if (scanResultLevel != 0) {
                            ScanResult scanResult = parseScanResult(
                                new String(mScanResultBuffer, 0, lineLen));
                            if (scanResult != null) {
                              scanResult.level = -scanResultLevel;
                              scanList.add(scanResult);
                            }
                        } else if (DBG) {
                            Log.w(TAG,
                                  "ScanResult.level=0: misformatted scan result?");
                        }
                    }
                } else if (0 < lineLen) {
                    if (DBG) {
                        Log.w(TAG, "Scan result line is too long: " +
                              (lineEnd - lineBeg) + ", skipping the line!");
                    }
                }
                lineBeg = lineEnd + 1;
            }
        }
        mWifiStateTracker.setScanResultsList(scanList);
        return scanList;
    
public int[]getValidChannelCounts()
Return the list of valid values for the number of allowed radio channels for various regulatory domains.

return
the list of channel counts

        enforceAccessPermission();
        return sValidRegulatoryChannelCounts;
    
public intgetWifiEnabledState()
see {@link WifiManager#getWifiState()}

return
One of {@link WifiManager#WIFI_STATE_DISABLED}, {@link WifiManager#WIFI_STATE_DISABLING}, {@link WifiManager#WIFI_STATE_ENABLED}, {@link WifiManager#WIFI_STATE_ENABLING}, {@link WifiManager#WIFI_STATE_UNKNOWN}

        enforceAccessPermission();
        return mWifiState;
    
private voidincrementHiddentNetworkPresentCounter()
Increments the present (enabled) hidden networks counter. If the counter value goes from 0 to 1, changes the scan mode to active.

        ++mNumHiddenNetworkPresent;
        if (1 == mNumHiddenNetworkPresent) {
            // Switch the scan mode to "active"
            mWifiStateTracker.setScanMode(true, SET_DUE_TO_A_HIDDEN_NETWORK);
        }
    
private synchronized voidinitializeHiddenNetworksState()
Initializes the hidden networks state. Must be called when we enable Wi-Fi.

        // First, reset the state
        resetHiddenNetworksState();

        // ... then add networks that are marked as hidden
        List<WifiConfiguration> networks = getConfiguredNetworks();
        if (!networks.isEmpty()) {
            for (WifiConfiguration config : networks) {
                if (config != null && config.hiddenSSID) {
                    addOrUpdateHiddenNetwork(
                        config.networkId,
                        config.status != WifiConfiguration.Status.DISABLED);
                }
            }

        }
    
private booleanisAirplaneModeOn()
Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is currently on.

return
{@code true} if airplane mode is on.

        return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
    
private booleanisAirplaneSensitive()

        String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
                Settings.System.AIRPLANE_MODE_RADIOS);
        return airplaneModeRadios == null
            || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
    
private synchronized booleanisHiddenNetwork(int netId)
Returns true if netId is an existing hidden network.

        return mIsHiddenNetworkPresent.containsKey(netId);
    
private static intlookupString(java.lang.String string, java.lang.String[] strings)

        int size = strings.length;

        string = string.replace('-", '_");

        for (int i = 0; i < size; i++)
            if (string.equals(strings[i]))
                return i;

        if (DBG) {
            // if we ever get here, we should probably add the
            // value to WifiConfiguration to reflect that it's
            // supported by the WPA supplicant
            Log.w(TAG, "Failed to look-up a string: " + string);
        }

        return -1;
    
private static java.lang.StringmakeString(java.util.BitSet set, java.lang.String[] strings)

        StringBuffer buf = new StringBuffer();
        int nextSetBit = -1;

        /* Make sure all set bits are in [0, strings.length) to avoid
         * going out of bounds on strings.  (Shouldn't happen, but...) */
        set = set.get(0, strings.length);

        while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
            buf.append(strings[nextSetBit].replace('_", '-")).append(' ");
        }

        // remove trailing space
        if (set.cardinality() > 0) {
            buf.setLength(buf.length() - 1);
        }

        return buf.toString();
    
private synchronized voidmarkAllHiddenNetworksButOneAsNotPresent(int netId)
Marks all but netId network as not present.

        for (Map.Entry<Integer, Boolean> entry : mIsHiddenNetworkPresent.entrySet()) {
            if (entry != null) {
                Integer networkId = entry.getKey();
                if (networkId != netId) {
                    updateNetworkIfHidden(
                        networkId, false);
                }
            }
        }
    
android.net.wifi.WifiConfigurationparseScanFlags(java.lang.String flags)
Parse the "flags" field passed back in a scan result by wpa_supplicant, and construct a {@code WifiConfiguration} that describes the encryption, key management, and authenticaion capabilities of the access point.

param
flags the string returned by wpa_supplicant
return
the {@link WifiConfiguration} object, filled in

        WifiConfiguration config = new WifiConfiguration();

        if (flags.length() == 0) {
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
        }
        // ... to be implemented
        return config;
    
private android.net.wifi.ScanResultparseScanResult(java.lang.String line)
Parse the scan result line passed to us by wpa_supplicant (helper).

param
line the line to parse
return
the {@link ScanResult} object

        ScanResult scanResult = null;
        if (line != null) {
            /*
             * Cache implementation (LinkedHashMap) is not synchronized, thus,
             * must synchronized here!
             */
            synchronized (mScanResultCache) {
                scanResult = mScanResultCache.get(line);
                if (scanResult == null) {
                    String[] result = scanResultPattern.split(line);
                    if (3 <= result.length && result.length <= 5) {
                        // bssid | frequency | level | flags | ssid
                        int frequency;
                        int level;
                        try {
                            frequency = Integer.parseInt(result[1]);
                            level = Integer.parseInt(result[2]);
                        } catch (NumberFormatException e) {
                            frequency = 0;
                            level = 0;
                        }

                        /*
                         * The formatting of the results returned by
                         * wpa_supplicant is intended to make the fields
                         * line up nicely when printed,
                         * not to make them easy to parse. So we have to
                         * apply some heuristics to figure out which field
                         * is the SSID and which field is the flags.
                         */
                        String ssid;
                        String flags;
                        if (result.length == 4) {
                            if (result[3].charAt(0) == '[") {
                                flags = result[3];
                                ssid = "";
                            } else {
                                flags = "";
                                ssid = result[3];
                            }
                        } else if (result.length == 5) {
                            flags = result[3];
                            ssid = result[4];
                        } else {
                            // Here, we must have 3 fields: no flags and ssid
                            // set
                            flags = "";
                            ssid = "";
                        }

                        // Do not add scan results that have no SSID set
                        if (0 < ssid.trim().length()) {
                            scanResult =
                                new ScanResult(
                                    ssid, result[0], flags, level, frequency);
                            mScanResultCache.put(line, scanResult);
                        }
                    } else {
                        Log.w(TAG, "Misformatted scan result text with " +
                              result.length + " fields: " + line);
                    }
                }
            }
        }

        return scanResult;
    
private voidpersistWifiEnabled(boolean enabled)

        final ContentResolver cr = mContext.getContentResolver();
        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
    
public booleanpingSupplicant()
see {@link android.net.wifi.WifiManager#pingSupplicant()}

return
{@code true} if the operation succeeds

        enforceChangePermission();
        synchronized (mWifiStateTracker) {
            return WifiNative.pingCommand();
        }
    
private static voidreadNetworkVariables(android.net.wifi.WifiConfiguration config)
Read the variables from the supplicant daemon that are needed to fill in the WifiConfiguration object.

The caller must hold the synchronization monitor.

param
config the {@link WifiConfiguration} object to be filled in.


        int netId = config.networkId;
        if (netId < 0)
            return;

        /*
         * TODO: maybe should have a native method that takes an array of
         * variable names and returns an array of values. But we'd still
         * be doing a round trip to the supplicant daemon for each variable.
         */
        String value;

        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName);
        if (!TextUtils.isEmpty(value)) {
            config.SSID = value;
        } else {
            config.SSID = null;
        }

        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName);
        if (!TextUtils.isEmpty(value)) {
            config.BSSID = value;
        } else {
            config.BSSID = null;
        }

        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName);
        config.priority = -1;
        if (!TextUtils.isEmpty(value)) {
            try {
                config.priority = Integer.parseInt(value);
            } catch (NumberFormatException ignore) {
            }
        }

        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName);
        config.hiddenSSID = false;
        if (!TextUtils.isEmpty(value)) {
            try {
                config.hiddenSSID = Integer.parseInt(value) != 0;
            } catch (NumberFormatException ignore) {
            }
        }

        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName);
        config.wepTxKeyIndex = -1;
        if (!TextUtils.isEmpty(value)) {
            try {
                config.wepTxKeyIndex = Integer.parseInt(value);
            } catch (NumberFormatException ignore) {
            }
        }

        /*
         * Get up to 4 WEP keys. Note that the actual keys are not passed back,
         * just a "*" if the key is set, or the null string otherwise.
         */
        for (int i = 0; i < 4; i++) {
            value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepKeyVarNames[i]);
            if (!TextUtils.isEmpty(value)) {
                config.wepKeys[i] = value;
            } else {
                config.wepKeys[i] = null;
            }
        }

        /*
         * Get the private shared key. Note that the actual keys are not passed back,
         * just a "*" if the key is set, or the null string otherwise.
         */
        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName);
        if (!TextUtils.isEmpty(value)) {
            config.preSharedKey = value;
        } else {
            config.preSharedKey = null;
        }

        value = WifiNative.getNetworkVariableCommand(config.networkId,
                WifiConfiguration.Protocol.varName);
        if (!TextUtils.isEmpty(value)) {
            String vals[] = value.split(" ");
            for (String val : vals) {
                int index =
                    lookupString(val, WifiConfiguration.Protocol.strings);
                if (0 <= index) {
                    config.allowedProtocols.set(index);
                }
            }
        }

        value = WifiNative.getNetworkVariableCommand(config.networkId,
                WifiConfiguration.KeyMgmt.varName);
        if (!TextUtils.isEmpty(value)) {
            String vals[] = value.split(" ");
            for (String val : vals) {
                int index =
                    lookupString(val, WifiConfiguration.KeyMgmt.strings);
                if (0 <= index) {
                    config.allowedKeyManagement.set(index);
                }
            }
        }

        value = WifiNative.getNetworkVariableCommand(config.networkId,
                WifiConfiguration.AuthAlgorithm.varName);
        if (!TextUtils.isEmpty(value)) {
            String vals[] = value.split(" ");
            for (String val : vals) {
                int index =
                    lookupString(val, WifiConfiguration.AuthAlgorithm.strings);
                if (0 <= index) {
                    config.allowedAuthAlgorithms.set(index);
                }
            }
        }

        value = WifiNative.getNetworkVariableCommand(config.networkId,
                WifiConfiguration.PairwiseCipher.varName);
        if (!TextUtils.isEmpty(value)) {
            String vals[] = value.split(" ");
            for (String val : vals) {
                int index =
                    lookupString(val, WifiConfiguration.PairwiseCipher.strings);
                if (0 <= index) {
                    config.allowedPairwiseCiphers.set(index);
                }
            }
        }

        value = WifiNative.getNetworkVariableCommand(config.networkId,
                WifiConfiguration.GroupCipher.varName);
        if (!TextUtils.isEmpty(value)) {
            String vals[] = value.split(" ");
            for (String val : vals) {
                int index =
                    lookupString(val, WifiConfiguration.GroupCipher.strings);
                if (0 <= index) {
                    config.allowedGroupCiphers.set(index);
                }
            }
        }
    
public booleanreassociate()
see {@link android.net.wifi.WifiManager#reassociate()}

return
{@code true} if the operation succeeds

        enforceChangePermission();
        synchronized (mWifiStateTracker) {
            return WifiNative.reassociateCommand();
        }
    
public booleanreconnect()
see {@link android.net.wifi.WifiManager#reconnect()}

return
{@code true} if the operation succeeds

        enforceChangePermission();
        synchronized (mWifiStateTracker) {
            return WifiNative.reconnectCommand();
        }
    
private voidregisterForBroadcasts()

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        intentFilter.addAction(ACTION_DEVICE_IDLE);
        intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
        mContext.registerReceiver(mReceiver, intentFilter);
    
public booleanreleaseWifiLock(android.os.IBinder lock)

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
        synchronized (mLocks) {
            return releaseWifiLockLocked(lock);
        }
    
private booleanreleaseWifiLockLocked(android.os.IBinder lock)

        boolean hadLock;
        
        WifiLock wifiLock = mLocks.removeLock(lock);
        hadLock = (wifiLock != null);

        if (hadLock) {
            int uid = Binder.getCallingUid();
            long ident = Binder.clearCallingIdentity();
            try {
                switch(wifiLock.mLockMode) {
                    case WifiManager.WIFI_MODE_FULL:
                        ++mFullLocksReleased;
                        mBatteryStats.noteFullWifiLockReleased(uid);
                        break;
                    case WifiManager.WIFI_MODE_SCAN_ONLY:
                        ++mScanLocksReleased;
                        mBatteryStats.noteScanWifiLockReleased(uid);
                        break;
                }
            } catch (RemoteException e) {
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
        
        updateWifiState();
        return hadLock;
    
private synchronized voidremoveHiddenNetwork(int netId)
Removes the netId network. For the call to be successful, the network must be hidden.

        if (0 <= netId) {
            Boolean isPresent =
                mIsHiddenNetworkPresent.remove(netId);
            if (isPresent != null) {
                // If we remove an existing hidden network that is not
                // present, no need to change the counter
                if (isPresent) {
                    decrementHiddentNetworkPresentCounter();
                }
            } else {
                if (DBG) {
                    Log.d(TAG, "removeHiddenNetwork(): Removing a non-existent network!");
                }
            }
        } else {
            Log.e(TAG, "removeHiddenNetwork(): Invalid (negative) network id!");
        }
    
public booleanremoveNetwork(int netId)
See {@link android.net.wifi.WifiManager#removeNetwork(int)}

param
netId the integer that identifies the network configuration to the supplicant
return
{@code true} if the operation succeeded

        enforceChangePermission();

        /*
         * If we have hidden networks, we may have to change the scan mode
         */
        removeNetworkIfHidden(netId);

        return mWifiStateTracker.removeNetwork(netId);
    
private synchronized voidremoveNetworkIfHidden(int netId)
Removes the netId network if it is hidden (being kept track of).

        if (isHiddenNetwork(netId)) {
            removeHiddenNetwork(netId);
        }
    
private synchronized voidresetHiddenNetworksState()
Resets the hidden networks state.

        mNumHiddenNetworkPresent = 0;
        mIsHiddenNetworkPresent.clear();
    
public booleansaveConfiguration()
Tell the supplicant to persist the current list of configured networks.

return
{@code true} if the operation succeeded

        boolean result;
        enforceChangePermission();
        synchronized (mWifiStateTracker) {
            result = WifiNative.saveConfigCommand();
            if (result && mNeedReconfig) {
                mNeedReconfig = false;
                result = WifiNative.reloadConfigCommand();

                if (result) {
                    Intent intent = new Intent(WifiManager.NETWORK_IDS_CHANGED_ACTION);
                    mContext.sendBroadcast(intent);
                }
            }
        }
        return result;
    
private voidsendEnableMessage(boolean enable, boolean persist, int uid)


            
        Message msg = Message.obtain(mWifiHandler,
                                     (enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI),
                                     (persist ? 1 : 0), uid);
        msg.sendToTarget();
    
private voidsendStartMessage(boolean scanOnlyMode)

        Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget();
    
public booleansetNumAllowedChannels(int numChannels)
Set the number of radio frequency channels that are allowed to be used in the current regulatory domain. This method should be used only if the correct number of channels cannot be determined automatically for some reason. If the operation is successful, the new value is persisted as a Secure setting.

param
numChannels the number of allowed channels. Must be greater than 0 and less than or equal to 16.
return
{@code true} if the operation succeeds, {@code false} otherwise, e.g., {@code numChannels} is outside the valid range.

        enforceChangePermission();
        /*
         * Validate the argument. We'd like to let the Wi-Fi driver do this,
         * but if Wi-Fi isn't currently enabled, that's not possible, and
         * we want to persist the setting anyway,so that it will take
         * effect when Wi-Fi does become enabled.
         */
        boolean found = false;
        for (int validChan : sValidRegulatoryChannelCounts) {
            if (validChan == numChannels) {
                found = true;
                break;
            }
        }
        if (!found) {
            return false;
        }

        Settings.Secure.putInt(mContext.getContentResolver(),
                               Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
                               numChannels);
        mWifiStateTracker.setNumAllowedChannels(numChannels);
        return true;
    
public booleansetWifiEnabled(boolean enable)
see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}

param
enable {@code true} to enable, {@code false} to disable.
return
{@code true} if the enable/disable operation was started or is already in the queue.

        enforceChangePermission();
        if (mWifiHandler == null) return false;

        synchronized (mWifiHandler) {
            sWakeLock.acquire();
            mLastEnableUid = Binder.getCallingUid();
            sendEnableMessage(enable, true, Binder.getCallingUid());
        }

        return true;
    
private booleansetWifiEnabledBlocking(boolean enable, boolean persist, int uid)
Enables/disables Wi-Fi synchronously.

param
enable {@code true} to turn Wi-Fi on, {@code false} to turn it off.
param
persist {@code true} if the setting should be persisted.
param
uid The UID of the process making the request.
return
{@code true} if the operation succeeds (or if the existing state is the same as the requested state)

        final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;

        if (mWifiState == eventualWifiState) {
            return true;
        }
        if (enable && isAirplaneModeOn()) {
            return false;
        }

        setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);

        if (enable) {
            if (!WifiNative.loadDriver()) {
                Log.e(TAG, "Failed to load Wi-Fi driver.");
                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                return false;
            }
            if (!WifiNative.startSupplicant()) {
                WifiNative.unloadDriver();
                Log.e(TAG, "Failed to start supplicant daemon.");
                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                return false;
            }
            registerForBroadcasts();
            mWifiStateTracker.startEventLoop();
        } else {

            mContext.unregisterReceiver(mReceiver);
           // Remove notification (it will no-op if it isn't visible)
            mWifiStateTracker.setNotificationVisible(false, 0, false, 0);

            boolean failedToStopSupplicantOrUnloadDriver = false;
            if (!WifiNative.stopSupplicant()) {
                Log.e(TAG, "Failed to stop supplicant daemon.");
                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                failedToStopSupplicantOrUnloadDriver = true;
            }

            // We must reset the interface before we unload the driver
            mWifiStateTracker.resetInterface();

            if (!WifiNative.unloadDriver()) {
                Log.e(TAG, "Failed to unload Wi-Fi driver.");
                if (!failedToStopSupplicantOrUnloadDriver) {
                    setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                    failedToStopSupplicantOrUnloadDriver = true;
                }
            }
            if (failedToStopSupplicantOrUnloadDriver) {
                return false;
            }
        }

        // Success!

        if (persist) {
            persistWifiEnabled(enable);
        }
        setWifiEnabledState(eventualWifiState, uid);

        /*
         * Initialize the hidden networks state and the number of allowed
         * radio channels if Wi-Fi is being turned on.
         */
        if (enable) {
            mWifiStateTracker.setNumAllowedChannels();
            initializeHiddenNetworksState();
        }

        return true;
    
private voidsetWifiEnabledState(int wifiState, int uid)

        final int previousWifiState = mWifiState;

        long ident = Binder.clearCallingIdentity();
        try {
            if (wifiState == WIFI_STATE_ENABLED) {
                mBatteryStats.noteWifiOn(uid);
            } else if (wifiState == WIFI_STATE_DISABLED) {
                mBatteryStats.noteWifiOff(uid);
            }
        } catch (RemoteException e) {
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        
        // Update state
        mWifiState = wifiState;

        // Broadcast
        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
        mContext.sendStickyBroadcast(intent);
    
public booleanstartScan()
see {@link android.net.wifi.WifiManager#startScan()}

return
{@code true} if the operation succeeds

        enforceChangePermission();
        synchronized (mWifiStateTracker) {
            switch (mWifiStateTracker.getSupplicantState()) {
                case DISCONNECTED:
                case INACTIVE:
                case SCANNING:
                case DORMANT:
                    break;
                default:
                    WifiNative.setScanResultHandlingCommand(
                            WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);
                    break;
            }
            return WifiNative.scanCommand();
        }
    
private static java.lang.StringstateName(int wifiState)

        switch (wifiState) {
            case WIFI_STATE_DISABLING:
                return "disabling";
            case WIFI_STATE_DISABLED:
                return "disabled";
            case WIFI_STATE_ENABLING:
                return "enabling";
            case WIFI_STATE_ENABLED:
                return "enabled";
            case WIFI_STATE_UNKNOWN:
                return "unknown state";
            default:
                return "[invalid state]";
        }
    
private synchronized voidupdateNetworkIfHidden(int netId, boolean present)
Updates the netId network presence status if netId is an existing hidden network.

        if (isHiddenNetwork(netId)) {
            addOrUpdateHiddenNetwork(netId, present);
        }
    
private voidupdateWifiState()

        boolean wifiEnabled = getPersistedWifiEnabled();
        boolean airplaneMode = isAirplaneModeOn();
        boolean lockHeld = mLocks.hasLocks();
        int strongestLockMode;
        boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
        boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
        if (mDeviceIdle && lockHeld) {
            strongestLockMode = mLocks.getStrongestLockMode();
        } else {
            strongestLockMode = WifiManager.WIFI_MODE_FULL;
        }

        synchronized (mWifiHandler) {
            if (mWifiState == WIFI_STATE_ENABLING && !airplaneMode) {
                return;
            }
            if (wifiShouldBeEnabled) {
                if (wifiShouldBeStarted) {
                    sWakeLock.acquire();
                    sendEnableMessage(true, false, mLastEnableUid);
                    sWakeLock.acquire();
                    sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
                } else {
                    int wakeLockTimeout =
                            Settings.Secure.getInt(
                                    mContext.getContentResolver(),
                                    Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
                                    DEFAULT_WAKELOCK_TIMEOUT);
                    /*
                     * The following wakelock is held in order to ensure
                     * that the connectivity manager has time to fail over
                     * to the mobile data network. The connectivity manager
                     * releases it once mobile data connectivity has been
                     * established. If connectivity cannot be established,
                     * the wakelock is released after wakeLockTimeout
                     * milliseconds have elapsed.
                     */
                    sDriverStopWakeLock.acquire();
                    mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI);
                    mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout);
                }
            } else {
                sWakeLock.acquire();
                sendEnableMessage(false, false, mLastEnableUid);
            }
        }