diff options
author | Anh Nguyen <anguyen@codeaurora.org> | 2015-03-10 00:45:06 -0700 |
---|---|---|
committer | Anh Nguyen <anguyen@codeaurora.org> | 2015-03-10 00:45:06 -0700 |
commit | d6459e7bcb9c1e9df6da3fb69346fb07d57655e5 (patch) | |
tree | 38c8561746a1843b7c227c4d27333329861ce86d | |
parent | 880aea0f9852a0f5afeb48855cfc6b7236cd3a37 (diff) | |
parent | 5921779b4827551735e9016c6b6a22adf176ec85 (diff) | |
download | android_frameworks_opt_net_wifi-d6459e7bcb9c1e9df6da3fb69346fb07d57655e5.tar.gz android_frameworks_opt_net_wifi-d6459e7bcb9c1e9df6da3fb69346fb07d57655e5.tar.bz2 android_frameworks_opt_net_wifi-d6459e7bcb9c1e9df6da3fb69346fb07d57655e5.zip |
Merge tag 'android-5.1.0_r1' into HEAD
Android 5.1.0 release 1
Conflicts:
service/java/com/android/server/wifi/WifiAutoJoinController.java
service/java/com/android/server/wifi/WifiConfigStore.java
service/java/com/android/server/wifi/WifiStateMachine.java
Change-Id: Ice0deccd16e33e512bf6c0b5ad53f8945303bdfe
-rwxr-xr-x[-rw-r--r--] | service/Android.mk | 3 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/RttService.java | 2 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/WifiAutoJoinController.java | 420 | ||||
-rwxr-xr-x | service/java/com/android/server/wifi/WifiConfigStore.java | 432 | ||||
-rwxr-xr-x | service/java/com/android/server/wifi/WifiMonitor.java | 29 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/WifiNative.java | 37 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/WifiNetworkScoreCache.java | 82 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/WifiServiceImpl.java | 55 | ||||
-rwxr-xr-x[-rw-r--r--] | service/java/com/android/server/wifi/WifiStateMachine.java | 834 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/WifiWatchdogStateMachine.java | 11 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java | 2 |
11 files changed, 1361 insertions, 546 deletions
diff --git a/service/Android.mk b/service/Android.mk index 970b805f5..ea83236fb 100644..100755 --- a/service/Android.mk +++ b/service/Android.mk @@ -50,6 +50,9 @@ else ifeq ($(BOARD_WLAN_DEVICE), mrvl) # this is commented because none of the nexus devices # that sport Marvell's wifi have support for HAL # LIB_WIFI_HAL := libwifi-hal-mrvl +else ifeq ($(BOARD_WLAN_DEVICE), MediaTek) + # support MTK WIFI HAL + LIB_WIFI_HAL := libwifi-hal-mt66xx endif # Build the HalUtil diff --git a/service/java/com/android/server/wifi/RttService.java b/service/java/com/android/server/wifi/RttService.java index efb028eca..c447e28b5 100644 --- a/service/java/com/android/server/wifi/RttService.java +++ b/service/java/com/android/server/wifi/RttService.java @@ -72,7 +72,7 @@ class RttService extends SystemService { } if (DBG) Slog.d(TAG, "closing client " + msg.replyTo); ClientInfo ci = mClients.remove(msg.replyTo); - ci.cleanup(); + if (ci != null) ci.cleanup(); return; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: AsyncChannel ac = new AsyncChannel(); diff --git a/service/java/com/android/server/wifi/WifiAutoJoinController.java b/service/java/com/android/server/wifi/WifiAutoJoinController.java index 50bc374f0..d7a88fbc3 100644 --- a/service/java/com/android/server/wifi/WifiAutoJoinController.java +++ b/service/java/com/android/server/wifi/WifiAutoJoinController.java @@ -17,13 +17,13 @@ package com.android.server.wifi; import android.content.Context; - import android.net.NetworkKey; import android.net.NetworkScoreManager; import android.net.WifiKey; import android.net.wifi.*; - +import android.net.wifi.WifiConfiguration.KeyMgmt; import android.os.SystemClock; +import android.provider.Settings; import android.os.Process; import android.text.TextUtils; import android.util.Log; @@ -53,9 +53,9 @@ public class WifiAutoJoinController { private static boolean DBG = false; private static boolean VDBG = false; private static final boolean mStaStaSupported = false; - private static final int SCAN_RESULT_CACHE_SIZE = 80; public static int mScanResultMaximumAge = 40000; /* milliseconds unit */ + public static int mScanResultAutoJoinAge = 5000; /* milliseconds unit */ private String mCurrentConfigurationKey = null; //used by autojoin @@ -66,8 +66,8 @@ public class WifiAutoJoinController { private WifiConnectionStatistics mWifiConnectionStatistics; - /* for debug purpose only : the untrusted SSID we would be connected to if we had VPN */ - String lastUntrustedBSSID = null; + /** Whether to allow connections to untrusted networks. */ + private boolean mAllowUntrustedConnections = false; /* For debug purpose only: if the scored override a score */ boolean didOverride = false; @@ -77,6 +77,9 @@ public class WifiAutoJoinController { // Lose some temporary blacklisting after 30 minutes private final static long loseBlackListSoftMilli = 1000 * 60 * 30; + /** @see android.provider.Settings.Global#WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS */ + private static final long DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS = 1000 * 60; // 1 minute + public static final int AUTO_JOIN_IDLE = 0; public static final int AUTO_JOIN_ROAMING = 1; public static final int AUTO_JOIN_EXTENDED_ROAMING = 2; @@ -161,10 +164,10 @@ public class WifiAutoJoinController { int numScanResultsKnown = 0; // Record number of scan results we knew about WifiConfiguration associatedConfig = null; boolean didAssociate = false; + long now = System.currentTimeMillis(); ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>(); - long nowMs = System.currentTimeMillis(); for(ScanResult result: scanList) { if (result.SSID == null) continue; @@ -174,11 +177,23 @@ public class WifiAutoJoinController { // Fetch the previous instance for this result ScanResult sr = scanResultCache.get(result.BSSID); if (sr != null) { + if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0 + && result.level == 0 + && sr.level < -20) { + // A 'zero' RSSI reading is most likely a chip problem which returns + // an unknown RSSI, hence ignore it + result.level = sr.level; + } + // If there was a previous cache result for this BSSID, average the RSSI values result.averageRssi(sr.level, sr.seen, mScanResultMaximumAge); // Remove the previous Scan Result - this is not necessary scanResultCache.remove(result.BSSID); + } else if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0 && result.level == 0) { + // A 'zero' RSSI reading is most likely a chip problem which returns + // an unknown RSSI, hence initialize it to a sane value + result.level = mWifiConfigStore.scanResultRssiLevelPatchUp; } if (!mNetworkScoreCache.isScoredNetwork(result)) { @@ -228,7 +243,11 @@ public class WifiAutoJoinController { if (associatedConfig != null && associatedConfig.SSID != null) { if (VDBG) { logDbg("addToScanCache save associated config " - + associatedConfig.SSID + " with " + result.SSID); + + associatedConfig.SSID + " with " + result.SSID + + " status " + associatedConfig.autoJoinStatus + + " reason " + associatedConfig.disableReason + + " tsp " + associatedConfig.blackListTimestamp + + " was " + (now - associatedConfig.blackListTimestamp)); } mWifiStateMachine.sendMessage( WifiStateMachine.CMD_AUTO_SAVE_NETWORK, associatedConfig); @@ -236,7 +255,6 @@ public class WifiAutoJoinController { } } else { // If the scan result has been blacklisted fir 18 hours -> unblacklist - long now = System.currentTimeMillis(); if ((now - result.blackListTimestamp) > loseBlackListHardMilli) { result.setAutoJoinStatus(ScanResult.ENABLED); } @@ -263,7 +281,6 @@ public class WifiAutoJoinController { } void logDbg(String message, boolean stackTrace) { - long now = SystemClock.elapsedRealtimeNanos(); if (stackTrace) { Log.e(TAG, message + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() + " - " @@ -289,7 +306,7 @@ public class WifiAutoJoinController { if (doAutoJoin) { attemptAutoJoin(); } - mWifiConfigStore.writeKnownNetworkHistory(); + mWifiConfigStore.writeKnownNetworkHistory(false); return numScanResultsKnown; } @@ -308,7 +325,7 @@ public class WifiAutoJoinController { addToScanCache(scanList); ageScanResultsOut(0); attemptAutoJoin(); - mWifiConfigStore.writeKnownNetworkHistory(); + mWifiConfigStore.writeKnownNetworkHistory(false); } /** @@ -347,7 +364,7 @@ public class WifiAutoJoinController { logDbg("compareNetwork will compare " + candidate.configKey() + " with current " + currentNetwork.configKey()); } - int order = compareWifiConfigurationsTop(currentNetwork, candidate); + int order = compareWifiConfigurations(currentNetwork, candidate); // The lastSelectedConfiguration is the configuration the user has manually selected // thru WifiPicker, or that a 3rd party app asked us to connect to via the @@ -538,7 +555,7 @@ public class WifiAutoJoinController { // TODO: write only if something changed if (userTriggered || connect) { - mWifiConfigStore.writeKnownNetworkHistory(); + mWifiConfigStore.writeKnownNetworkHistory(false); } } @@ -573,30 +590,88 @@ public class WifiAutoJoinController { } } + int compareWifiConfigurationsFromVisibility(WifiConfiguration a, int aRssiBoost, + WifiConfiguration b, int bRssiBoost) { + + int aRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref) + int bRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref) - int getScoreFromVisibility(WifiConfiguration.Visibility visibility, int rssiBoost, String dbg) { - int rssiBoost5 = 0; - int score = 0; + int aScore = 0; + int bScore = 0; + + boolean aPrefers5GHz = false; + boolean bPrefers5GHz = false; /** - * Boost RSSI value of 5GHz bands iff the base value is better than threshold + * Calculate a boost to apply to RSSI value of configuration we want to join on 5GHz: + * Boost RSSI value of 5GHz bands iff the base value is better than threshold, + * penalize the RSSI value of 5GHz band iff the base value is lower than threshold * This implements band preference where we prefer 5GHz if RSSI5 is good enough, whereas * we prefer 2.4GHz otherwise. - * Note that 2.4GHz doesn't need a boost since at equal power the RSSI is typically - * at least 6-10 dB higher */ - rssiBoost5 = rssiBoostFrom5GHzRssi(visibility.rssi5, dbg+"->"); + aRssiBoost5 = rssiBoostFrom5GHzRssi(a.visibility.rssi5, a.configKey() + "->"); + bRssiBoost5 = rssiBoostFrom5GHzRssi(b.visibility.rssi5, b.configKey() + "->"); - // Select which band to use so as to score a - if (visibility.rssi5 + rssiBoost5 > visibility.rssi24) { + // Select which band to use for a + if (a.visibility.rssi5 + aRssiBoost5 > a.visibility.rssi24) { // Prefer a's 5GHz - score = visibility.rssi5 + rssiBoost5 + rssiBoost; + aPrefers5GHz = true; + } + + // Select which band to use for b + if (b.visibility.rssi5 + bRssiBoost5 > b.visibility.rssi24) { + // Prefer b's 5GHz + bPrefers5GHz = true; + } + + if (aPrefers5GHz) { + if (bPrefers5GHz) { + // If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either + // one, but directly compare the RSSI values, this improves stability, + // since the 5GHz RSSI boost can introduce large fluctuations + aScore = a.visibility.rssi5 + aRssiBoost; + } else { + // If only a is on 5GHz, then apply the 5GHz preference boost to a + aScore = a.visibility.rssi5 + aRssiBoost + aRssiBoost5; + } + } else { + aScore = a.visibility.rssi24 + aRssiBoost; + } + + if (bPrefers5GHz) { + if (aPrefers5GHz) { + // If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either + // one, but directly compare the RSSI values, this improves stability, + // since the 5GHz RSSI boost can introduce large fluctuations + bScore = b.visibility.rssi5 + bRssiBoost; + } else { + // If only b is on 5GHz, then apply the 5GHz preference boost to b + bScore = b.visibility.rssi5 + bRssiBoost + bRssiBoost5; + } } else { - // Prefer a's 2.4GHz - score = visibility.rssi24 + rssiBoost; + bScore = b.visibility.rssi24 + bRssiBoost; + } + if (VDBG) { + logDbg(" " + a.configKey() + " is5=" + aPrefers5GHz + " score=" + aScore + + " " + b.configKey() + " is5=" + bPrefers5GHz + " score=" + bScore); + } + + // Debug only, record RSSI comparison parameters + if (a.visibility != null) { + a.visibility.score = aScore; + a.visibility.currentNetworkBoost = aRssiBoost; + a.visibility.bandPreferenceBoost = aRssiBoost5; + } + if (b.visibility != null) { + b.visibility.score = bScore; + b.visibility.currentNetworkBoost = bRssiBoost; + b.visibility.bandPreferenceBoost = bRssiBoost5; } - return score; + // Compare a and b + // If a score is higher then a > b and the order is descending (negative) + // If b score is higher then a < b and the order is ascending (positive) + return bScore - aScore; } // Compare WifiConfiguration by RSSI, and return a comparison value in the range [-50, +50] @@ -629,33 +704,25 @@ public class WifiAutoJoinController { // Apply Hysteresis, boost RSSI of current configuration if (null != currentConfiguration) { if (a.configKey().equals(currentConfiguration)) { - aRssiBoost = +10; + aRssiBoost = mWifiConfigStore.currentNetworkBoost; } else if (b.configKey().equals(currentConfiguration)) { - bRssiBoost = +10; + bRssiBoost = mWifiConfigStore.currentNetworkBoost; } - - } if (VDBG) { logDbg(" compareWifiConfigurationsRSSI: " + a.configKey() - + " " + Integer.toString(astatus.rssi24) + + " rssi=" + Integer.toString(astatus.rssi24) + "," + Integer.toString(astatus.rssi5) + " boost=" + Integer.toString(aRssiBoost) - + " " + b.configKey() + " " + + " " + b.configKey() + " rssi=" + Integer.toString(bstatus.rssi24) + "," + Integer.toString(bstatus.rssi5) + " boost=" + Integer.toString(bRssiBoost) ); } - scoreA = getScoreFromVisibility(astatus, aRssiBoost, a.configKey()); - scoreB = getScoreFromVisibility(bstatus, bRssiBoost, b.configKey()); - - // Compare a and b - // If a score is higher then a > b and the order is descending (negative) - // If b score is higher then a < b and the order is ascending (positive) - order = scoreB - scoreA; + order = compareWifiConfigurationsFromVisibility(a, aRssiBoost, b, bRssiBoost); // Normalize the order to [-50, +50] if (order > 50) order = 50; @@ -673,36 +740,36 @@ public class WifiAutoJoinController { + "," + a.visibility.rssi5 + ") num=(" + a.visibility.num24 + "," + a.visibility.num5 + ")" - + " scorea=" + scoreA + prefer + b.configKey() + " rssi=(" + b.visibility.rssi24 + "," + b.visibility.rssi5 + ") num=(" + b.visibility.num24 + "," + b.visibility.num5 + ")" - + " scoreb=" + scoreB + " -> " + order); } return order; } - + /** + * b/18490330 only use scorer for untrusted networks + * int compareWifiConfigurationsWithScorer(WifiConfiguration a, WifiConfiguration b) { - int aRssiBoost = 0; - int bRssiBoost = 0; + boolean aIsActive = false; + boolean bIsActive = false; // Apply Hysteresis : boost RSSI of current configuration before // looking up the score if (null != mCurrentConfigurationKey) { if (a.configKey().equals(mCurrentConfigurationKey)) { - aRssiBoost += 20; + aIsActive = true; } else if (b.configKey().equals(mCurrentConfigurationKey)) { - bRssiBoost += 20; + bIsActive = true; } } - int scoreA = getConfigNetworkScore(a, 3000, aRssiBoost); - int scoreB = getConfigNetworkScore(b, 3000, bRssiBoost); + int scoreA = getConfigNetworkScore(a, mScanResultAutoJoinAge, aIsActive); + int scoreB = getConfigNetworkScore(b, mScanResultAutoJoinAge, bIsActive); // Both configurations need to have a score for the scorer to be used // ...and the scores need to be different:-) @@ -742,10 +809,10 @@ public class WifiAutoJoinController { // If scoreA > scoreB, the comparison is descending hence the return value is negative return scoreB - scoreA; } + */ int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) { int order = 0; - String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration(); boolean linked = false; if ((a.linkedConfigurations != null) && (b.linkedConfigurations != null) @@ -791,6 +858,10 @@ public class WifiAutoJoinController { + " due to user choice of " + choice + " order -> " + Integer.toString(order)); } + if (a.visibility != null) { + a.visibility.lastChoiceBoost = choice; + a.visibility.lastChoiceConfig = b.configKey(); + } } choice = getConnectChoice(b, a); @@ -802,6 +873,10 @@ public class WifiAutoJoinController { + a.configKey() + " due to user choice of " + choice + " order ->" + Integer.toString(order)); } + if (b.visibility != null) { + b.visibility.lastChoiceBoost = choice; + b.visibility.lastChoiceConfig = a.configKey(); + } } } @@ -845,6 +920,7 @@ public class WifiAutoJoinController { return (rssi5 < -80 && rssi24 < -90); } + /* int compareWifiConfigurationsTop(WifiConfiguration a, WifiConfiguration b) { int scorerOrder = compareWifiConfigurationsWithScorer(a, b); int order = compareWifiConfigurations(a, b); @@ -868,6 +944,7 @@ public class WifiAutoJoinController { } return order; } + */ public int rssiBoostFrom5GHzRssi(int rssi, String dbg) { if (!mWifiConfigStore.enable5GHzPreference) { @@ -882,13 +959,12 @@ public class WifiAutoJoinController { int boost = mWifiConfigStore.bandPreferenceBoostFactor5 *(rssi - mWifiConfigStore.bandPreferenceBoostThreshold5); if (boost > 50) { - // 50 dB boost is set so as to overcome the hysteresis of +20 plus a difference of - // 25 dB between 2.4 and 5GHz band. This allows jumping from 2.4 to 5GHz + // 50 dB boost allows jumping from 2.4 to 5GHz // consistently boost = 50; } if (VDBG && dbg != null) { - logDbg(" " + dbg + ": rssi5 " + rssi + " boost " + boost); + logDbg(" " + dbg + ": rssi5 " + rssi + " 5GHz-boost " + boost); } return boost; } @@ -1054,7 +1130,7 @@ public class WifiAutoJoinController { * @param config * @return score */ - int getConfigNetworkScore(WifiConfiguration config, int age, int rssiBoost) { + int getConfigNetworkScore(WifiConfiguration config, int age, boolean isActive) { if (mNetworkScoreCache == null) { if (VDBG) { @@ -1079,7 +1155,7 @@ public class WifiAutoJoinController { // Run thru all cached scan results for (ScanResult result : config.scanResultCache.values()) { if ((nowMs - result.seen) < age) { - int sc = mNetworkScoreCache.getNetworkScore(result, rssiBoost); + int sc = mNetworkScoreCache.getNetworkScore(result, isActive); if (sc > startScore) { startScore = sc; } @@ -1094,7 +1170,7 @@ public class WifiAutoJoinController { + " -> no available score"); } else { logDbg(" getConfigNetworkScore for " + config.configKey() - + " boost=" + Integer.toString(rssiBoost) + + " isActive=" + isActive + " score = " + Integer.toString(startScore)); } } @@ -1126,13 +1202,82 @@ public class WifiAutoJoinController { } /** + * Set whether connections to untrusted connections are allowed. + */ + void setAllowUntrustedConnections(boolean allow) { + boolean changed = mAllowUntrustedConnections != allow; + mAllowUntrustedConnections = allow; + if (changed) { + // Trigger a scan so as to reattempt autojoin + mWifiStateMachine.startScanForUntrustedSettingChange(); + } + } + + private boolean isOpenNetwork(ScanResult result) { + return !result.capabilities.contains("WEP") && + !result.capabilities.contains("PSK") && + !result.capabilities.contains("EAP"); + } + + private boolean haveRecentlySeenScoredBssid(WifiConfiguration config) { + long ephemeralOutOfRangeTimeoutMs = Settings.Global.getLong( + mContext.getContentResolver(), + Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS, + DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS); + + // Check whether the currently selected network has a score curve. If + // ephemeralOutOfRangeTimeoutMs is <= 0, then this is all we check, and we stop here. + // Otherwise, we stop here if the currently selected network has a score. If it doesn't, we + // keep going - it could be that another BSSID is in range (has been seen recently) which + // has a score, even if the one we're immediately connected to doesn't. + ScanResult currentScanResult = mWifiStateMachine.getCurrentScanResult(); + boolean currentNetworkHasScoreCurve = mNetworkScoreCache.hasScoreCurve(currentScanResult); + if (ephemeralOutOfRangeTimeoutMs <= 0 || currentNetworkHasScoreCurve) { + if (DBG) { + if (currentNetworkHasScoreCurve) { + logDbg("Current network has a score curve, keeping network: " + + currentScanResult); + } else { + logDbg("Current network has no score curve, giving up: " + config.SSID); + } + } + return currentNetworkHasScoreCurve; + } + + if (config.scanResultCache == null || config.scanResultCache.isEmpty()) { + return false; + } + + long currentTimeMs = System.currentTimeMillis(); + for (ScanResult result : config.scanResultCache.values()) { + if (currentTimeMs > result.seen + && currentTimeMs - result.seen < ephemeralOutOfRangeTimeoutMs + && mNetworkScoreCache.hasScoreCurve(result)) { + if (DBG) { + logDbg("Found scored BSSID, keeping network: " + result.BSSID); + } + return true; + } + } + + if (DBG) { + logDbg("No recently scored BSSID found, giving up connection: " + config.SSID); + } + return false; + } + + /** * attemptAutoJoin() function implements the core of the a network switching algorithm + * Return false if no acceptable networks were found. */ - void attemptAutoJoin() { + boolean attemptAutoJoin() { + boolean found = false; didOverride = false; didBailDueToWeakRssi = false; int networkSwitchType = AUTO_JOIN_IDLE; + long now = System.currentTimeMillis(); + String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration(); // Reset the currentConfiguration Key, and set it only if WifiStateMachine and @@ -1143,11 +1288,12 @@ public class WifiAutoJoinController { WifiConfiguration candidate = null; // Obtain the subset of recently seen networks - List<WifiConfiguration> list = mWifiConfigStore.getRecentConfiguredNetworks(3000, false); + List<WifiConfiguration> list = + mWifiConfigStore.getRecentConfiguredNetworks(mScanResultAutoJoinAge, false); if (list == null) { if (VDBG) logDbg("attemptAutoJoin nothing known=" + mWifiConfigStore.getconfiguredNetworkSize()); - return; + return false; } // Find the currently connected network: ask the supplicant directly @@ -1199,7 +1345,7 @@ public class WifiAutoJoinController { // mWifiNative.status() command, which allow us to know that // supplicant has started association process, even though we didnt yet get the // SUPPLICANT_STATE_CHANGE message. - return; + return false; } } if (DBG) { @@ -1218,22 +1364,32 @@ public class WifiAutoJoinController { if (currentConfiguration != null) { if (supplicantNetId != currentConfiguration.networkId - //https://b.corp.google.com/issue?id=16484607 - //mark this confition as an error only if the mismatched networkId are valid + // https://b.corp.google.com/issue?id=16484607 + // mark this condition as an error only if the mismatched networkId are valid && supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID && currentConfiguration.networkId != WifiConfiguration.INVALID_NETWORK_ID) { logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid=" + Integer.toString(supplicantNetId) + " WifiStateMachine=" + Integer.toString(currentConfiguration.networkId)); mWifiStateMachine.disconnectCommand(); - return; + return false; + } else if (currentConfiguration.ephemeral && (!mAllowUntrustedConnections || + !haveRecentlySeenScoredBssid(currentConfiguration))) { + // The current connection is untrusted (the framework added it), but we're either + // no longer allowed to connect to such networks, the score has been nullified + // since we connected, or the scored BSSID has gone out of range. + // Drop the current connection and perform the rest of autojoin. + logDbg("attemptAutoJoin() disconnecting from unwanted ephemeral network"); + mWifiStateMachine.disconnectCommand(Process.WIFI_UID, + mAllowUntrustedConnections ? 1 : 0); + return false; } else { mCurrentConfigurationKey = currentConfiguration.configKey(); } } else { if (supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID) { // Maybe in the process of associating, skip this attempt - return; + return false; } } @@ -1262,19 +1418,52 @@ public class WifiAutoJoinController { if (config.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { + // Wait for 5 minutes before reenabling config that have known, + // repeated connection or DHCP failures + if (config.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE + || config.disableReason + == WifiConfiguration.DISABLED_ASSOCIATION_REJECT + || config.disableReason + == WifiConfiguration.DISABLED_AUTH_FAILURE) { + if (config.blackListTimestamp == 0 + || (config.blackListTimestamp > now)) { + // Sanitize the timestamp + config.blackListTimestamp = now; + } + if ((now - config.blackListTimestamp) > + mWifiConfigStore.wifiConfigBlacklistMinTimeMilli) { + // Re-enable the WifiConfiguration + config.status = WifiConfiguration.Status.ENABLED; + + // Reset the blacklist condition + config.numConnectionFailures = 0; + config.numIpConfigFailures = 0; + config.numAuthFailures = 0; + config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); + + config.dirty = true; + } else { + if (VDBG) { + long delay = mWifiConfigStore.wifiConfigBlacklistMinTimeMilli + - (now - config.blackListTimestamp); + logDbg("attemptautoJoin " + config.configKey() + + " dont unblacklist yet, waiting for " + + delay + " ms"); + } + } + } // Avoid networks disabled because of AUTH failure altogether if (DBG) { logDbg("attemptAutoJoin skip candidate due to auto join status " + Integer.toString(config.autoJoinStatus) + " key " + config.configKey(true) - + " reason " + config.disableReason); + + " reason " + config.disableReason); } continue; } // Try to un-blacklist based on elapsed time if (config.blackListTimestamp > 0) { - long now = System.currentTimeMillis(); if (now < config.blackListTimestamp) { /** * looks like there was a change in the system clock since we black listed, and @@ -1363,6 +1552,29 @@ public class WifiAutoJoinController { if (config.visibility == null) { continue; } + + if (config.lastRoamingFailure != 0 + && currentConfiguration != null + && (lastSelectedConfiguration == null + || !config.configKey().equals(lastSelectedConfiguration))) { + // Apply blacklisting for roaming to this config if: + // - the target config had a recent roaming failure + // - we are currently associated + // - the target config is not the last selected + if (now > config.lastRoamingFailure + && (now - config.lastRoamingFailure) + < config.roamingFailureBlackListTimeMilli) { + if (DBG) { + logDbg("compareNetwork not switching to " + config.configKey() + + " from current " + currentConfiguration.configKey() + + " because it is blacklisted due to roam failure, " + + " blacklist remain time = " + + (now - config.lastRoamingFailure) + " ms"); + } + continue; + } + } + int boost = config.autoJoinUseAggressiveJoinAttemptThreshold + weakRssiBailCount; if ((config.visibility.rssi5 + boost) < mWifiConfigStore.thresholdInitialAutoJoinAttemptMin5RSSI @@ -1392,12 +1604,16 @@ public class WifiAutoJoinController { } } } - if (config.noInternetAccess && !isLastSelected) { - // Avoid autojoining this network because last time we used it, it didn't - // have internet access + if (config.numNoInternetAccessReports > 0 + && !isLastSelected + && !config.validatedInternetAccess) { + // Avoid autoJoining this network because last time we used it, it didn't + // have internet access, and we never manage to validate internet access on this + // network configuration if (DBG) { - logDbg("attemptAutoJoin skip candidate due to noInternetAccess flag " - + config.configKey(true)); + logDbg("attemptAutoJoin skip candidate due to no InternetAccess " + + config.configKey(true) + + " num reports " + config.numNoInternetAccessReports); } continue; } @@ -1421,7 +1637,7 @@ public class WifiAutoJoinController { logDbg("attemptAutoJoin will compare candidate " + candidate.configKey() + " with " + config.configKey()); } - int order = compareWifiConfigurationsTop(candidate, config); + int order = compareWifiConfigurations(candidate, config); // The lastSelectedConfiguration is the configuration the user has manually selected // thru WifiPicker, or that a 3rd party app asked us to connect to via the @@ -1463,12 +1679,10 @@ public class WifiAutoJoinController { } } - // Wait for VPN to be available on the system to make use of this code // Now, go thru scan result to try finding a better untrusted network - if (mNetworkScoreCache != null) { + if (mNetworkScoreCache != null && mAllowUntrustedConnections) { int rssi5 = WifiConfiguration.INVALID_RSSI; int rssi24 = WifiConfiguration.INVALID_RSSI; - WifiConfiguration.Visibility visibility; if (candidate != null) { rssi5 = candidate.visibility.rssi5; rssi24 = candidate.visibility.rssi24; @@ -1482,22 +1696,24 @@ public class WifiAutoJoinController { // Look for untrusted scored network only if the current candidate is bad if (isBadCandidate(rssi24, rssi5)) { for (ScanResult result : scanResultCache.values()) { - int rssiBoost = 0; // We look only at untrusted networks with a valid SSID // A trusted result would have been looked at thru it's Wificonfiguration - if (TextUtils.isEmpty(result.SSID) || !result.untrusted) { + if (TextUtils.isEmpty(result.SSID) || !result.untrusted || + !isOpenNetwork(result)) { continue; } - if ((nowMs - result.seen) < 3000) { + String quotedSSID = "\"" + result.SSID + "\""; + if (mWifiConfigStore.mDeletedEphemeralSSIDs.contains(quotedSSID)) { + // SSID had been Forgotten by user, then don't score it + continue; + } + if ((nowMs - result.seen) < mScanResultAutoJoinAge) { // Increment usage count for the network - mWifiConnectionStatistics.incrementOrAddUntrusted(result.SSID, 0, 1); + mWifiConnectionStatistics.incrementOrAddUntrusted(quotedSSID, 0, 1); - if (lastUntrustedBSSID != null - && result.BSSID.equals(lastUntrustedBSSID)) { - // Apply a large hysteresis to the untrusted network we are connected to - rssiBoost = 25; - } - int score = mNetworkScoreCache.getNetworkScore(result, rssiBoost); + boolean isActiveNetwork = currentConfiguration != null + && currentConfiguration.SSID.equals(quotedSSID); + int score = mNetworkScoreCache.getNetworkScore(result, isActiveNetwork); if (score != WifiNetworkScoreCache.INVALID_NETWORK_SCORE && score > currentScore) { // Highest score: Select this candidate @@ -1515,18 +1731,13 @@ public class WifiAutoJoinController { } } if (untrustedCandidate != null) { - if (lastUntrustedBSSID == null - || !untrustedCandidate.SSID.equals(lastUntrustedBSSID)) { - // We found a new candidate that we are going to connect to, then - // increase its connection count - mWifiConnectionStatistics. - incrementOrAddUntrusted(untrustedCandidate.SSID, 1, 0); - // Remember which SSID we are connecting to - lastUntrustedBSSID = untrustedCandidate.SSID; - } + // At this point, we have an untrusted network candidate. + // Create the new ephemeral configuration and see if we should switch over + candidate = + mWifiConfigStore.wifiConfigurationFromScanResult(untrustedCandidate); + candidate.allowedKeyManagement.set(KeyMgmt.NONE); + candidate.ephemeral = true; } - // Now we don't have VPN, and thus don't actually connect to the untrusted candidate - untrustedCandidate = null; } long lastUnwanted = @@ -1603,12 +1814,20 @@ public class WifiAutoJoinController { candidate.numAssociation++; mWifiConnectionStatistics.numAutoJoinAttempt++; + if (candidate.ephemeral) { + // We found a new candidate that we are going to connect to, then + // increase its connection count + mWifiConnectionStatistics. + incrementOrAddUntrusted(candidate.SSID, 1, 0); + } + if (candidate.BSSID == null || candidate.BSSID.equals("any")) { // First step we selected the configuration we want to connect to // Second step: Look for the best Scan result for this configuration // TODO this algorithm should really be done in one step String currentBSSID = mWifiStateMachine.getCurrentBSSID(); - ScanResult roamCandidate = attemptRoam(null, candidate, 3000, null); + ScanResult roamCandidate = + attemptRoam(null, candidate, mScanResultAutoJoinAge, null); if (roamCandidate != null && currentBSSID != null && currentBSSID.equals(roamCandidate.BSSID)) { // Sanity, we were already asociated to that candidate @@ -1632,14 +1851,15 @@ public class WifiAutoJoinController { } mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT, candidate.networkId, networkSwitchType, candidate); + found = true; } } if (networkSwitchType == AUTO_JOIN_IDLE) { String currentBSSID = mWifiStateMachine.getCurrentBSSID(); // Attempt same WifiConfiguration roaming - ScanResult roamCandidate = attemptRoam(null, currentConfiguration, 3000, - currentBSSID); + ScanResult roamCandidate = + attemptRoam(null, currentConfiguration, mScanResultAutoJoinAge, currentBSSID); /** * TODO: (post L initial release) * consider handling linked configurations roaming (i.e. extended Roaming) @@ -1658,7 +1878,7 @@ public class WifiAutoJoinController { for (String key : currentConfiguration.linkedConfigurations.keySet()) { WifiConfiguration link = mWifiConfigStore.getWifiConfiguration(key); if (link != null) { - roamCandidate = attemptRoam(roamCandidate, link, 3000, + roamCandidate = attemptRoam(roamCandidate, link, mScanResultAutoJoinAge, currentBSSID); } } @@ -1680,9 +1900,11 @@ public class WifiAutoJoinController { mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM, currentConfiguration.networkId, 1, roamCandidate); + found = true; } } if (VDBG) logDbg("Done attemptAutoJoin status=" + Integer.toString(networkSwitchType)); + return found; } } diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index 9f5fa9026..4959ce7c5 100755 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -80,6 +80,8 @@ import java.text.DateFormat; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.*; +import java.util.zip.Checksum; +import java.util.zip.CRC32; /** * This class provides the API to manage configured @@ -150,6 +152,21 @@ public class WifiConfigStore extends IpConfigStore { private HashMap<Integer, Integer> mNetworkIds = new HashMap<Integer, Integer>(); + /** + * Framework keeps a list of (the CRC32 hashes of) all SSIDs that where deleted by user, + * so as, framework knows not to re-add those SSIDs automatically to the Saved networks + */ + private Set<Long> mDeletedSSIDs = new HashSet<Long>(); + + /** + * Framework keeps a list of ephemeral SSIDs that where deleted by user, + * so as, framework knows not to autojoin again those SSIDs based on scorer input. + * The list is never cleared up. + * + * The SSIDs are encoded in a String as per definition of WifiConfiguration.SSID field. + */ + public Set<String> mDeletedEphemeralSSIDs = new HashSet<String>(); + /* Tracks the highest priority of configured networks */ private int mLastPriority = -1; @@ -196,9 +213,13 @@ public class WifiConfigStore extends IpConfigStore { private static final String NUM_AUTH_FAILURES_KEY = "AUTH_FAILURES: "; private static final String SCORER_OVERRIDE_KEY = "SCORER_OVERRIDE: "; private static final String SCORER_OVERRIDE_AND_SWITCH_KEY = "SCORER_OVERRIDE_AND_SWITCH: "; - private static final String NO_INTERNET_ACCESS_KEY = "NO_INTERNET_ACCESS: "; + private static final String VALIDATED_INTERNET_ACCESS_KEY = "VALIDATED_INTERNET_ACCESS: "; + private static final String NO_INTERNET_ACCESS_REPORTS_KEY = "NO_INTERNET_ACCESS_REPORTS : "; private static final String EPHEMERAL_KEY = "EPHEMERAL: "; private static final String NUM_ASSOCIATION_KEY = "NUM_ASSOCIATION: "; + private static final String DELETED_CRC32_KEY = "DELETED_CRC32: "; + private static final String DELETED_EPHEMERAL_KEY = "DELETED_EPHEMERAL: "; + private static final String JOIN_ATTEMPT_BOOST_KEY = "JOIN_ATTEMPT_BOOST: "; private static final String THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY = "THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G: "; @@ -323,6 +344,10 @@ public class WifiConfigStore extends IpConfigStore { public int associatedPartialScanPeriodMilli; + // Sane value for roam blacklisting (not switching to a network if already associated) + // 2 days + public int networkSwitchingBlackListPeriodMilli = 2 * 24 * 60 * 60 * 1000; + public int bandPreferenceBoostFactor5 = 5; // Boost by 5 dB per dB above threshold public int bandPreferencePenaltyFactor5 = 2; // Penalize by 2 dB per dB below threshold public int bandPreferencePenaltyThreshold5 = WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD; @@ -337,6 +362,9 @@ public class WifiConfigStore extends IpConfigStore { public int maxConnectionErrorsToBlacklist = 4; public int wifiConfigBlacklistMinTimeMilli = 1000 * 60 * 5; + // How long a disconnected config remain considered as the last user selection + public int wifiConfigLastSelectionHysteresis = 1000 * 60 * 3; + // Boost RSSI values of associated networks public int associatedHysteresisHigh = +14; public int associatedHysteresisLow = +8; @@ -365,6 +393,11 @@ public class WifiConfigStore extends IpConfigStore { public boolean enable5GHzPreference = true; public boolean enableWifiCellularHandoverUserTriggeredAdjustment = true; + public int currentNetworkBoost = 25; + public int scanResultRssiLevelPatchUp = -85; + + public static final int maxNumScanCacheEntries = 128; + /** * Regex pattern for extracting a connect choice. * Matches a strings like the following: @@ -516,6 +549,15 @@ public class WifiConfigStore extends IpConfigStore { enableAutoJoinWhenAssociated = mContext.getResources().getBoolean( R.bool.config_wifi_framework_enable_associated_network_selection); + + currentNetworkBoost = mContext.getResources().getInteger( + R.integer.config_wifi_framework_current_network_boost); + + scanResultRssiLevelPatchUp = mContext.getResources().getInteger( + R.integer.config_wifi_framework_scan_result_rssi_level_patchup_value); + + networkSwitchingBlackListPeriodMilli = mContext.getResources().getInteger( + R.integer.config_wifi_network_switching_blacklist_time); } void enableVerboseLogging(int verbose) { @@ -567,7 +609,9 @@ public class WifiConfigStore extends IpConfigStore { List<WifiConfiguration> networks = new ArrayList<>(); for(WifiConfiguration config : mConfiguredNetworks.values()) { WifiConfiguration newConfig = new WifiConfiguration(config); - if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) { + // When updating this condition, update WifiStateMachine's CONNECT_NETWORK handler to + // correctly handle updating existing configs that are filtered out here. + if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || config.ephemeral) { // Do not enumerate and return this configuration to any one, // for instance WiFi Picker. // instead treat it as unknown. the configuration can still be retrieved @@ -622,10 +666,10 @@ public class WifiConfigStore extends IpConfigStore { * @return List of networks */ List<WifiConfiguration> getRecentConfiguredNetworks(int milli, boolean copy) { - List<WifiConfiguration> networks = null; + List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); for (WifiConfiguration config : mConfiguredNetworks.values()) { - if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) { + if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || config.ephemeral) { // Do not enumerate and return this configuration to any one, // instead treat it as unknown. the configuration can still be retrieved // directly by the key or networkId @@ -641,8 +685,6 @@ public class WifiConfigStore extends IpConfigStore { config.visibility.rssi24 == WifiConfiguration.INVALID_RSSI) { continue; } - if (networks == null) - networks = new ArrayList<WifiConfiguration>(); if (copy) { networks.add(new WifiConfiguration(config)); } else { @@ -718,11 +760,11 @@ public class WifiConfigStore extends IpConfigStore { for(WifiConfiguration config : mConfiguredNetworks.values()) { - if(config != null && config.status == Status.DISABLED + if(config != null && config.status == Status.DISABLED && !config.ephemeral && (config.autoJoinStatus <= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) { - // Wait for 20 minutes before reenabling config that have known, repeated connection + // Wait for 5 minutes before reenabling config that have known, repeated connection // or DHCP failures if (config.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE || config.disableReason == WifiConfiguration.DISABLED_ASSOCIATION_REJECT @@ -822,6 +864,15 @@ public class WifiConfigStore extends IpConfigStore { + " Uid=" + Integer.toString(config.creatorUid) + "/" + Integer.toString(config.lastUpdateUid)); } + + if (mDeletedEphemeralSSIDs.remove(config.SSID)) { + if (VDBG) { + loge("WifiConfigStore: removed from ephemeral blacklist: " + config.SSID); + } + // NOTE: This will be flushed to disk as part of the addOrUpdateNetworkNative call + // below, since we're creating/modifying a config. + } + boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid); int netId = result.getNetworkId(); @@ -887,6 +938,19 @@ public class WifiConfigStore extends IpConfigStore { } } + void noteRoamingFailure(WifiConfiguration config, int reason) { + if (config == null) return; + config.lastRoamingFailure = System.currentTimeMillis(); + config.roamingFailureBlackListTimeMilli + = 2 * (config.roamingFailureBlackListTimeMilli + 1000); + if (config.roamingFailureBlackListTimeMilli + > networkSwitchingBlackListPeriodMilli) { + config.roamingFailureBlackListTimeMilli = + networkSwitchingBlackListPeriodMilli; + } + config.lastRoamingFailureReason = reason; + } + void saveWifiConfigBSSID(WifiConfiguration config) { // Sanity check the config is valid if (config == null || (config.networkId == INVALID_NETWORK_ID && @@ -939,6 +1003,42 @@ public class WifiConfigStore extends IpConfigStore { } } + + /** + * Disable an ephemeral SSID for the purpose of auto-joining thru scored. + * This SSID will never be scored anymore. + * The only way to "un-disable it" is if the user create a network for that SSID and then + * forget it. + * + * @param SSID caller must ensure that the SSID passed thru this API match + * the WifiConfiguration.SSID rules, and thus be surrounded by quotes. + * @return the {@link WifiConfiguration} corresponding to this SSID, if any, so that we can + * disconnect if this is the current network. + */ + WifiConfiguration disableEphemeralNetwork(String SSID) { + if (SSID == null) { + return null; + } + + WifiConfiguration foundConfig = null; + + mDeletedEphemeralSSIDs.add(SSID); + loge("Forget ephemeral SSID " + SSID + " num=" + mDeletedEphemeralSSIDs.size()); + + for (WifiConfiguration config : mConfiguredNetworks.values()) { + if (SSID.equals(config.SSID) && config.ephemeral) { + loge("Found ephemeral config in disableEphemeralNetwork: " + config.networkId); + foundConfig = config; + } + } + + // Force a write, because the mDeletedEphemeralSSIDs list has changed even though the + // configurations may not have. + writeKnownNetworkHistory(true); + + return foundConfig; + } + /** * Forget the specified network and save config * @@ -1008,7 +1108,6 @@ public class WifiConfigStore extends IpConfigStore { } private boolean removeConfigAndSendBroadcastIfNeeded(int netId) { - boolean remove = true; WifiConfiguration config = mConfiguredNetworks.get(netId); if (config != null) { if (VDBG) { @@ -1028,65 +1127,28 @@ public class WifiConfigStore extends IpConfigStore { if (config.selfAdded || config.linkedConfigurations != null || config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { - remove = false; - loge("removeNetwork " + Integer.toString(netId) - + " key=" + config.configKey() - + " config.id=" + Integer.toString(config.networkId) - + " -> mark as deleted"); - } - - if (remove) { - mConfiguredNetworks.remove(netId); - mNetworkIds.remove(configKey(config)); - } else { - /** - * We can't directly remove the configuration since we could re-add it ourselves, - * and that would look weird to the user. - * Instead mark it as deleted and completely hide it from the rest of the system. - */ - config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_DELETED); - // Disable - mWifiNative.disableNetwork(config.networkId); - config.status = WifiConfiguration.Status.DISABLED; - // Since we don't delete the configuration, clean it up and loose the history - config.linkedConfigurations = null; - config.scanResultCache = null; - config.connectChoices = null; - config.defaultGwMacAddress = null; - config.setIpConfiguration(new IpConfiguration()); - // Loose the PSK - if (!mWifiNative.setNetworkVariable( - config.networkId, - WifiConfiguration.pskVarName, - "\"" + DELETED_CONFIG_PSK + "\"")) { - loge("removeNetwork, failed to clear PSK, nid=" + config.networkId); - } - // Loose the BSSID - config.BSSID = null; - config.autoJoinBSSID = null; - if (!mWifiNative.setNetworkVariable( - config.networkId, - WifiConfiguration.bssidVarName, - "any")) { - loge("removeNetwork, failed to remove BSSID"); - } - // Loose the hiddenSSID flag - config.hiddenSSID = false; - if (!mWifiNative.setNetworkVariable( - config.networkId, - WifiConfiguration.hiddenSSIDVarName, - Integer.toString(0))) { - loge("removeNetwork, failed to remove hiddenSSID"); + if (!TextUtils.isEmpty(config.SSID)) { + /* Remember that we deleted this PSK SSID */ + Checksum csum = new CRC32(); + if (config.SSID != null) { + csum.update(config.SSID.getBytes(), 0, config.SSID.getBytes().length); + mDeletedSSIDs.add(csum.getValue()); + } + loge("removeNetwork " + Integer.toString(netId) + + " key=" + config.configKey() + + " config.id=" + Integer.toString(config.networkId) + + " crc=" + csum.getValue()); } - - mWifiNative.saveConfig(); } + mConfiguredNetworks.remove(netId); + mNetworkIds.remove(configKey(config)); + writeIpAndProxyConfigurations(); sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); - writeKnownNetworkHistory(); + writeKnownNetworkHistory(true); } - return remove; + return true; } /** @@ -1180,17 +1242,19 @@ public class WifiConfigStore extends IpConfigStore { /* Only change the reason if the network was not previously disabled /* and the reason is not DISABLED_BY_WIFI_MANAGER, that is, if a 3rd party * set its configuration as disabled, then leave it disabled */ - if (config != null && config.status != Status.DISABLED + if (config != null) { + if (config.status != Status.DISABLED && config.disableReason != WifiConfiguration.DISABLED_BY_WIFI_MANAGER) { - config.status = Status.DISABLED; - config.disableReason = reason; - network = config; - } - if (reason == WifiConfiguration.DISABLED_BY_WIFI_MANAGER) { - // Make sure autojoin wont reenable this configuration without further user - // intervention - config.status = Status.DISABLED; - config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_DISABLED_USER_ACTION; + config.status = Status.DISABLED; + config.disableReason = reason; + network = config; + } + if (reason == WifiConfiguration.DISABLED_BY_WIFI_MANAGER) { + // Make sure autojoin wont reenable this configuration without further user + // intervention + config.status = Status.DISABLED; + config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_DISABLED_USER_ACTION; + } } if (network != null) { sendConfiguredNetworksChangedBroadcast(network, @@ -1349,64 +1413,69 @@ public class WifiConfigStore extends IpConfigStore { } void loadConfiguredNetworks() { - String listStr = mWifiNative.listNetworks(); + mLastPriority = 0; mConfiguredNetworks.clear(); mNetworkIds.clear(); - if (listStr == null) - return; + int last_id = -1; + boolean done = false; + while (!done) { - String[] lines = listStr.split("\n"); + String listStr = mWifiNative.listNetworks(last_id); + if (listStr == null) + return; - if (showNetworks) { - localLog("WifiConfigStore: loadConfiguredNetworks: "); - for (String net : lines) { - localLog(net); - } - } + 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) { - loge("Failed to read network-id '" + result[0] + "'"); - continue; + if (showNetworks) { + localLog("WifiConfigStore: loadConfiguredNetworks: "); + for (String net : lines) { + localLog(net); + } } - 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 + + // 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]); + last_id = config.networkId; + } catch(NumberFormatException e) { + loge("Failed to read network-id '" + result[0] + "'"); + 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; - } else { - config.status = WifiConfiguration.Status.ENABLED; } readNetworkVariables(config); - String psk = readNetworkVariableFromSupplicantFile(config.SSID, "psk"); - if (psk!= null && psk.equals(DELETED_CONFIG_PSK)) { - // This is a config we previously deleted, ignore it - if (showNetworks) { - localLog("found deleted network " + config.SSID + " ", config.networkId); + Checksum csum = new CRC32(); + if (config.SSID != null) { + csum.update(config.SSID.getBytes(), 0, config.SSID.getBytes().length); + long d = csum.getValue(); + if (mDeletedSSIDs.contains(d)) { + loge(" got CRC for SSID " + config.SSID + " -> " + d + ", was deleted"); } - config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_DELETED); - config.priority = 0; } if (config.priority > mLastPriority) { mLastPriority = config.priority; } - config.setIpAssignment(IpAssignment.DHCP); - config.setProxySettings(ProxySettings.NONE); + config.setIpAssignment(IpAssignment.DHCP); + config.setProxySettings(ProxySettings.NONE); if (mNetworkIds.containsKey(configKey(config))) { // That SSID is already known, just ignore this duplicate entry @@ -1443,7 +1512,10 @@ public class WifiConfigStore extends IpConfigStore { } else { if (showNetworks) log("Ignoring loaded configured for network " + config.networkId + " because config are not valid"); + } } + + done = (lines.length == 1); } readIpAndProxyConfigurations(); @@ -1565,8 +1637,14 @@ public class WifiConfigStore extends IpConfigStore { } private String readNetworkVariableFromSupplicantFile(String ssid, String key) { + long start = SystemClock.elapsedRealtimeNanos(); Map<String, String> data = readNetworkVariablesFromSupplicantFile(key); - if (VDBG) loge("readNetworkVariableFromSupplicantFile ssid=[" + ssid + "] key=" + key); + long end = SystemClock.elapsedRealtimeNanos(); + + if (VDBG) { + loge("readNetworkVariableFromSupplicantFile ssid=[" + ssid + "] key=" + key + + " duration=" + (long)(end - start)); + } return data.get(ssid); } @@ -1606,14 +1684,15 @@ public class WifiConfigStore extends IpConfigStore { return false; } - public void writeKnownNetworkHistory() { - boolean needUpdate = false; + public void writeKnownNetworkHistory(boolean force) { + boolean needUpdate = force; /* Make a copy */ final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); for (WifiConfiguration config : mConfiguredNetworks.values()) { networks.add(new WifiConfiguration(config)); if (config.dirty == true) { + loge(" rewrite network history for " + config.configKey()); config.dirty = false; needUpdate = true; } @@ -1684,8 +1763,11 @@ public class WifiConfigStore extends IpConfigStore { + SEPARATOR_KEY); out.writeUTF(DID_SELF_ADD_KEY + Boolean.toString(config.didSelfAdd) + SEPARATOR_KEY); - out.writeUTF(NO_INTERNET_ACCESS_KEY - + Boolean.toString(config.noInternetAccess) + out.writeUTF(NO_INTERNET_ACCESS_REPORTS_KEY + + Integer.toString(config.numNoInternetAccessReports) + + SEPARATOR_KEY); + out.writeUTF(VALIDATED_INTERNET_ACCESS_KEY + + Boolean.toString(config.validatedInternetAccess) + SEPARATOR_KEY); out.writeUTF(EPHEMERAL_KEY + Boolean.toString(config.ephemeral) @@ -1777,13 +1859,26 @@ public class WifiConfigStore extends IpConfigStore { out.writeUTF(SEPARATOR_KEY); out.writeUTF(SEPARATOR_KEY); } + if (mDeletedSSIDs != null && mDeletedSSIDs.size() > 0) { + for (Long i : mDeletedSSIDs) { + out.writeUTF(DELETED_CRC32_KEY); + out.writeUTF(String.valueOf(i)); + out.writeUTF(SEPARATOR_KEY); + } + } + if (mDeletedEphemeralSSIDs != null && mDeletedEphemeralSSIDs.size() > 0) { + for (String ssid : mDeletedEphemeralSSIDs) { + out.writeUTF(DELETED_EPHEMERAL_KEY); + out.writeUTF(ssid); + out.writeUTF(SEPARATOR_KEY); + } + } } - }); } public void setLastSelectedConfiguration(int netId) { - if (DBG) { + if (VDBG) { loge("setLastSelectedConfiguration " + Integer.toString(netId)); } if (netId == WifiConfiguration.INVALID_NETWORK_ID) { @@ -1797,6 +1892,7 @@ public class WifiConfigStore extends IpConfigStore { selected.numConnectionFailures = 0; selected.numIpConfigFailures = 0; selected.numAuthFailures = 0; + selected.numNoInternetAccessReports = 0; if (VDBG) { loge("setLastSelectedConfiguration now: " + lastSelectedConfiguration); } @@ -1914,10 +2010,16 @@ public class WifiConfigStore extends IpConfigStore { config.didSelfAdd = Boolean.parseBoolean(didSelfAdd); } - if (key.startsWith(NO_INTERNET_ACCESS_KEY)) { - String access = key.replace(NO_INTERNET_ACCESS_KEY, ""); + if (key.startsWith(NO_INTERNET_ACCESS_REPORTS_KEY)) { + String access = key.replace(NO_INTERNET_ACCESS_REPORTS_KEY, ""); + access = access.replace(SEPARATOR_KEY, ""); + config.numNoInternetAccessReports = Integer.parseInt(access); + } + + if (key.startsWith(VALIDATED_INTERNET_ACCESS_KEY)) { + String access = key.replace(VALIDATED_INTERNET_ACCESS_KEY, ""); access = access.replace(SEPARATOR_KEY, ""); - config.noInternetAccess = Boolean.parseBoolean(access); + config.validatedInternetAccess = Boolean.parseBoolean(access); } if (key.startsWith(EPHEMERAL_KEY)) { @@ -2081,7 +2183,6 @@ public class WifiConfigStore extends IpConfigStore { } if (key.startsWith(BSSID_KEY_END)) { - if ((bssid != null) && (ssid != null)) { if (config.scanResultCache == null) { @@ -2095,6 +2196,19 @@ public class WifiConfigStore extends IpConfigStore { result.autoJoinStatus = status; } } + + if (key.startsWith(DELETED_CRC32_KEY)) { + String crc = key.replace(DELETED_CRC32_KEY, ""); + Long c = Long.parseLong(crc); + mDeletedSSIDs.add(c); + } + if (key.startsWith(DELETED_EPHEMERAL_KEY)) { + String s = key.replace(DELETED_EPHEMERAL_KEY, ""); + if (!TextUtils.isEmpty(s)) { + s = s.replace(SEPARATOR_KEY, ""); + mDeletedEphemeralSSIDs.add(s); + } + } } } } @@ -2556,7 +2670,7 @@ public class WifiConfigStore extends IpConfigStore { private void readIpAndProxyConfigurations() { SparseArray<IpConfiguration> networks = super.readIpAndProxyConfigurations(ipConfigFile); - if (networks.size() == 0) { + if (networks == null || networks.size() == 0) { // IpConfigStore.readIpAndProxyConfigurations has already logged an error. return; } @@ -2565,7 +2679,9 @@ public class WifiConfigStore extends IpConfigStore { int id = networks.keyAt(i); WifiConfiguration config = mConfiguredNetworks.get(mNetworkIds.get(id)); - if (config == null || config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) { + + if (config == null || config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || + config.ephemeral) { loge("configuration found for missing network, nid=" + id +", ignored, networks.size=" + Integer.toString(networks.size())); } else if (config != null && config.duplicateNetwork == true) { @@ -2925,6 +3041,14 @@ public class WifiConfigStore extends IpConfigStore { currentConfig.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); } + if (currentConfig.configKey().equals(getLastSelectedConfiguration()) && + currentConfig.ephemeral) { + // Make the config non-ephemeral since the user just explicitly clicked it. + currentConfig.ephemeral = false; + if (DBG) loge("remove ephemeral status netId=" + Integer.toString(netId) + + " " + currentConfig.configKey()); + } + if (DBG) loge("will read network variables netId=" + Integer.toString(netId)); readNetworkVariables(currentConfig); @@ -2936,7 +3060,7 @@ public class WifiConfigStore extends IpConfigStore { result.setIsNewNetwork(newNetwork); result.setNetworkId(netId); - writeKnownNetworkHistory(); + writeKnownNetworkHistory(false); return result; } @@ -2963,7 +3087,7 @@ public class WifiConfigStore extends IpConfigStore { continue; } - if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) { + if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || link.ephemeral) { continue; } @@ -3079,6 +3203,7 @@ public class WifiConfigStore extends IpConfigStore { * */ public WifiConfiguration associateWithConfiguration(ScanResult result) { + boolean doNotAdd = false; String configKey = WifiConfiguration.configKey(result); if (configKey == null) { if (DBG) loge("associateWithConfiguration(): no config key " ); @@ -3092,11 +3217,18 @@ public class WifiConfigStore extends IpConfigStore { loge("associateWithConfiguration(): try " + configKey); } + Checksum csum = new CRC32(); + csum.update(SSID.getBytes(), 0, SSID.getBytes().length); + if (mDeletedSSIDs.contains(csum.getValue())) { + doNotAdd = true; + } + WifiConfiguration config = null; for (WifiConfiguration link : mConfiguredNetworks.values()) { boolean doLink = false; - if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || link.selfAdded) { + if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || link.selfAdded || + link.ephemeral) { if (VVDBG) loge("associateWithConfiguration(): skip selfadd " + link.configKey() ); // Make sure we dont associate the scan result to a deleted config continue; @@ -3113,7 +3245,7 @@ public class WifiConfigStore extends IpConfigStore { return link; // Found it exactly } - if ((link.scanResultCache != null) && (link.scanResultCache.size() <= 6)) { + if (!doNotAdd && (link.scanResultCache != null) && (link.scanResultCache.size() <= 6)) { for (String bssid : link.scanResultCache.keySet()) { if (result.BSSID.regionMatches(true, 0, bssid, 0, 16) && SSID.regionMatches(false, 0, link.SSID, 0, 4)) { @@ -3134,8 +3266,9 @@ public class WifiConfigStore extends IpConfigStore { // Try to make a non verified WifiConfiguration, but only if the original // configuration was not self already added if (VDBG) { - loge("associateWithConfiguration: will create " + - result.SSID + " and associate it with: " + link.SSID); + loge("associateWithConfiguration: try to create " + + result.SSID + " and associate it with: " + link.SSID + + " key " + link.configKey()); } config = wifiConfigurationFromScanResult(result); if (config != null) { @@ -3145,6 +3278,10 @@ public class WifiConfigStore extends IpConfigStore { config.peerWifiConfiguration = link.configKey(); if (config.allowedKeyManagement.equals(link.allowedKeyManagement) && config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { + if (VDBG && config != null) { + loge("associateWithConfiguration: got a config from beacon" + + config.SSID + " key " + config.configKey()); + } // Transfer the credentials from the configuration we are linking from String psk = readNetworkVariableFromSupplicantFile(link.SSID, "psk"); if (psk != null) { @@ -3163,6 +3300,11 @@ public class WifiConfigStore extends IpConfigStore { } link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); + + // Carry over the Ip configuration + if (link.getIpConfiguration() != null) { + config.setIpConfiguration(link.getIpConfiguration()); + } } else { config = null; } @@ -3171,6 +3313,10 @@ public class WifiConfigStore extends IpConfigStore { } if (config != null) break; } + if (VDBG && config != null) { + loge("associateWithConfiguration: success, created: " + config.SSID + + " key " + config.configKey()); + } } } return config; @@ -3325,6 +3471,36 @@ public class WifiConfigStore extends IpConfigStore { scanResult.isAutoJoinCandidate = result.isAutoJoinCandidate; } + if (config.ephemeral) { + // For an ephemeral Wi-Fi config, the ScanResult should be considered + // untrusted. + scanResult.untrusted = true; + } + + if (config.scanResultCache.size() > (maxNumScanCacheEntries + 64)) { + long now_dbg = 0; + if (VVDBG) { + loge(" Will trim config " + config.configKey() + + " size " + config.scanResultCache.size()); + + for (ScanResult r : config.scanResultCache.values()) { + loge(" " + result.BSSID + " " + result.seen); + } + now_dbg = SystemClock.elapsedRealtimeNanos(); + } + // Trim the scan result cache to maxNumScanCacheEntries entries max + // Since this operation is expensive, make sure it is not performed + // until the cache has grown significantly above the trim treshold + config.trimScanResultsCache(maxNumScanCacheEntries); + if (VVDBG) { + long diff = SystemClock.elapsedRealtimeNanos() - now_dbg; + loge(" Finished trimming config, time(ns) " + diff); + for (ScanResult r : config.scanResultCache.values()) { + loge(" " + r.BSSID + " " + r.seen); + } + } + } + // Add the scan result to this WifiConfiguration config.scanResultCache.put(scanResult.BSSID, scanResult); // Since we added a scan result to this configuration, re-attempt linking diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java index 14903091e..7ececb9e5 100755 --- a/service/java/com/android/server/wifi/WifiMonitor.java +++ b/service/java/com/android/server/wifi/WifiMonitor.java @@ -633,6 +633,14 @@ public class WifiMonitor { } public synchronized void killSupplicant(boolean p2pSupported) { + String suppState = System.getProperty("init.svc.wpa_supplicant"); + if (suppState == null) suppState = "unknown"; + String p2pSuppState = System.getProperty("init.svc.p2p_supplicant"); + if (p2pSuppState == null) p2pSuppState = "unknown"; + + Log.e(TAG, "killSupplicant p2p" + p2pSupported + + " init.svc.wpa_supplicant=" + suppState + + " init.svc.p2p_supplicant=" + p2pSuppState); WifiNative.killSupplicant(p2pSupported); mConnected = false; for (WifiMonitor m : mIfaceMap.values()) { @@ -683,12 +691,25 @@ public class WifiMonitor { } else { if (DBG) Log.d(TAG, "Sending to all monitors because there's no matching iface"); boolean done = false; + boolean isMonitoring = false; + boolean isTerminating = false; + if (eventStr.startsWith(EVENT_PREFIX_STR) + && eventStr.contains(TERMINATING_STR)) { + isTerminating = true; + } for (WifiMonitor monitor : mIfaceMap.values()) { - if (monitor.mMonitoring && monitor.dispatchEvent(eventStr, iface)) { - done = true; + if (monitor.mMonitoring) { + isMonitoring = true; + if (monitor.dispatchEvent(eventStr, iface)) { + done = true; + } } } + if (!isMonitoring && isTerminating) { + done = true; + } + if (done) { mConnected = false; } @@ -983,8 +1004,6 @@ public class WifiMonitor { Matcher match = mTargetBSSIDPattern.matcher(eventStr); if (match.find()) { BSSID = match.group(1); - } else { - Log.d(TAG, "didn't find BSSID " + eventStr); } mStateMachine.sendMessage(WifiStateMachine.CMD_TARGET_BSSID, eventLogCounter, 0, BSSID); } @@ -994,8 +1013,6 @@ public class WifiMonitor { Matcher match = mAssociatedPattern.matcher(eventStr); if (match.find()) { BSSID = match.group(1); - } else { - Log.d(TAG, "handleAssociatedBSSIDEvent: didn't find BSSID " + eventStr); } mStateMachine.sendMessage(WifiStateMachine.CMD_ASSOCIATED_BSSID, eventLogCounter, 0, BSSID); } diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index 6b813639d..ac2fb2f61 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -254,6 +254,10 @@ public class WifiNative { return doStringCommand("LIST_NETWORKS"); } + public String listNetworks(int last_id) { + return doStringCommand("LIST_NETWORKS LAST_ID=" + last_id); + } + public int addNetwork() { return doIntCommand("ADD_NETWORK"); } @@ -1140,6 +1144,7 @@ public class WifiNative { private static int sP2p0Index = -1; private static boolean sHalIsStarted = false; + private static boolean sHalFailed = false; private static native boolean startHalNative(); private static native void stopHalNative(); @@ -1157,14 +1162,16 @@ public class WifiNative { synchronized (mLock) { if (sHalIsStarted) return true; - if (startHalNative()) { - getInterfaces(); + if (sHalFailed) + return false; + if (startHalNative() && (getInterfaces() != 0) && (sWlan0Index != -1)) { new MonitorThread().start(); sHalIsStarted = true; return true; } else { Log.i(TAG, "Could not start hal"); sHalIsStarted = false; + sHalFailed = true; return false; } } @@ -1283,15 +1290,21 @@ public class WifiNative { if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID + ", " + "num = " + bytes.length); + if (sScanEventHandler == null) { + return; + } + int num = 0; for (int i = 0; i < bytes.length; ) { - num++; - int type = (int) bytes[i] & 0xFF; - int len = (int) bytes[i + 1] & 0xFF; - if (len < 0) { - Log.e(TAG, "bad length; returning"); - return; + int type = bytes[i] & 0xFF; + int len = bytes[i + 1] & 0xFF; + + if (i + len + 2 > bytes.length) { + Log.w(TAG, "bad length " + len + " of IE " + type + " from " + result.BSSID); + Log.w(TAG, "ignoring the rest of the IEs"); + break; } + num++; i += len + 2; if (DBG) Log.i(TAG, "bytes[" + i + "] = [" + type + ", " + len + "]" + ", " + "next = " + i); @@ -1299,8 +1312,8 @@ public class WifiNative { ScanResult.InformationElement elements[] = new ScanResult.InformationElement[num]; for (int i = 0, index = 0; i < num; i++) { - int type = (int) bytes[index] & 0xFF; - int len = (int) bytes[index + 1] & 0xFF; + int type = bytes[index] & 0xFF; + int len = bytes[index + 1] & 0xFF; if (DBG) Log.i(TAG, "index = " + index + ", type = " + type + ", len = " + len); ScanResult.InformationElement elem = new ScanResult.InformationElement(); elem.id = type; @@ -1313,9 +1326,7 @@ public class WifiNative { } result.informationElements = elements; - if (sScanEventHandler != null) { - sScanEventHandler.onFullScanResult(result); - } + sScanEventHandler.onFullScanResult(result); } private static int sScanCmdId = 0; diff --git a/service/java/com/android/server/wifi/WifiNetworkScoreCache.java b/service/java/com/android/server/wifi/WifiNetworkScoreCache.java index 382b311f9..0a7df0b0e 100644 --- a/service/java/com/android/server/wifi/WifiNetworkScoreCache.java +++ b/service/java/com/android/server/wifi/WifiNetworkScoreCache.java @@ -34,8 +34,10 @@ import java.util.Map; public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { - // A Network scorer returns a score in the range [-127, +127] - public static int INVALID_NETWORK_SCORE = 100000; + // A Network scorer returns a score in the range [-128, +127] + // We treat the lowest possible score as though there were no score, effectively allowing the + // scorer to provide an RSSI threshold below which a network should not be used. + public static int INVALID_NETWORK_SCORE = Byte.MIN_VALUE; private static String TAG = "WifiNetworkScoreCache"; private boolean DBG = true; @@ -71,63 +73,69 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub } } + /** + * Returns whether there is any score info for the given ScanResult. + * + * This includes null-score info, so it should only be used when determining whether to request + * scores from the network scorer. + */ public boolean isScoredNetwork(ScanResult result) { - String key = buildNetworkKey(result); - if (key == null) return false; + return getScoredNetwork(result) != null; + } - //find it - synchronized(mNetworkCache) { - ScoredNetwork network = mNetworkCache.get(key); - if (network != null) { - return true; - } - } - return false; + /** + * Returns whether there is a non-null score curve for the given ScanResult. + * + * A null score curve has special meaning - we should never connect to an ephemeral network if + * the score curve is null. + */ + public boolean hasScoreCurve(ScanResult result) { + ScoredNetwork network = getScoredNetwork(result); + return network != null && network.rssiCurve != null; } public int getNetworkScore(ScanResult result) { int score = INVALID_NETWORK_SCORE; - String key = buildNetworkKey(result); - if (key == null) return score; - - //find it - synchronized(mNetworkCache) { - ScoredNetwork network = mNetworkCache.get(key); - if (network != null && network.rssiCurve != null) { - score = network.rssiCurve.lookupScore(result.level); - if (DBG) { - Log.e(TAG, "getNetworkScore found scored network " + key - + " score " + Integer.toString(score) - + " RSSI " + result.level); - } + ScoredNetwork network = getScoredNetwork(result); + if (network != null && network.rssiCurve != null) { + score = network.rssiCurve.lookupScore(result.level); + if (DBG) { + Log.e(TAG, "getNetworkScore found scored network " + network.networkKey + + " score " + Integer.toString(score) + + " RSSI " + result.level); } } return score; } - public int getNetworkScore(ScanResult result, int rssiBoost) { + public int getNetworkScore(ScanResult result, boolean isActiveNetwork) { int score = INVALID_NETWORK_SCORE; + ScoredNetwork network = getScoredNetwork(result); + if (network != null && network.rssiCurve != null) { + score = network.rssiCurve.lookupScore(result.level, isActiveNetwork); + if (DBG) { + Log.e(TAG, "getNetworkScore found scored network " + network.networkKey + + " score " + Integer.toString(score) + + " RSSI " + result.level + + " isActiveNetwork " + isActiveNetwork); + } + } + return score; + } + + private ScoredNetwork getScoredNetwork(ScanResult result) { String key = buildNetworkKey(result); - if (key == null) return score; + if (key == null) return null; //find it synchronized(mNetworkCache) { ScoredNetwork network = mNetworkCache.get(key); - if (network != null && network.rssiCurve != null) { - score = network.rssiCurve.lookupScore(result.level + rssiBoost); - if (DBG) { - Log.e(TAG, "getNetworkScore found scored network " + key - + " score " + Integer.toString(score) - + " RSSI " + result.level - + " boost " + rssiBoost); - } - } + return network; } - return score; } private String buildNetworkKey(ScoredNetwork network) { diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index 7589673d0..586eae2a7 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -16,6 +16,7 @@ package com.android.server.wifi; +import android.Manifest; import android.app.ActivityManager; import android.app.AppOpsManager; import android.bluetooth.BluetoothAdapter; @@ -391,6 +392,30 @@ public final class WifiServiceImpl extends IWifiManager.Stub { } } + // Start a location scan. + // L release: A location scan is implemented as a normal scan and avoids scanning DFS channels + public void startLocationRestrictedScan(WorkSource workSource) { + enforceChangePermission(); + enforceLocationHardwarePermission(); + List<WifiChannel> channels = getChannelList(); + if (channels == null) { + Slog.e(TAG, "startLocationRestrictedScan cant get channels"); + return; + } + ScanSettings settings = new ScanSettings(); + for (WifiChannel channel : channels) { + if (!channel.isDFS) { + settings.channelSet.add(channel); + } + } + if (workSource == null) { + // Make sure we always have a workSource indicating the origin of the scan + // hence if there is none, pick an internal WifiStateMachine one + workSource = new WorkSource(WifiStateMachine.DFS_RESTRICTED_SCAN_REQUEST); + } + startScan(settings, workSource); + } + /** * see {@link android.net.wifi.WifiManager#startScan} * and {@link android.net.wifi.WifiManager#startCustomizedScan} @@ -401,9 +426,6 @@ public final class WifiServiceImpl extends IWifiManager.Stub { public void startScan(ScanSettings settings, WorkSource workSource) { enforceChangePermission(); if (settings != null) { - // TODO: should be removed once the startCustomizedScan API is opened up - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.LOCATION_HARDWARE, - "LocationHardware"); settings = new ScanSettings(settings); if (!settings.isValid()) { Slog.e(TAG, "invalid scan setting"); @@ -490,13 +512,14 @@ public final class WifiServiceImpl extends IWifiManager.Stub { if (mBatchedScanSupported == false) return new ArrayList<BatchedScanResult>(); int uid = Binder.getCallingUid(); int userId = UserHandle.getCallingUserId(); + boolean hasInteractUsersFull = checkInteractAcrossUsersFull(); long ident = Binder.clearCallingIdentity(); try { if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage) != AppOpsManager.MODE_ALLOWED) { return new ArrayList<BatchedScanResult>(); } - if (!isCurrentProfile(userId)) { + if (!isCurrentProfile(userId) && !hasInteractUsersFull) { return new ArrayList<BatchedScanResult>(); } return mWifiStateMachine.syncGetBatchedScanResultsList(); @@ -615,7 +638,11 @@ public final class WifiServiceImpl extends IWifiManager.Stub { private void enforceChangePermission() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, "WifiService"); + } + private void enforceLocationHardwarePermission() { + mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, + "LocationHardware"); } private void enforceReadCredentialPermission() { @@ -970,13 +997,14 @@ public final class WifiServiceImpl extends IWifiManager.Stub { enforceAccessPermission(); int userId = UserHandle.getCallingUserId(); int uid = Binder.getCallingUid(); + boolean hasInteractUsersFull = checkInteractAcrossUsersFull(); long ident = Binder.clearCallingIdentity(); try { if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage) != AppOpsManager.MODE_ALLOWED) { return new ArrayList<ScanResult>(); } - if (!isCurrentProfile(userId)) { + if (!isCurrentProfile(userId) && !hasInteractUsersFull) { return new ArrayList<ScanResult>(); } return mWifiStateMachine.syncGetScanResultsList(); @@ -986,6 +1014,15 @@ public final class WifiServiceImpl extends IWifiManager.Stub { } /** + * Returns true if the caller holds INTERACT_ACROSS_USERS_FULL. + */ + private boolean checkInteractAcrossUsersFull() { + return mContext.checkCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) + == PackageManager.PERMISSION_GRANTED; + } + + /** * Returns true if the calling user is the current one or a profile of the * current user.. */ @@ -1301,6 +1338,14 @@ public final class WifiServiceImpl extends IWifiManager.Stub { return new Messenger(mClientHandler); } + /** + * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer + */ + public void disableEphemeralNetwork(String SSID) { + enforceAccessPermission(); + enforceChangePermission(); + mWifiStateMachine.disableEphemeralNetwork(SSID); + } /** * Get the IP and proxy configuration file diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 8f0d950bf..fabc85b98 100644..100755 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -16,22 +16,22 @@ package com.android.server.wifi; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; -import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; - /** * TODO: * Deprecate WIFI_STATE_UNKNOWN */ -import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; +import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; +import android.app.ActivityManager; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.backup.IBackupManager; @@ -53,12 +53,27 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; +import android.net.NetworkRequest; import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.StaticIpConfiguration; import android.net.TrafficStats; -import android.net.wifi.*; +import android.net.wifi.BatchedScanResult; +import android.net.wifi.BatchedScanSettings; +import android.net.wifi.RssiPacketCountInfo; +import android.net.wifi.ScanResult; +import android.net.wifi.ScanSettings; import android.net.wifi.SupplicantState; +import android.net.wifi.WifiChannel; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConnectionStatistics; +import android.net.wifi.WifiEnterpriseConfig; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiLinkLayerStats; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiSsid; +import android.net.wifi.WpsInfo; +import android.net.wifi.WpsResult; import android.net.wifi.WpsResult.Status; import android.net.wifi.p2p.IWifiP2pManager; import android.os.BatteryStats; @@ -78,9 +93,9 @@ import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; import android.telephony.TelephonyManager; -import android.util.LruCache; import android.text.TextUtils; import android.util.Log; +import android.util.LruCache; import com.android.internal.R; import com.android.internal.app.IBatteryStats; @@ -88,24 +103,28 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; -import com.android.server.net.BaseNetworkObserver; import com.android.server.net.NetlinkTracker; - import com.android.server.wifi.p2p.WifiP2pServiceImpl; import android.net.wifi.p2p.WifiP2pManager; +import java.io.BufferedReader; import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; import java.io.PrintWriter; +import java.net.Inet4Address; import java.net.InetAddress; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Queue; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.io.FileReader; -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.Inet4Address; /** * Track the state of Wifi connectivity. All event handling is done here, @@ -121,6 +140,7 @@ import java.net.Inet4Address; public class WifiStateMachine extends StateMachine { private static final String NETWORKTYPE = "WIFI"; + private static final String NETWORKTYPE_UNTRUSTED = "WIFI_UT"; private static boolean DBG = false; private static boolean VDBG = false; private static boolean VVDBG = false; @@ -229,11 +249,16 @@ public class WifiStateMachine extends StateMachine { private int mOperationalMode = CONNECT_MODE; private boolean mIsScanOngoing = false; private boolean mIsFullScanOngoing = false; + private boolean mSendScanResultsBroadcast = false; + private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>(); private WorkSource mScanWorkSource = null; private static final int UNKNOWN_SCAN_SOURCE = -1; private static final int SCAN_ALARM_SOURCE = -2; private static final int ADD_OR_UPDATE_SOURCE = -3; + private static final int SET_ALLOW_UNTRUSTED_SOURCE = -4; + private static final int ENABLE_WIFI = -5; + public static final int DFS_RESTRICTED_SCAN_REQUEST = -6; private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10; private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings"; @@ -332,6 +357,7 @@ public class WifiStateMachine extends StateMachine { // This is the BSSID we are trying to associate to, it can be set to "any" // if we havent selected a BSSID for joining. + // if we havent selected a BSSID for joining. // The BSSID we are associated to is found in mWifiInfo private String mTargetRoamBSSID = "any"; @@ -406,7 +432,9 @@ public class WifiStateMachine extends StateMachine { private AsyncChannel mWifiP2pChannel; private AsyncChannel mWifiApConfigChannel; + private int mConnectionRequests = 0; private WifiNetworkFactory mNetworkFactory; + private UntrustedWifiNetworkFactory mUntrustedNetworkFactory; private WifiNetworkAgent mNetworkAgent; // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi @@ -581,6 +609,9 @@ public class WifiStateMachine extends StateMachine { /* Disconnecting state watchdog */ static final int CMD_DISCONNECTING_WATCHDOG_TIMER = BASE + 96; + /* Disable an ephemeral network */ + static final int CMD_DISABLE_EPHEMERAL_NETWORK = BASE + 98; + /* P2p commands */ /* We are ok with no response here since we wont do much with it anyway */ public static final int CMD_ENABLE_P2P = BASE + 131; @@ -626,10 +657,12 @@ public class WifiStateMachine extends StateMachine { static final int CMD_ASSOCIATED_BSSID = BASE + 147; + static final int CMD_NETWORK_STATUS = BASE + 148; + /* Supplicant is trying to associate to a given SSID */ - static final int CMD_TARGET_SSID = BASE + 148; + static final int CMD_TARGET_SSID = BASE + 149; - static final int CMD_GET_SIM_INFO = BASE + 149; + static final int CMD_GET_SIM_INFO = BASE + 150; /* Wifi state machine modes of operation */ /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ @@ -871,6 +904,8 @@ public class WifiStateMachine extends StateMachine { private static int DEFAULT_SCORE = NetworkAgent.WIFI_BASE_SCORE; + final static int frameworkMinScanIntervalSaneValue = 10000; + public WifiStateMachine(Context context, String wlanInterface, WifiTrafficPoller trafficPoller){ super("WifiStateMachine"); @@ -916,15 +951,16 @@ public class WifiStateMachine extends StateMachine { } mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - Intent scanIntent = new Intent(ACTION_START_SCAN, null); - mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); + mScanIntent = getPrivateBroadcast(ACTION_START_SCAN, SCAN_REQUEST); + mBatchedScanIntervalIntent = getPrivateBroadcast(ACTION_REFRESH_BATCHED_SCAN, 0); - Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); - mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0); - - mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger( + // Make sure the interval is not configured less than 10 seconds + int period = mContext.getResources().getInteger( R.integer.config_wifi_framework_scan_interval); - + if (period < frameworkMinScanIntervalSaneValue) { + period = frameworkMinScanIntervalSaneValue; + } + mDefaultFrameworkScanIntervalMs = period; mDriverStopDelayMs = mContext.getResources().getInteger( R.integer.config_wifi_driver_stop_delay); @@ -961,10 +997,10 @@ public class WifiStateMachine extends StateMachine { new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - sScanAlarmIntentCount++; - startScan(SCAN_ALARM_SOURCE, -2, null, null); + sScanAlarmIntentCount++; // Used for debug only + startScan(SCAN_ALARM_SOURCE, mDelayedScanCounter.incrementAndGet(), null, null); if (VDBG) - loge("WiFiStateMachine SCAN ALARM"); + loge("WiFiStateMachine SCAN ALARM -> " + mDelayedScanCounter.get()); } }, new IntentFilter(ACTION_START_SCAN)); @@ -1080,7 +1116,7 @@ public class WifiStateMachine extends StateMachine { setInitialState(mInitialState); - setLogRecSize(3000); + setLogRecSize(ActivityManager.isLowRamDeviceStatic() ? 100 : 3000); setLogOnlyTransitions(false); if (VDBG) setDbg(true); @@ -1093,6 +1129,14 @@ public class WifiStateMachine extends StateMachine { mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } + + PendingIntent getPrivateBroadcast(String action, int requestCode) { + Intent intent = new Intent(action, null); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.setPackage(this.getClass().getPackage().getName()); + return PendingIntent.getBroadcast(mContext, requestCode, intent, 0); + } + private int mVerboseLoggingLevel = 0; int getVerboseLoggingLevel() { @@ -1151,35 +1195,27 @@ public class WifiStateMachine extends StateMachine { */ private long mFrameworkScanIntervalMs = 10000; - private long mCurrentScanAlarmMs = 10000; - private void setScanAlarm(boolean enabled, int delayMilli) { + private AtomicInteger mDelayedScanCounter = new AtomicInteger(); + + private void setScanAlarm(boolean enabled) { if (PDBG) { loge("setScanAlarm " + enabled - + " period " + mCurrentScanAlarmMs - + " initial delay " + delayMilli); + + " period " + mDefaultFrameworkScanIntervalMs + + " mBackgroundScanSupported " + mBackgroundScanSupported); } - if (mCurrentScanAlarmMs <= 0) enabled = false; + if (mBackgroundScanSupported == false) { + // Scan alarm is only used for background scans if they are not + // offloaded to the wifi chipset, hence enable the scan alarm + // gicing us RTC_WAKEUP of backgroundScan is NOT supported + enabled = true; + } + if (enabled == mAlarmEnabled) return; if (enabled) { - long initialDelayMilli; - if (delayMilli <= 0) { - // scan now - startScan(SCAN_ALARM_SOURCE, 0, null, null); - initialDelayMilli = mCurrentScanAlarmMs; - } else { - initialDelayMilli = delayMilli; - } - - int type = AlarmManager.RTC; - /* Set RTC_WAKEUP alarms if PNO is not supported - because no one is */ /* going to wake up the host processor to look for access points */ - if (mBackgroundScanSupported == false) - type = AlarmManager.RTC_WAKEUP; - - mAlarmManager.setRepeating(type, - System.currentTimeMillis() + initialDelayMilli, - mCurrentScanAlarmMs, + mAlarmManager.set(AlarmManager.RTC_WAKEUP, + System.currentTimeMillis() + mDefaultFrameworkScanIntervalMs, mScanIntent); mAlarmEnabled = true; } else { @@ -1188,6 +1224,53 @@ public class WifiStateMachine extends StateMachine { } } + private void cancelDelayedScan() { + mDelayedScanCounter.incrementAndGet(); + loge("cancelDelayedScan -> " + mDelayedScanCounter); + } + + private boolean checkAndRestartDelayedScan(int counter, boolean restart, int milli, + ScanSettings settings, WorkSource workSource) { + if (counter != mDelayedScanCounter.get()) { + return false; + } + if (restart) + startDelayedScan(milli, settings, workSource); + return true; + } + + private void startDelayedScan(int milli, ScanSettings settings, WorkSource workSource) { + if (milli <= 0) return; + /** + * The cases where the scan alarm should be run are : + * - DisconnectedState && screenOn => used delayed timer + * - DisconnectedState && !screenOn && mBackgroundScanSupported => PNO + * - DisconnectedState && !screenOn && !mBackgroundScanSupported => used RTC_WAKEUP Alarm + * - ConnectedState && screenOn => used delayed timer + */ + + mDelayedScanCounter.incrementAndGet(); + if (mScreenOn && + (getCurrentState() == mDisconnectedState + || getCurrentState() == mConnectedState)) { + Bundle bundle = new Bundle(); + bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); + bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); + bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis()); + sendMessageDelayed(CMD_START_SCAN, SCAN_ALARM_SOURCE, + mDelayedScanCounter.get(), bundle, milli); + if (DBG) loge("startDelayedScan send -> " + mDelayedScanCounter + " milli " + milli); + } else if (mBackgroundScanSupported == false + && !mScreenOn && getCurrentState() == mDisconnectedState) { + setScanAlarm(true); + if (DBG) loge("startDelayedScan start scan alarm -> " + + mDelayedScanCounter + " milli " + milli); + } else { + if (DBG) loge("startDelayedScan unhandled -> " + + mDelayedScanCounter + " milli " + milli); + } + } + private boolean setRandomMacOui() { String oui = mContext.getResources().getString( R.string.config_wifi_random_mac_oui, GOOGLE_OUI); @@ -1251,6 +1334,13 @@ public class WifiStateMachine extends StateMachine { return (list != null && list.size() > 0) ? list : null; } + /** + * When settings allowing making use of untrusted networks change, trigger a scan + * so as to kick of autojoin. + */ + public void startScanForUntrustedSettingChange() { + startScan(SET_ALLOW_UNTRUSTED_SOURCE, 0, null, null); + } /** * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is @@ -1613,7 +1703,7 @@ public class WifiStateMachine extends StateMachine { private static int MESSAGE_HANDLING_STATUS_UNKNOWN = 0; private static int MESSAGE_HANDLING_STATUS_REFUSED = -1; private static int MESSAGE_HANDLING_STATUS_FAIL = -2; - private static int MESSAGE_HANDLING_STATUS_BUFFERED = -3; + private static int MESSAGE_HANDLING_STATUS_OBSOLETE = -3; private static int MESSAGE_HANDLING_STATUS_DEFERRED = -4; private static int MESSAGE_HANDLING_STATUS_DISCARD = -5; private static int MESSAGE_HANDLING_STATUS_LOOPED = -6; @@ -1624,9 +1714,11 @@ public class WifiStateMachine extends StateMachine { //TODO: this is used only to track connection attempts, however the link state and packet per //TODO: second logic should be folded into that - private boolean isScanAllowed(int scanSource) { + private boolean checkOrDeferScanAllowed(Message msg) { long now = System.currentTimeMillis(); if (lastConnectAttempt != 0 && (now - lastConnectAttempt) < 10000) { + Message dmsg = Message.obtain(msg); + sendMessageDelayed(dmsg, 11000 - (now - lastConnectAttempt)); return false; } if (mP2pConnected.get()) { @@ -1714,11 +1806,17 @@ public class WifiStateMachine extends StateMachine { mRxTime = stats.rx_time; mRunningBeaconCount = stats.beacon_rx; if (dbg) { - loge("WifiLinkLayerStats:"); loge(stats.toString()); } } } + if (stats == null || mWifiLinkLayerStatsSupported <= 0) { + long mTxPkts = TrafficStats.getTxPackets(mInterfaceName); + long mRxPkts = TrafficStats.getRxPackets(mInterfaceName); + mWifiInfo.updatePacketRates(mTxPkts, mRxPkts); + } else { + mWifiInfo.updatePacketRates(stats); + } return stats; } @@ -1757,7 +1855,8 @@ public class WifiStateMachine extends StateMachine { loge(ts + " noteScanStart" + workSource.toString() + " uid " + Integer.toString(callingUid)); } else { - loge(ts + " noteScanstart no scan source"); + loge(ts + " noteScanstart no scan source" + + " uid " + Integer.toString(callingUid)); } } startRadioScanStats(); @@ -1782,9 +1881,11 @@ public class WifiStateMachine extends StateMachine { if (DBG) { String ts = String.format("[%,d ms]", now); if (mScanWorkSource != null) - loge(ts + " noteScanEnd " + mScanWorkSource.toString()); + loge(ts + " noteScanEnd " + mScanWorkSource.toString() + + " onTime=" + mOnTimeThisScan); else - loge(ts + " noteScanEnd no scan source"); + loge(ts + " noteScanEnd no scan source" + + " onTime=" + mOnTimeThisScan); } if (mScanWorkSource != null) { try { @@ -1839,10 +1940,16 @@ public class WifiStateMachine extends StateMachine { } private void handleScanRequest(int type, Message message) { + ScanSettings settings = null; + WorkSource workSource = null; + // unbundle parameters Bundle bundle = (Bundle) message.obj; - ScanSettings settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); - WorkSource workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); + + if (bundle != null) { + settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); + workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); + } // parse scan settings String freqs = null; @@ -1864,6 +1971,11 @@ public class WifiStateMachine extends StateMachine { if (freqs == null) mBufferedScanMsg.clear(); messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK; + if (workSource != null) { + // External worksource was passed along the scan request, + // hence always send a broadcast + mSendScanResultsBroadcast = true; + } return; } @@ -2052,6 +2164,12 @@ public class WifiStateMachine extends StateMachine { } } + public void disableEphemeralNetwork(String SSID) { + if (SSID != null) { + sendMessage(CMD_DISABLE_EPHEMERAL_NETWORK, SSID); + } + } + /** * Get unsynchronized pointer to scan result list * Can be called only from AutoJoinController which runs in the WifiStateMachine context @@ -2067,6 +2185,10 @@ public class WifiStateMachine extends StateMachine { sendMessage(CMD_DISCONNECT); } + public void disconnectCommand(int uid, int reason) { + sendMessage(CMD_DISCONNECT, uid, reason); + } + /** * Initiate a reconnection to AP */ @@ -2216,6 +2338,13 @@ public class WifiStateMachine extends StateMachine { return mWifiNative.getNfcWpsConfigurationToken(netId); } + void enableBackgroundScan(boolean enable) { + if (enable) { + mWifiConfigStore.enableAllNetworks(); + } + mWifiNative.enableBackgroundScan(enable); + } + /** * Blacklist a BSSID. This will avoid the AP if there are * alternate APs to connect @@ -2410,6 +2539,8 @@ public class WifiStateMachine extends StateMachine { pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); pw.println("mLastSetCountryCode " + mLastSetCountryCode); pw.println("mPersistedCountryCode " + mPersistedCountryCode); + mNetworkFactory.dump(fd, pw, args); + mUntrustedNetworkFactory.dump(fd, pw, args); pw.println(); mWifiConfigStore.dump(fd, pw, args); } @@ -2429,6 +2560,16 @@ public class WifiStateMachine extends StateMachine { } /** + * helper, prints the milli time since boot wi and w/o suspended time + */ + String printTime() { + StringBuilder sb = new StringBuilder(); + sb.append(" rt=").append(SystemClock.uptimeMillis()); + sb.append("/").append(SystemClock.elapsedRealtime()); + return sb.toString(); + } + + /** * Return the additional string to be logged by LogRec, default * * @param msg that was processed @@ -2437,8 +2578,8 @@ public class WifiStateMachine extends StateMachine { protected String getLogRecString(Message msg) { WifiConfiguration config; Long now; - long milli; String report; + String key; StringBuilder sb = new StringBuilder(); if (mScreenOn) { sb.append("!"); @@ -2475,6 +2616,7 @@ public class WifiStateMachine extends StateMachine { if (lastScanDuration != 0) { sb.append(" dur:").append(lastScanDuration); } + sb.append(" cnt=").append(mDelayedScanCounter); sb.append(" rssi=").append(mWifiInfo.getRssi()); sb.append(" f=").append(mWifiInfo.getFrequency()); sb.append(" sc=").append(mWifiInfo.score); @@ -2494,12 +2636,11 @@ public class WifiStateMachine extends StateMachine { } break; case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - milli = SystemClock.elapsedRealtime(); sb.append(" "); sb.append(Integer.toString(msg.arg1)); sb.append(" "); sb.append(Integer.toString(msg.arg2)); - sb.append(" rt=").append(milli).append(" "); + sb.append(printTime()); StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; if (stateChangeResult != null) { sb.append(stateChangeResult.toString()); @@ -2567,8 +2708,7 @@ public class WifiStateMachine extends StateMachine { sb.append(bssid); } sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID)); - milli = SystemClock.elapsedRealtime(); - sb.append(" rt=").append(milli); + sb.append(printTime()); break; case WifiMonitor.SCAN_RESULTS_EVENT: sb.append(" "); @@ -2597,6 +2737,11 @@ public class WifiStateMachine extends StateMachine { sb.append(",").append(mRxTime); } sb.append(String.format(" bcn=%d", mRunningBeaconCount)); + sb.append(String.format(" con=%d", mConnectionRequests)); + key = mWifiConfigStore.getLastSelectedConfiguration(); + if (key != null) { + sb.append(" last=").append(key); + } break; case WifiMonitor.NETWORK_CONNECTION_EVENT: sb.append(" "); @@ -2609,8 +2754,11 @@ public class WifiStateMachine extends StateMachine { if (config != null) { sb.append(" ").append(config.configKey()); } - milli = SystemClock.elapsedRealtime(); - sb.append(" rt=").append(milli); + sb.append(printTime()); + key = mWifiConfigStore.getLastSelectedConfiguration(); + if (key != null) { + sb.append(" last=").append(key); + } break; case CMD_TARGET_BSSID: case CMD_ASSOCIATED_BSSID: @@ -2625,8 +2773,7 @@ public class WifiStateMachine extends StateMachine { sb.append(" Target=").append(mTargetRoamBSSID); } sb.append(" roam=").append(Integer.toString(mAutoRoaming)); - milli = SystemClock.elapsedRealtime(); - sb.append(" rt=").append(milli); + sb.append(printTime()); break; case WifiMonitor.NETWORK_DISCONNECTION_EVENT: if (msg.obj != null) { @@ -2644,8 +2791,7 @@ public class WifiStateMachine extends StateMachine { if (linkDebouncing) { sb.append(" debounce"); } - milli = SystemClock.elapsedRealtime(); - sb.append(" rt=").append(milli); + sb.append(printTime()); break; case WifiMonitor.SSID_TEMP_DISABLED: case WifiMonitor.SSID_REENABLED: @@ -2677,8 +2823,7 @@ public class WifiStateMachine extends StateMachine { sb.append(" bssid=").append(mWifiInfo.getBSSID()); } } - milli = SystemClock.elapsedRealtime(); - sb.append(" rt=").append(milli); + sb.append(printTime()); break; case CMD_RSSI_POLL: case CMD_UNWANTED_NETWORK: @@ -2719,26 +2864,19 @@ public class WifiStateMachine extends StateMachine { if (config != null) { sb.append(" ").append(config.configKey()); if (config.visibility != null) { - sb.append(" [").append(config.visibility.num24); - sb.append(" ,").append(config.visibility.rssi24); - sb.append(" ;").append(config.visibility.num5); - sb.append(" ,").append(config.visibility.rssi5).append("]"); + sb.append(" ").append(config.visibility.toString()); } } if (mTargetRoamBSSID != null) { sb.append(" ").append(mTargetRoamBSSID); } sb.append(" roam=").append(Integer.toString(mAutoRoaming)); - milli = SystemClock.elapsedRealtime(); - sb.append(" rt=").append(milli); + sb.append(printTime()); config = getCurrentWifiConfiguration(); if (config != null) { - sb.append(" ").append(config.configKey()); + sb.append(config.configKey()); if (config.visibility != null) { - sb.append(" [").append(config.visibility.num24); - sb.append(" ,").append(config.visibility.rssi24); - sb.append(" ;").append(config.visibility.num5); - sb.append(" ,").append(config.visibility.rssi5).append("]"); + sb.append(" ").append(config.visibility.toString()); } } break; @@ -2765,8 +2903,7 @@ public class WifiStateMachine extends StateMachine { } sb.append(" roam=").append(Integer.toString(mAutoRoaming)); sb.append(" fail count=").append(Integer.toString(mRoamFailCount)); - milli = SystemClock.elapsedRealtime(); - sb.append(" rt=").append(milli); + sb.append(printTime()); break; case CMD_ADD_OR_UPDATE_NETWORK: sb.append(" "); @@ -2799,7 +2936,7 @@ public class WifiStateMachine extends StateMachine { sb.append(Integer.toString(msg.arg1)); sb.append(" "); sb.append(Integer.toString(msg.arg2)); - String key = mWifiConfigStore.getLastSelectedConfiguration(); + key = mWifiConfigStore.getLastSelectedConfiguration(); if (key != null) { sb.append(" last=").append(key); } @@ -2902,8 +3039,7 @@ public class WifiStateMachine extends StateMachine { sb.append(",").append(mWifiInfo.txBad); sb.append(",").append(mWifiInfo.txRetries); } - milli = SystemClock.elapsedRealtime(); - sb.append(" rt=").append(milli); + sb.append(printTime()); sb.append(String.format(" bcn=%d", mRunningBeaconCount)); break; case CMD_UPDATE_LINKPROPERTIES: @@ -3009,7 +3145,6 @@ public class WifiStateMachine extends StateMachine { mScreenOn = screenOn; if (PDBG) { loge(" handleScreenStateChanged Enter: screenOn=" + screenOn - + " mCurrentScanAlarmMs = " + Long.toString(mCurrentScanAlarmMs) + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt + " state " + getCurrentState().getName() + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); @@ -3030,45 +3165,37 @@ public class WifiStateMachine extends StateMachine { getWifiLinkLayerStats(false); mOnTimeScreenStateChange = mOnTime; lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate; + mEnableBackgroundScan = false; + cancelDelayedScan(); if (screenOn) { + setScanAlarm(false); clearBlacklist(); fullBandConnectedTimeIntervalMilli = mWifiConfigStore.associatedPartialScanPeriodMilli; - // Start the scan alarm so as to enable autojoin + // In either Disconnectedstate or ConnectedState, + // start the scan alarm so as to enable autojoin if (getCurrentState() == mConnectedState && mWifiConfigStore.enableAutoJoinScanWhenAssociated) { - mCurrentScanAlarmMs = mWifiConfigStore.associatedPartialScanPeriodMilli; - // Scan after 200ms - setScanAlarm(true, 200); + // Scan after 500ms + startDelayedScan(500, null, null); } else if (getCurrentState() == mDisconnectedState) { - - // Configure the scan alarm time to mFrameworkScanIntervalMs - // (5 minutes) if there are no saved profiles as there is - // already a periodic scan getting issued for every - // mSupplicantScanIntervalMs seconds. However keep the - // scan frequency by setting it to mDisconnectedScanPeriodMs - // (10 seconds) when there are configured profiles. - if (mWifiConfigStore.getConfiguredNetworks().size() != 0) { - mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; - } else { - mCurrentScanAlarmMs = mFrameworkScanIntervalMs; - } - // Scan after 200ms - setScanAlarm(true, 200); + startDelayedScan(200, null, null); + } + } else if (startBackgroundScanIfNeeded) { + // Screen Off and Disconnected and chipset doesn't support scan offload + // => start scan alarm + // Screen Off and Disconnected and chipset does support scan offload + // => will use scan offload (i.e. background scan) + if (!mBackgroundScanSupported) { + setScanAlarm(true); + } else { + mEnableBackgroundScan = true; } - } else { - setScanAlarm(false, 0); - } - - if (mBackgroundScanSupported) { - mEnableBackgroundScan = (screenOn == false); } - if (DBG) logd("backgroundScan enabled=" + mEnableBackgroundScan + " startBackgroundScanIfNeeded:" + startBackgroundScanIfNeeded); - if (startBackgroundScanIfNeeded) { if (mEnableBackgroundScan) { if (!mWifiNative.enableBackgroundScan(true)) { @@ -3078,7 +3205,6 @@ public class WifiStateMachine extends StateMachine { mWifiNative.enableBackgroundScan(false); } } - if (DBG) log("handleScreenStateChanged Exit: " + screenOn); } @@ -3306,6 +3432,9 @@ public class WifiStateMachine extends StateMachine { int emptyScanResultCount = 0; + // Used for matching BSSID strings, at least one characteer must be a non-zero number + private static Pattern mNotZero = Pattern.compile("[1-9a-fA-F]"); + /** * Format: * @@ -3419,7 +3548,11 @@ public class WifiStateMachine extends StateMachine { wifiSsid = WifiSsid.createFromAsciiEncoded( line.substring(SSID_STR.length())); } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { - if (bssid != null) { + Matcher match = null; + if (bssid!= null) { + match = mNotZero.matcher(bssid); + } + if (match != null && !bssid.isEmpty() && match.find()) { String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; String key = bssid + ssid; ScanResult scanResult = mScanResultCache.get(key); @@ -3444,6 +3577,11 @@ public class WifiStateMachine extends StateMachine { mNumScanResultsReturned ++; // Keep track of how many scan results we got // as part of this scan's processing mScanResults.add(scanResult); + } else { + if (bssid != null) { + loge("setScanResults obtaining null BSSID results <" + + bssid + ">, discard it"); + } } bssid = null; level = 0; @@ -3456,6 +3594,7 @@ public class WifiStateMachine extends StateMachine { } boolean attemptAutoJoin = true; SupplicantState state = mWifiInfo.getSupplicantState(); + String selection = mWifiConfigStore.getLastSelectedConfiguration(); if (getCurrentState() == mRoamingState || getCurrentState() == mObtainingIpState || getCurrentState() == mScanModeState @@ -3466,21 +3605,29 @@ public class WifiStateMachine extends StateMachine { || state == SupplicantState.ASSOCIATING || state == SupplicantState.AUTHENTICATING || state == SupplicantState.FOUR_WAY_HANDSHAKE - || state == SupplicantState.GROUP_HANDSHAKE) { + || state == SupplicantState.GROUP_HANDSHAKE + || (/* keep autojoin enabled if user has manually selected a wifi network, + so as to make sure we reliably remain connected to this network */ + mConnectionRequests == 0 && selection == null)) { // Dont attempt auto-joining again while we are already attempting to join // and/or obtaining Ip address attemptAutoJoin = false; } if (DBG) { + if (selection == null) { + selection = "<none>"; + } loge("wifi setScanResults state" + getCurrentState() + " sup_state=" + state - + " debouncing=" + linkDebouncing); + + " debouncing=" + linkDebouncing + + " mConnectionRequests=" + mConnectionRequests + + " selection=" + selection); } if (attemptAutoJoin) { messageHandlingStatus = MESSAGE_HANDLING_STATUS_PROCESSED; } - // Loose last selected configuration if we have been disconnected for 30 minutes - if (getDisconnectedTimeMilli() > 1000 * 60 * 30) { + // Loose last selected configuration if we have been disconnected for 5 minutes + if (getDisconnectedTimeMilli() > mWifiConfigStore.wifiConfigLastSelectionHysteresis) { mWifiConfigStore.setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); } @@ -3632,14 +3779,7 @@ public class WifiStateMachine extends StateMachine { String wifiScoringReport = null; private void calculateWifiScore(WifiLinkLayerStats stats) { StringBuilder sb = new StringBuilder(); - if (stats == null || mWifiLinkLayerStatsSupported <= 0) { - long mTxPkts = TrafficStats.getTxPackets(mInterfaceName); - long mRxPkts = TrafficStats.getRxPackets(mInterfaceName); - mWifiInfo.updatePacketRates(mTxPkts, mRxPkts); - } else { - sb.append(" stats"); - mWifiInfo.updatePacketRates(stats); - } + int score = 56; // Starting score, temporarily hardcoded in between 50 and 60 boolean isBadLinkspeed = (mWifiInfo.is24GHz() && mWifiInfo.getLinkSpeed() < mWifiConfigStore.badLinkSpeed24) @@ -3933,17 +4073,8 @@ public class WifiStateMachine extends StateMachine { } private boolean isProvisioned(LinkProperties lp) { - // LinkProperties#isProvisioned returns true even if all we have is an IPv4 address and no - // connectivity. This turns out not to be very useful, because we can't distinguish it from - // a state where we have an IPv4 address assigned to the interface but are still running - // DHCP. - // TODO: Fix LinkProperties and remove this function. - if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { - return lp.hasIPv4Address(); - } else { - return (lp.hasIPv4Address() && lp.hasIPv4DefaultRoute() && lp.hasIPv4DnsServer()) || - (lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute() && lp.hasIPv6DnsServer()); - } + return lp.isProvisioned() || + (mWifiConfigStore.isUsingStaticIp(mLastNetworkId) && lp.hasIPv4Address()); } /** @@ -3997,6 +4128,8 @@ public class WifiStateMachine extends StateMachine { final boolean linkChanged = !newLp.equals(mLinkProperties); final boolean wasProvisioned = isProvisioned(mLinkProperties); final boolean isProvisioned = isProvisioned(newLp); + final boolean lostIPv4Provisioning = + mLinkProperties.hasIPv4Address() && !newLp.hasIPv4Address(); final DetailedState detailedState = getNetworkDetailedState(); if (linkChanged) { @@ -4064,9 +4197,10 @@ public class WifiStateMachine extends StateMachine { break; case DhcpStateMachine.DHCP_FAILURE: - // DHCP failed. If we're not already provisioned, give up and disconnect. + // DHCP failed. If we're not already provisioned, or we had IPv4 and now lost it, + // give up and disconnect. // If we're already provisioned (e.g., IPv6-only network), stay connected. - if (!isProvisioned) { + if (!isProvisioned || lostIPv4Provisioning) { sendMessage(CMD_IP_CONFIGURATION_LOST); } else { // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network). @@ -4328,7 +4462,14 @@ public class WifiStateMachine extends StateMachine { linkDebouncing = false; /* Reset roaming parameters */ mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; - fullBandConnectedTimeIntervalMilli = 20 * 1000; // Start scans at 20 seconds interval + + /** + * fullBandConnectedTimeIntervalMilli: + * - start scans at mWifiConfigStore.associatedPartialScanPeriodMilli seconds interval + * - exponentially increase to mWifiConfigStore.associatedFullScanMaxIntervalMilli + * Initialize to sane value = 20 seconds + */ + fullBandConnectedTimeIntervalMilli = 20 * 1000; setNetworkDetailedState(DetailedState.DISCONNECTED); if (mNetworkAgent != null) { @@ -4379,6 +4520,9 @@ public class WifiStateMachine extends StateMachine { stopBatchedScan(); WifiNative.pauseScan(); + // Update link layer stats + getWifiLinkLayerStats(false); + /* P2p discovery breaks dhcp, shut it down in order to get through this */ Message msg = new Message(); msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; @@ -4469,9 +4613,12 @@ public class WifiStateMachine extends StateMachine { private void handleSuccessfulIpConfiguration() { mLastSignalLevel = -1; // Force update of signal strength WifiConfiguration c = getCurrentWifiConfiguration(); - // Reset IP failure tracking if (c != null) { + // Reset IP failure tracking c.numConnectionFailures = 0; + + // Tell the framework whether the newly connected network is trusted or untrusted. + updateCapabilities(c); } if (c != null) { ScanResult result = getCurrentScanResult(); @@ -4601,15 +4748,74 @@ public class WifiStateMachine extends StateMachine { public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) { super(l, c, TAG, f); } - protected void startNetwork() { - // TODO - // Enter association mode. + + @Override + protected void needNetworkFor(NetworkRequest networkRequest, int score) { + ++mConnectionRequests; + } + + @Override + protected void releaseNetworkFor(NetworkRequest networkRequest) { + --mConnectionRequests; + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("mConnectionRequests " + mConnectionRequests); + } + + } + + private class UntrustedWifiNetworkFactory extends NetworkFactory { + private int mUntrustedReqCount; + + public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) { + super(l, c, tag, f); + } + + @Override + protected void needNetworkFor(NetworkRequest networkRequest, int score) { + if (!networkRequest.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { + if (++mUntrustedReqCount == 1) { + mWifiAutoJoinController.setAllowUntrustedConnections(true); + } + } + } + + @Override + protected void releaseNetworkFor(NetworkRequest networkRequest) { + if (!networkRequest.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { + if (--mUntrustedReqCount == 0) { + mWifiAutoJoinController.setAllowUntrustedConnections(false); + } + } + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("mUntrustedReqCount " + mUntrustedReqCount); } - protected void stopNetwork() { - // TODO - // Stop associating. + } + + void maybeRegisterNetworkFactory() { + if (mNetworkFactory == null) { + checkAndSetConnectivityInstance(); + if (mCm != null) { + mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext, + NETWORKTYPE, mNetworkCapabilitiesFilter); + mNetworkFactory.setScoreFilter(60); + mNetworkFactory.register(); + + // We can't filter untrusted network in the capabilities filter because a trusted + // network would still satisfy a request that accepts untrusted ones. + mUntrustedNetworkFactory = new UntrustedWifiNetworkFactory(getHandler().getLooper(), + mContext, NETWORKTYPE_UNTRUSTED, mNetworkCapabilitiesFilter); + mUntrustedNetworkFactory.setScoreFilter(Integer.MAX_VALUE); + mUntrustedNetworkFactory.register(); + } } } + /******************************************************** * HSM states *******************************************************/ @@ -4688,12 +4894,7 @@ public class WifiStateMachine extends StateMachine { sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, sequenceNum, 0, countryCode); } - - checkAndSetConnectivityInstance(); - mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext, - NETWORKTYPE, mNetworkCapabilitiesFilter); - mNetworkFactory.setScoreFilter(60); - mCm.registerNetworkFactory(new Messenger(mNetworkFactory), NETWORKTYPE); + maybeRegisterNetworkFactory(); break; case CMD_SET_BATCHED_SCAN: recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); @@ -4768,6 +4969,7 @@ public class WifiStateMachine extends StateMachine { case CMD_UNWANTED_NETWORK: case CMD_DISCONNECTING_WATCHDOG_TIMER: case CMD_ROAM_WATCHDOG_TIMER: + case CMD_DISABLE_EPHEMERAL_NETWORK: messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; break; case DhcpStateMachine.CMD_ON_QUIT: @@ -5094,13 +5296,15 @@ public class WifiStateMachine extends StateMachine { sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); break; case WifiMonitor.SCAN_RESULTS_EVENT: + maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered closeRadioScanStats(); noteScanEnd(); setScanResults(); - if (mIsFullScanOngoing) { + if (mIsFullScanOngoing || mSendScanResultsBroadcast) { /* Just updated results from full scan, let apps know about this */ sendScanResultsAvailableBroadcast(); } + mSendScanResultsBroadcast = false; mIsScanOngoing = false; mIsFullScanOngoing = false; if (mBufferedScanMsg.size() > 0) @@ -5121,6 +5325,8 @@ public class WifiStateMachine extends StateMachine { break; case CMD_SET_OPERATIONAL_MODE: mOperationalMode = message.arg1; + mWifiConfigStore. + setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); break; case CMD_TARGET_BSSID: // Trying to associate to this BSSID @@ -5158,7 +5364,14 @@ public class WifiStateMachine extends StateMachine { mDhcpStateMachine.doQuit(); } - if (DBG) log("stopping supplicant"); + String suppState = System.getProperty("init.svc.wpa_supplicant"); + if (suppState == null) suppState = "unknown"; + String p2pSuppState = System.getProperty("init.svc.p2p_supplicant"); + if (p2pSuppState == null) p2pSuppState = "unknown"; + + loge("SupplicantStoppingState: stopSupplicant " + + " init.svc.wpa_supplicant=" + suppState + + " init.svc.p2p_supplicant=" + p2pSuppState); mWifiMonitor.stopSupplicant(); /* Send ourselves a delayed message to indicate failure after a wait time */ @@ -5284,7 +5497,7 @@ public class WifiStateMachine extends StateMachine { public void enter() { if (PDBG) { - loge("Driverstarted State enter"); + loge("DriverStartedState enter"); } mIsRunning = true; mInDelayedStop = false; @@ -5471,6 +5684,7 @@ public class WifiStateMachine extends StateMachine { /* send regular delayed shut down */ Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); + driverStopIntent.setPackage(this.getClass().getPackage().getName()); driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); mDriverStopIntent = PendingIntent.getBroadcast(mContext, DRIVER_STOP_REQUEST, driverStopIntent, @@ -5709,7 +5923,16 @@ public class WifiStateMachine extends StateMachine { mWifiConfigStore.enableAllNetworks(); } - mWifiNative.reconnect(); + // Try autojoining with recent network already present in the cache + // If none are found then trigger a scan which will trigger autojoin + // upon reception of scan results event + if (!mWifiAutoJoinController.attemptAutoJoin()) { + startScan(ENABLE_WIFI, 0, null, null); + } + + // Loose last selection choice since user toggled WiFi + mWifiConfigStore. + setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); mOperationalMode = CONNECT_MODE; transitionTo(mDisconnectedState); @@ -5759,6 +5982,9 @@ public class WifiStateMachine extends StateMachine { case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: s = "CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER"; break; + case CMD_DISABLE_EPHEMERAL_NETWORK: + s = "CMD_DISABLE_EPHEMERAL_NETWORK"; + break; case CMD_START_DRIVER: s = "CMD_START_DRIVER"; break; @@ -5858,6 +6084,9 @@ public class WifiStateMachine extends StateMachine { case CMD_UNWANTED_NETWORK: s = "CMD_UNWANTED_NETWORK"; break; + case CMD_NETWORK_STATUS: + s = "CMD_NETWORK_STATUS"; + break; case CMD_GET_LINK_LAYER_STATS: s = "CMD_GET_LINK_LAYER_STATS"; break; @@ -6093,6 +6322,10 @@ public class WifiStateMachine extends StateMachine { WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); if (config != null) { config.lastDisconnected = System.currentTimeMillis(); + if (config.ephemeral) { + // Remove ephemeral WifiConfigurations from file + mWifiConfigStore.forgetNetwork(mLastNetworkId); + } } } } @@ -6124,13 +6357,6 @@ public class WifiStateMachine extends StateMachine { } } - void setInternetAccessState(boolean enabled) { - WifiConfiguration config = getCurrentWifiConfiguration(); - if (config != null) { - config.noInternetAccess = enabled; - } - } - WifiConfiguration getCurrentWifiConfiguration() { if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) { return null; @@ -6326,6 +6552,15 @@ public class WifiStateMachine extends StateMachine { WifiManager.ERROR); } break; + case CMD_DISABLE_EPHEMERAL_NETWORK: + config = mWifiConfigStore.disableEphemeralNetwork((String)message.obj); + if (config != null) { + if (config.networkId == mLastNetworkId) { + // Disconnect and let autojoin reselect a new network + sendMessage(CMD_DISCONNECT); + } + } + break; case CMD_BLACKLIST_NETWORK: mWifiNative.addToBlacklist((String) message.obj); break; @@ -6392,8 +6627,7 @@ public class WifiStateMachine extends StateMachine { mWifiNative.disconnect(); break; case CMD_RECONNECT: - lastConnectAttempt = System.currentTimeMillis(); - mWifiNative.reconnect(); + mWifiAutoJoinController.attemptAutoJoin(); break; case CMD_REASSOCIATE: lastConnectAttempt = System.currentTimeMillis(); @@ -6460,20 +6694,31 @@ public class WifiStateMachine extends StateMachine { mWifiNative.reconnect()) { lastConnectAttempt = System.currentTimeMillis(); targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); - // We selected a better config, - // maybe because we could not see the last user - // selection, then forget it. We will remember the selection - // only if it was persisted. - mWifiConfigStore. - setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); - + config = mWifiConfigStore.getWifiConfiguration(netId); + if (config != null + && !mWifiConfigStore.isLastSelectedConfiguration(config)) { + // If we autojoined a different config than the user selected one, + // it means we could not see the last user selection, + // or that the last user selection was faulty and ended up blacklisted + // for some reason (in which case the user is notified with an error + // message in the Wifi picker), and thus we managed to auto-join away + // from the selected config. -> in that case we need to forget + // the selection because we don't want to abruptly switch back to it. + // + // Note that the user selection is also forgotten after a period of time + // during which the device has been disconnected. + // The default value is 30 minutes : see the code path at bottom of + // setScanResults() function. + mWifiConfigStore. + setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); + } mAutoRoaming = roam; if (isRoaming() || linkDebouncing) { transitionTo(mRoamingState); } else if (didDisconnect) { transitionTo(mDisconnectingState); } else { - transitionTo(mDisconnectedState); + /* Already in disconnected state, nothing to change */ } } else { loge("Failed to connect config: " + config + " netId: " + netId); @@ -6492,9 +6737,25 @@ public class WifiStateMachine extends StateMachine { netId = message.arg1; config = (WifiConfiguration) message.obj; mWifiConnectionStatistics.numWifiManagerJoinAttempt++; + boolean updatedExisting = false; /* Save the network config */ if (config != null) { + String configKey = config.configKey(true /* allowCached */); + WifiConfiguration savedConfig = + mWifiConfigStore.getWifiConfiguration(configKey); + if (savedConfig != null) { + // There is an existing config with this netId, but it wasn't exposed + // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigStore# + // getConfiguredNetworks). Remove those bits and update the config. + config = savedConfig; + loge("CONNECT_NETWORK updating existing config with id=" + + config.networkId + " configKey=" + configKey); + config.ephemeral = false; + config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_ENABLED; + updatedExisting = true; + } + result = mWifiConfigStore.saveNetwork(config, message.sendingUid); netId = result.getNetworkId(); } @@ -6559,6 +6820,11 @@ public class WifiStateMachine extends StateMachine { if (didDisconnect) { /* Expect a disconnection from the old connection */ transitionTo(mDisconnectingState); + } else if (updatedExisting && getCurrentState() == mConnectedState && + getCurrentWifiConfiguration().networkId == netId) { + // Update the current set of network capabilities, but stay in the + // current state. + updateCapabilities(config); } else { /** * Directly go to disconnected state where we @@ -6690,8 +6956,7 @@ public class WifiStateMachine extends StateMachine { mWifiInfo.setBSSID(mLastBssid); mWifiInfo.setNetworkId(mLastNetworkId); - // Send event to CM & network change broadcast - setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); + sendNetworkStateChangeBroadcast(mLastBssid); transitionTo(mObtainingIpState); break; @@ -6716,6 +6981,17 @@ public class WifiStateMachine extends StateMachine { } } + private void updateCapabilities(WifiConfiguration config) { + if (config.ephemeral) { + mNetworkCapabilities.removeCapability( + NetworkCapabilities.NET_CAPABILITY_TRUSTED); + } else { + mNetworkCapabilities.addCapability( + NetworkCapabilities.NET_CAPABILITY_TRUSTED); + } + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + } + private class WifiNetworkAgent extends NetworkAgent { public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score) { @@ -6731,9 +7007,13 @@ public class WifiStateMachine extends StateMachine { protected void networkStatus(int status) { if (status == NetworkAgent.INVALID_NETWORK) { - if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid score " + if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid, score=" + Integer.toString(mWifiInfo.score)); unwantedNetwork(network_status_unwanted_disable_autojoin); + } else if (status == NetworkAgent.VALID_NETWORK) { + if (DBG && mWifiInfo != null) log("WifiNetworkAgent -> Wifi networkStatus valid, score= " + + Integer.toString(mWifiInfo.score)); + doNetworkStatus(status); } } } @@ -6742,6 +7022,9 @@ public class WifiStateMachine extends StateMachine { sendMessage(CMD_UNWANTED_NETWORK, reason); } + void doNetworkStatus(int status) { + sendMessage(CMD_NETWORK_STATUS, status); + } boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) { if (config == null) @@ -6898,6 +7181,8 @@ public class WifiStateMachine extends StateMachine { transitionTo(mConnectedState); break; case CMD_IP_CONFIGURATION_LOST: + // Get Link layer stats so as we get fresh tx packet counters + getWifiLinkLayerStats(true); handleIpConfigurationLost(); transitionTo(mDisconnectingState); break; @@ -6920,13 +7205,15 @@ public class WifiStateMachine extends StateMachine { noteWifiDisabledWhileAssociated(); } } + mWifiConfigStore. + setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); break; case CMD_SET_COUNTRY_CODE: messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; deferMessage(message); break; case CMD_START_SCAN: - if (!isScanAllowed(message.arg1)) { + if (!checkOrDeferScanAllowed(message)) { // Ignore the scan request if (VDBG) logd("L2ConnectedState: ignore scan"); return HANDLED; @@ -6939,6 +7226,28 @@ public class WifiStateMachine extends StateMachine { + " RSSI=" + mWifiInfo.getRssi()); //} if (message.arg1 == SCAN_ALARM_SOURCE) { + // Check if the CMD_START_SCAN message is obsolete (and thus if it should + // not be processed) and restart the scan if needed + boolean shouldScan = + mScreenOn && mWifiConfigStore.enableAutoJoinScanWhenAssociated; + if (!checkAndRestartDelayedScan(message.arg2, + shouldScan, + mWifiConfigStore.associatedPartialScanPeriodMilli, null, null)) { + messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE; + loge("WifiStateMachine L2Connected CMD_START_SCAN source " + + message.arg1 + + " " + message.arg2 + ", " + mDelayedScanCounter + + " -> obsolete"); + return HANDLED; + } + if (mP2pConnected.get()) { + loge("WifiStateMachine L2Connected CMD_START_SCAN source " + + message.arg1 + + " " + message.arg2 + ", " + mDelayedScanCounter + + " ignore because P2P is connected"); + messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; + return HANDLED; + } boolean tryFullBandScan = false; boolean restrictChannelList = false; long now_ms = System.currentTimeMillis(); @@ -7044,13 +7353,14 @@ public class WifiStateMachine extends StateMachine { WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); } } + } else { loge("CMD_START_SCAN : connected mode and no configuration"); messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR; } } else { // Not scan alarm source - handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); + return NOT_HANDLED; } break; /* Ignore connection to same network */ @@ -7166,6 +7476,9 @@ public class WifiStateMachine extends StateMachine { // We might still be roaming linkDebouncing = false; + // Send event to CM & network change broadcast + setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); + // We must clear the config BSSID, as the wifi chipset may decide to roam // from this point on and having the BSSID specified in the network block would // cause the roam to faile and the device to disconnect @@ -7191,6 +7504,8 @@ public class WifiStateMachine extends StateMachine { } obtainingIpWatchdogCount++; loge("Start Dhcp Watchdog " + obtainingIpWatchdogCount); + // Get Link layer stats so as we get fresh tx packet counters + getWifiLinkLayerStats(true); sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER, obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC); } else { @@ -7327,7 +7642,7 @@ public class WifiStateMachine extends StateMachine { log("RoamingState Enter" + " mScreenOn=" + mScreenOn ); } - setScanAlarm(false, 0); + setScanAlarm(false); // Make sure we disconnect if roaming fails roamWatchdogCount++; @@ -7339,8 +7654,15 @@ public class WifiStateMachine extends StateMachine { @Override public boolean processMessage(Message message) { logStateAndMessage(message, getClass().getSimpleName()); - + WifiConfiguration config; switch (message.what) { + case CMD_IP_CONFIGURATION_LOST: + config = getCurrentWifiConfiguration(); + if (config != null) { + mWifiConfigStore.noteRoamingFailure(config, + WifiConfiguration.ROAMING_FAILURE_IP_CONFIG); + } + return NOT_HANDLED; case WifiWatchdogStateMachine.POOR_LINK_DETECTED: if (DBG) log("Roaming and Watchdog reports poor link -> ignore"); return HANDLED; @@ -7426,6 +7748,11 @@ public class WifiStateMachine extends StateMachine { + " isRoaming=" + isRoaming() + " roam=" + Integer.toString(mAutoRoaming)); if (message.arg1 == mLastNetworkId) { + config = getCurrentWifiConfiguration(); + if (config != null) { + mWifiConfigStore.noteRoamingFailure(config, + WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE); + } handleNetworkDisconnect(); transitionTo(mDisconnectingState); } @@ -7458,11 +7785,8 @@ public class WifiStateMachine extends StateMachine { } if (mScreenOn && mWifiConfigStore.enableAutoJoinScanWhenAssociated) { - mCurrentScanAlarmMs = mWifiConfigStore.associatedPartialScanPeriodMilli; - // Scan after 200ms - setScanAlarm(true, 200); - } else { - mCurrentScanAlarmMs = 0; + // restart scan alarm + startDelayedScan(mWifiConfigStore.associatedPartialScanPeriodMilli, null, null); } registerConnected(); lastConnectAttempt = 0; @@ -7501,11 +7825,21 @@ public class WifiStateMachine extends StateMachine { mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); mWifiNative.disconnect(); transitionTo(mDisconnectingState); - } else if (message.arg1 == network_status_unwanted_disconnect) { + } else if (message.arg1 == network_status_unwanted_disable_autojoin) { config = getCurrentWifiConfiguration(); if (config != null) { // Disable autojoin - config.noInternetAccess = true; + config.numNoInternetAccessReports += 1; + } + } + return HANDLED; + case CMD_NETWORK_STATUS: + if (message.arg1 == NetworkAgent.VALID_NETWORK) { + config = getCurrentWifiConfiguration(); + if (config != null) { + // re-enable autojoin + config.numNoInternetAccessReports = 0; + config.validatedInternetAccess = true; } } return HANDLED; @@ -7653,7 +7987,7 @@ public class WifiStateMachine extends StateMachine { @Override public void exit() { loge("WifiStateMachine: Leaving Connected state"); - setScanAlarm(false, 0); + setScanAlarm(false); mLastDriverRoamAttempt = 0; } } @@ -7662,7 +7996,6 @@ public class WifiStateMachine extends StateMachine { @Override public void enter() { - mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; if (PDBG) { loge(" Enter DisconnectingState State scan interval " + mFrameworkScanIntervalMs @@ -7692,7 +8025,7 @@ public class WifiStateMachine extends StateMachine { } break; case CMD_START_SCAN: - // Ignore scans while disconnecting + deferMessage(message); return HANDLED; case CMD_DISCONNECTING_WATCHDOG_TIMER: if (disconnectingWatchdogCount == message.arg1) { @@ -7716,11 +8049,6 @@ public class WifiStateMachine extends StateMachine { } return HANDLED; } - - @Override - public void exit() { - mCurrentScanAlarmMs = 0; - } } class DisconnectedState extends State { @@ -7733,57 +8061,42 @@ public class WifiStateMachine extends StateMachine { return; } - // Loose the last selection choice - // mWifiAutoJoinController.setLastSelectedConfiguration - // (WifiConfiguration.INVALID_NETWORK_ID); - mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, mDefaultFrameworkScanIntervalMs); - // Configure the scan alarm time to mFrameworkScanIntervalMs - // (5 minutes) if there are no saved profiles as there is - // already a periodic scan getting issued for every - // mSupplicantScanIntervalMs seconds. However keep the - // scan frequency by setting it to mDisconnectedScanPeriodMs - // (10 seconds) when there are configured profiles. - if (mScreenOn) { - if (mWifiConfigStore.getConfiguredNetworks().size() != 0) { - mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; - } else { - mCurrentScanAlarmMs = mFrameworkScanIntervalMs; - } - } if (PDBG) { loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs + " mEnableBackgroundScan= " + mEnableBackgroundScan - + " screenOn=" + mScreenOn); + + " screenOn=" + mScreenOn + + " mFrameworkScanIntervalMs=" + mFrameworkScanIntervalMs); } /** clear the roaming state, if we were roaming, we failed */ mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; - // Reenable all networks, allow for hidden networks to be scanned - mWifiConfigStore.enableAllNetworks(); - - /** - * - screen dark and PNO supported => scan alarm disabled - * - everything else => scan alarm enabled with mDefaultFrameworkScanIntervalMs period - */ - if ((mScreenOn == false) && mEnableBackgroundScan) { //mEnableBackgroundScan) - /* If a regular scan result is pending, do not initiate background - * scan until the scan results are returned. This is needed because - * initiating a background scan will cancel the regular scan and - * scan results will not be returned until background scanning is - * cleared + if (mScreenOn) { + /** + * screen lit and => delayed timer + */ + startDelayedScan(mDisconnectedScanPeriodMs, null, null); + } else { + /** + * screen dark and PNO supported => scan alarm disabled */ - if (!mIsScanOngoing) { - if (!mWifiNative.enableBackgroundScan(true)) { - handlePnoFailError(); + if (mEnableBackgroundScan) { + /* If a regular scan result is pending, do not initiate background + * scan until the scan results are returned. This is needed because + * initiating a background scan will cancel the regular scan and + * scan results will not be returned until background scanning is + * cleared + */ + if (!mIsScanOngoing) { + enableBackgroundScan(true); } + } else { + setScanAlarm(true); } - } else { - setScanAlarm(true, 200); } /** @@ -7844,9 +8157,10 @@ public class WifiStateMachine extends StateMachine { mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); setWifiState(WIFI_STATE_DISABLED); } - transitionTo(mScanModeState); } + mWifiConfigStore. + setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); break; /* Ignore network disconnect */ case WifiMonitor.NETWORK_DISCONNECTION_EVENT: @@ -7863,17 +8177,38 @@ public class WifiStateMachine extends StateMachine { ret = NOT_HANDLED; break; case CMD_START_SCAN: - if (!isScanAllowed(message.arg1)) { - // Ignore the scan request - if (VDBG) logd("DisconnectedState: ignore scan"); + if (!checkOrDeferScanAllowed(message)) { + // The scan request was rescheduled + messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED; return HANDLED; } /* Disable background scan temporarily during a regular scan */ if (mEnableBackgroundScan) { - mWifiNative.enableBackgroundScan(false); + enableBackgroundScan(false); + } + if (message.arg1 == SCAN_ALARM_SOURCE) { + // Check if the CMD_START_SCAN message is obsolete (and thus if it should + // not be processed) and restart the scan + int period = mDisconnectedScanPeriodMs; + if (mP2pConnected.get()) { + period = (int)Settings.Global.getLong(mContext.getContentResolver(), + Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, + mDisconnectedScanPeriodMs); + } + if (!checkAndRestartDelayedScan(message.arg2, + true, period, null, null)) { + messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE; + loge("WifiStateMachine Disconnected CMD_START_SCAN source " + + message.arg1 + + " " + message.arg2 + ", " + mDelayedScanCounter + + " -> obsolete"); + return HANDLED; + } + handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); + ret = HANDLED; + } else { + ret = NOT_HANDLED; } - /* Handled in parent state */ - ret = NOT_HANDLED; break; case WifiMonitor.SCAN_RESULTS_EVENT: /* Re-enable background scan when a pending scan result is received */ @@ -7907,6 +8242,12 @@ public class WifiStateMachine extends StateMachine { if (DBG) log("Stop periodic scan on PNO success"); mBackgroundScanConfigured = true; } + } else { + // If P2P is not connected and there are saved networks, then restart + // scanning at the normal period. This is necessary because scanning might + // have been disabled altogether if WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS + // was set to zero. + startDelayedScan(mDisconnectedScanPeriodMs, null, null); } case CMD_RECONNECT: case CMD_REASSOCIATE: @@ -7936,10 +8277,9 @@ public class WifiStateMachine extends StateMachine { public void exit() { /* No need for a background scan upon exit from a disconnected state */ if (mEnableBackgroundScan) { - mWifiNative.enableBackgroundScan(false); + enableBackgroundScan(false); } - mCurrentScanAlarmMs = 0; - setScanAlarm(false, 0); + setScanAlarm(false); } } diff --git a/service/java/com/android/server/wifi/WifiWatchdogStateMachine.java b/service/java/com/android/server/wifi/WifiWatchdogStateMachine.java index 181e043d2..0ef18e6ae 100644 --- a/service/java/com/android/server/wifi/WifiWatchdogStateMachine.java +++ b/service/java/com/android/server/wifi/WifiWatchdogStateMachine.java @@ -435,15 +435,8 @@ public class WifiWatchdogStateMachine extends StateMachine { private void updateSettings() { if (DBG) logd("Updating secure settings"); - // disable poor network avoidance - if (sWifiOnly) { - logd("Disabling poor network avoidance for wi-fi only device"); - mPoorNetworkDetectionEnabled = false; - } else { - mPoorNetworkDetectionEnabled = getSettingsGlobalBoolean(mContentResolver, - Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED, - WifiManager.DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED); - } + // Unconditionally disable poor network avoidance, since this mechanism is obsolete + mPoorNetworkDetectionEnabled = false; } /** diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java index 9e4149164..0fc9431df 100644 --- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java +++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java @@ -2880,7 +2880,7 @@ public final class WifiP2pServiceImpl extends IWifiP2pManager.Stub { // Remove only the peer we failed to connect to so that other devices discovered // that have not timed out still remain in list for connection boolean peersChanged = mPeers.remove(mPeersLostDuringConnection); - if (mSavedPeerConfig.deviceAddress != null && + if (TextUtils.isEmpty(mSavedPeerConfig.deviceAddress) == false && mPeers.remove(mSavedPeerConfig.deviceAddress) != null) { peersChanged = true; } |