summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnh Nguyen <anguyen@codeaurora.org>2015-03-10 00:45:06 -0700
committerAnh Nguyen <anguyen@codeaurora.org>2015-03-10 00:45:06 -0700
commitd6459e7bcb9c1e9df6da3fb69346fb07d57655e5 (patch)
tree38c8561746a1843b7c227c4d27333329861ce86d
parent880aea0f9852a0f5afeb48855cfc6b7236cd3a37 (diff)
parent5921779b4827551735e9016c6b6a22adf176ec85 (diff)
downloadandroid_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.mk3
-rw-r--r--service/java/com/android/server/wifi/RttService.java2
-rw-r--r--service/java/com/android/server/wifi/WifiAutoJoinController.java420
-rwxr-xr-xservice/java/com/android/server/wifi/WifiConfigStore.java432
-rwxr-xr-xservice/java/com/android/server/wifi/WifiMonitor.java29
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java37
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkScoreCache.java82
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java55
-rwxr-xr-x[-rw-r--r--]service/java/com/android/server/wifi/WifiStateMachine.java834
-rw-r--r--service/java/com/android/server/wifi/WifiWatchdogStateMachine.java11
-rw-r--r--service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java2
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;
}