summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStore.java207
-rw-r--r--service/java/com/android/server/wifi/WifiQualifiedNetworkSelection.java176
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java34
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java30
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectionTest.java193
5 files changed, 454 insertions, 186 deletions
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index 894263a1c..3af6ffd94 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -112,7 +112,6 @@ import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
@@ -219,7 +218,9 @@ public class WifiConfigStore extends IpConfigStore {
/* Network History Keys */
private static final String SSID_KEY = "SSID";
static final String CONFIG_KEY = "CONFIG";
+ private static final String CONFIG_BSSID_KEY = "CONFIG_BSSID";
private static final String CHOICE_KEY = "CHOICE";
+ private static final String CHOICE_TIME_KEY = "CHOICE_TIME";
private static final String LINK_KEY = "LINK";
private static final String BSSID_KEY = "BSSID";
private static final String BSSID_KEY_END = "/BSSID";
@@ -232,7 +233,6 @@ public class WifiConfigStore extends IpConfigStore {
private static final String PRIORITY_KEY = "PRIORITY";
private static final String DEFAULT_GW_KEY = "DEFAULT_GW";
private static final String AUTH_KEY = "AUTH";
- private static final String STATUS_KEY = "AUTO_JOIN_STATUS";
private static final String BSSID_STATUS_KEY = "BSSID_STATUS";
private static final String SELF_ADDED_KEY = "SELF_ADDED";
private static final String FAILURE_KEY = "FAILURE";
@@ -241,8 +241,6 @@ public class WifiConfigStore extends IpConfigStore {
static final String CREATOR_UID_KEY = "CREATOR_UID_KEY";
private static final String CONNECT_UID_KEY = "CONNECT_UID_KEY";
private static final String UPDATE_UID_KEY = "UPDATE_UID";
- private static final String SUPPLICANT_STATUS_KEY = "SUP_STATUS";
- private static final String SUPPLICANT_DISABLE_REASON_KEY = "SUP_DIS_REASON";
private static final String FQDN_KEY = "FQDN";
private static final String SCORER_OVERRIDE_KEY = "SCORER_OVERRIDE";
private static final String SCORER_OVERRIDE_AND_SWITCH_KEY = "SCORER_OVERRIDE_AND_SWITCH";
@@ -1021,7 +1019,7 @@ public class WifiConfigStore extends IpConfigStore {
mWifiNative.selectNetwork(config.networkId);
updateLastConnectUid(config, uid);
- writeKnownNetworkHistory(false);
+ writeKnownNetworkHistory();
/* Enable the given network while disabling all other networks */
enableNetworkWithoutBroadcast(config.networkId, true);
@@ -1152,12 +1150,7 @@ public class WifiConfigStore extends IpConfigStore {
return;
}
- // If an app specified a BSSID then dont over-write it
- if (config.BSSID != null && config.BSSID != "any") {
- return;
- }
-
- // If autojoin specified a BSSID then write it in the network block
+ // If Network Selection specified a BSSID then write it in the network block
WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus();
String bssid = networkStatus.getNetworkSelectionBSSID();
if (bssid != null) {
@@ -1226,9 +1219,7 @@ public class WifiConfigStore extends IpConfigStore {
loge("Found ephemeral config in disableEphemeralNetwork: " + foundConfig.networkId);
}
- // Force a write, because the mDeletedEphemeralSSIDs list has changed even though the
- // configurations may not have.
- writeKnownNetworkHistory(true);
+ writeKnownNetworkHistory();
return foundConfig;
}
@@ -1254,7 +1245,7 @@ public class WifiConfigStore extends IpConfigStore {
writePasspointConfigs(config.FQDN, null);
}
mWifiNative.saveConfig();
- writeKnownNetworkHistory(true);
+ writeKnownNetworkHistory();
return true;
} else {
loge("Failed to remove network " + netId);
@@ -1425,13 +1416,13 @@ public class WifiConfigStore extends IpConfigStore {
private boolean removeConfigAndSendBroadcastIfNeeded(int netId) {
WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
if (config != null) {
+ String key = config.configKey();
if (VDBG) {
- loge("removeNetwork " + Integer.toString(netId) + " key=" +
- config.configKey() + " config.id=" + Integer.toString(config.networkId));
+ loge("removeNetwork " + netId + " key=" + key + " config.id=" + config.networkId);
}
// cancel the last user choice
- if (config.configKey().equals(lastSelectedConfiguration)) {
+ if (key.equals(lastSelectedConfiguration)) {
lastSelectedConfiguration = null;
}
@@ -1447,14 +1438,14 @@ public class WifiConfigStore extends IpConfigStore {
if (config.SSID != null) {
Long csum = getChecksum(config.SSID);
mDeletedSSIDs.add(csum);
- loge("removeNetwork " + Integer.toString(netId)
- + " key=" + config.configKey()
- + " config.id=" + Integer.toString(config.networkId)
+ loge("removeNetwork " + netId
+ + " key=" + key
+ + " config.id=" + config.networkId
+ " crc=" + csum);
} else {
- loge("removeNetwork " + Integer.toString(netId)
- + " key=" + config.configKey()
- + " config.id=" + Integer.toString(config.networkId));
+ loge("removeNetwork " + netId
+ + " key=" + key
+ + " config.id=" + config.networkId);
}
}
}
@@ -1464,11 +1455,34 @@ public class WifiConfigStore extends IpConfigStore {
writeIpAndProxyConfigurations();
sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED);
- writeKnownNetworkHistory(true);
+ if (!config.ephemeral) {
+ removeUserSelectionPreference(key);
+ }
+ writeKnownNetworkHistory();
}
return true;
}
+ private void removeUserSelectionPreference(String configKey) {
+ if (DBG) {
+ Log.d(TAG, "removeUserSelectionPreference: key is " + configKey);
+ }
+ if (configKey == null) {
+ return;
+ }
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
+ WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus();
+ String connectChoice = status.getConnectChoice();
+ if (connectChoice != null && connectChoice.equals(configKey)) {
+ Log.d(TAG, "remove connect choice:" + connectChoice + " from " + config.SSID
+ + " : " + config.networkId);
+ status.setConnectChoice(null);
+ status.setConnectChoiceTimestamp(WifiConfiguration.NetworkSelectionStatus
+ .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
+ }
+ }
+ }
+
/*
* Remove all networks associated with an application
*
@@ -1539,7 +1553,7 @@ public class WifiConfigStore extends IpConfigStore {
if (disableOthers) {
if (VDBG) localLogNetwork("enableNetwork(disableOthers=true, uid=" + uid + ") ", netId);
updateLastConnectUid(getWifiConfiguration(netId), uid);
- writeKnownNetworkHistory(false);
+ writeKnownNetworkHistory();
sendConfiguredNetworksChangedBroadcast();
} else {
if (VDBG) localLogNetwork("enableNetwork(disableOthers=false) ", netId);
@@ -1783,32 +1797,6 @@ public class WifiConfigStore extends IpConfigStore {
}
return true;
}
- /**
- * update the network history after user select a network
- * - if userTriggered, we mark the configuration as "non selfAdded" since the user has seen it
- * and took over management
- * - TODO: if selected network can override the setting ones, need remember the preference
- * user has higher preference of this network to all other saved network with good RSSI
- */
- public void userSelectNetwork(int netId, boolean connect) {
- WifiConfiguration selected = getWifiConfiguration(netId);
- if (selected == null) {
- Log.e(TAG, "userSelectNetwork: Can not find network with network ID: " + netId);
- return;
- }
-
- if (selected.SSID == null) {
- Log.e(TAG, "userSelectNetwork: no network SSID");
- return;
- }
-
- updateNetworkStatus(selected,
- WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE);
- selected.selfAdded = false;
- // Todo: may need remember user preferernce between networks?
- writeKnownNetworkHistory(false);
- }
-
/**
* Save the configured networks in supplicant to disk
@@ -2322,8 +2310,7 @@ public class WifiConfigStore extends IpConfigStore {
}, false);
}
- public void writeKnownNetworkHistory(boolean force) {
- boolean needUpdate = force;
+ public void writeKnownNetworkHistory() {
/* Make a copy */
final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
@@ -2331,13 +2318,10 @@ public class WifiConfigStore extends IpConfigStore {
networks.add(new WifiConfiguration(config));
}
if (VDBG) {
- logd(" writeKnownNetworkHistory() num networks:"
- + mConfiguredNetworks.sizeForAllUsers() + " (for all users) needWrite="
- + needUpdate);
- }
- if (needUpdate == false) {
- return;
+ loge(" writeKnownNetworkHistory() num networks:"
+ + mConfiguredNetworks.valuesForCurrentUser());
}
+
mWriter.write(networkHistoryConfigFile, new DelayedDiskWrite.Writer() {
public void onWriteCalled(DataOutputStream out) throws IOException {
for (WifiConfiguration config : networks) {
@@ -2347,13 +2331,10 @@ public class WifiConfigStore extends IpConfigStore {
else
loge("attempt config w/o lp");
*/
-
+ WifiConfiguration.NetworkSelectionStatus status =
+ config.getNetworkSelectionStatus();
if (VDBG) {
- int num = 0;
int numlink = 0;
- if (config.connectChoices != null) {
- num = config.connectChoices.size();
- }
if (config.linkedConfigurations != null) {
numlink = config.linkedConfigurations.size();
}
@@ -2366,12 +2347,12 @@ public class WifiConfigStore extends IpConfigStore {
}
loge("saving network history: " + config.configKey() + " gw: "
+ config.defaultGwMacAddress + " Network Selection-status: "
- + config.getNetworkSelectionStatus().getNetworkStatusString()
+ + status.getNetworkStatusString()
+ disableTime + " ephemeral=" + config.ephemeral
- + " choices:" + Integer.toString(num)
- + " link:" + Integer.toString(numlink)
- + " status:" + Integer.toString(config.status)
- + " nid:" + Integer.toString(config.networkId));
+ + " choice:" + status.getConnectChoice()
+ + " link:" + numlink
+ + " status:" + config.status
+ + " nid:" + config.networkId);
}
if (!WifiServiceImpl.isValid(config))
@@ -2391,19 +2372,17 @@ public class WifiConfigStore extends IpConfigStore {
if (config.SSID != null) {
out.writeUTF(SSID_KEY + SEPARATOR + config.SSID + NL);
}
+ if (config.BSSID != null) {
+ out.writeUTF(CONFIG_BSSID_KEY + SEPARATOR + config.BSSID + NL);
+ } else {
+ out.writeUTF(CONFIG_BSSID_KEY + SEPARATOR + "null" + NL);
+ }
if (config.FQDN != null) {
out.writeUTF(FQDN_KEY + SEPARATOR + config.FQDN + NL);
}
out.writeUTF(PRIORITY_KEY + SEPARATOR +
Integer.toString(config.priority) + NL);
- out.writeUTF(STATUS_KEY + SEPARATOR +
- config.getNetworkSelectionStatus().getNetworkStatusString() + NL);
- out.writeUTF(SUPPLICANT_STATUS_KEY + SEPARATOR +
- Integer.toString(config.status) + NL);
- out.writeUTF(SUPPLICANT_DISABLE_REASON_KEY + SEPARATOR +
- config.getNetworkSelectionStatus().getNetworkDisableReasonString()
- + NL);
out.writeUTF(NETWORK_ID_KEY + SEPARATOR +
Integer.toString(config.networkId) + NL);
out.writeUTF(SELF_ADDED_KEY + SEPARATOR +
@@ -2451,13 +2430,13 @@ public class WifiConfigStore extends IpConfigStore {
out.writeUTF(AUTH_KEY + SEPARATOR +
allowedKeyManagementString + NL);
- if (config.connectChoices != null) {
- for (String key : config.connectChoices.keySet()) {
- Integer choice = config.connectChoices.get(key);
- out.writeUTF(CHOICE_KEY + SEPARATOR +
- key + "=" + choice.toString() + NL);
- }
+
+ if (status.getConnectChoice() != null) {
+ out.writeUTF(CHOICE_KEY + SEPARATOR + status.getConnectChoice() + NL);
+ out.writeUTF(CHOICE_TIME_KEY + SEPARATOR
+ + status.getConnectChoiceTimestamp() + NL);
}
+
if (config.linkedConfigurations != null) {
log("writeKnownNetworkHistory write linked "
+ config.linkedConfigurations.size());
@@ -2484,14 +2463,6 @@ public class WifiConfigStore extends IpConfigStore {
out.writeUTF(RSSI_KEY + SEPARATOR +
Integer.toString(result.level) + NL);
- out.writeUTF(BSSID_STATUS_KEY + SEPARATOR
- + config.getNetworkSelectionStatus().getNetworkStatusString()
- + NL);
-
- //if (result.seen != 0) {
- // out.writeUTF(MILLI_KEY + SEPARATOR + Long.toString(result.seen)
- // + NL);
- //}
out.writeUTF(BSSID_KEY_END + NL);
}
}
@@ -2649,6 +2620,9 @@ public class WifiConfigStore extends IpConfigStore {
config.SSID = ssid;
}
break;
+ case CONFIG_BSSID_KEY:
+ config.BSSID = value.equals("null") ? null : value;
+ break;
case FQDN_KEY:
// Check for literal 'null' to be backwards compatible.
config.FQDN = value.equals("null") ? null : value;
@@ -2656,12 +2630,6 @@ public class WifiConfigStore extends IpConfigStore {
case DEFAULT_GW_KEY:
config.defaultGwMacAddress = value;
break;
- case STATUS_KEY:
- networkStatus.setNetworkSelectionStatus(Integer.parseInt(value));
- break;
- case SUPPLICANT_DISABLE_REASON_KEY:
- networkStatus.setNetworkSelectionDisableReason(Integer.parseInt(value));
- break;
case SELF_ADDED_KEY:
config.selfAdded = Boolean.parseBoolean(value);
break;
@@ -2711,26 +2679,10 @@ public class WifiConfigStore extends IpConfigStore {
config.peerWifiConfiguration = value;
break;
case CHOICE_KEY:
- String configKey = "";
- int choice = 0;
- Matcher match = mConnectChoice.matcher(value);
- if (!match.find()) {
- if (DBG) Log.d(TAG, "WifiConfigStore: connectChoice: " +
- " Couldnt match pattern : " + value);
- } else {
- configKey = match.group(1);
- try {
- choice = Integer.parseInt(match.group(2));
- } catch (NumberFormatException e) {
- choice = 0;
- }
- if (choice > 0) {
- if (config.connectChoices == null) {
- config.connectChoices = new HashMap<>();
- }
- config.connectChoices.put(configKey, choice);
- }
- }
+ networkStatus.setConnectChoice(value);
+ break;
+ case CHOICE_TIME_KEY:
+ networkStatus.setConnectChoiceTimestamp(Long.parseLong(value));
break;
case LINK_KEY:
if (config.linkedConfigurations == null) {
@@ -2752,9 +2704,6 @@ public class WifiConfigStore extends IpConfigStore {
case RSSI_KEY:
rssi = Integer.parseInt(value);
break;
- case BSSID_STATUS_KEY:
- status = Integer.parseInt(value);
- break;
case FREQ_KEY:
freq = Integer.parseInt(value);
break;
@@ -2956,13 +2905,14 @@ public class WifiConfigStore extends IpConfigStore {
break setVariables;
}
- if (config.BSSID != null) {
- log("Setting BSSID for " + config.configKey() + " to " + config.BSSID);
+ //set selected BSSID to supplicant
+ if (config.getNetworkSelectionStatus().getNetworkSelectionBSSID() != null) {
+ String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID();
if (!mWifiNative.setNetworkVariable(
netId,
WifiConfiguration.bssidVarName,
- config.BSSID)) {
- loge("failed to set BSSID: " + config.BSSID);
+ bssid)) {
+ loge("failed to set BSSID: " + bssid);
break setVariables;
}
}
@@ -3299,7 +3249,8 @@ public class WifiConfigStore extends IpConfigStore {
if (homeSP != null) {
writePasspointConfigs(null, homeSP);
}
- writeKnownNetworkHistory(true);
+
+ writeKnownNetworkHistory();
return result;
}
@@ -3918,7 +3869,7 @@ public class WifiConfigStore extends IpConfigStore {
mWifiNative.removeNetwork(config.networkId);
}
mWifiNative.saveConfig();
- writeKnownNetworkHistory(true);
+ writeKnownNetworkHistory();
}
final List<WifiConfiguration> hiddenConfigurations =
@@ -4074,9 +4025,9 @@ public class WifiConfigStore extends IpConfigStore {
value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.bssidVarName);
if (!TextUtils.isEmpty(value)) {
- config.BSSID = value;
+ config.getNetworkSelectionStatus().setNetworkSelectionBSSID(value);
} else {
- config.BSSID = null;
+ config.getNetworkSelectionStatus().setNetworkSelectionBSSID(null);
}
value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName);
diff --git a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelection.java b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelection.java
index 37304b6b7..5f9b748da 100644
--- a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelection.java
+++ b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelection.java
@@ -232,13 +232,12 @@ class WifiQualifiedNetworkSelector {
return true;
}
- /*
+ /**
* check whether QualifiedNetworkSelection is needed or not
* return - true need a Qualified Network Selection procedure
* - false do not need a QualifiedNetworkSelection procedure
*/
private boolean needQualifiedNetworkSelection() {
- //TODO:This should be called in scan result call back in the future
mScanDetails = mWifiStateMachine.getScanResultsListNoCopyUnsync();
if (mScanDetails.size() == 0) {
qnsLog("empty scan result");
@@ -363,7 +362,7 @@ class WifiQualifiedNetworkSelector {
}
//security award
- if (!TextUtils.isEmpty(network.FQDN)) {
+ if (network.isPasspoint()) {
score += mPasspointSecurityAward;
sbuf.append(" Passpoint Bonus:" + mPasspointSecurityAward);
} else if (!mWifiConfigStore.isOpenNetwork(network)) {
@@ -378,10 +377,10 @@ class WifiQualifiedNetworkSelector {
sbuf.append(" No internet Penalty:-" + mNoIntnetPenalty);
}
- if (mDbg) {
- sbuf.append("\n" + TAG + "Score for scanresult: " + scanResult + " and Network ID: "
- + network.networkId + " final score:" + score + "\n");
- }
+
+ sbuf.append(" Score for scanResult: " + scanResult + " and Network ID: "
+ + network.networkId + " final score:" + score + "\n\n");
+
return score;
}
@@ -395,21 +394,35 @@ class WifiQualifiedNetworkSelector {
return;
}
- if (mDbg) {
- StringBuffer sbuf = new StringBuffer("Saved Network List\n");
- for (WifiConfiguration network : savedNetworks) {
- WifiConfiguration.NetworkSelectionStatus networkStatus =
- network.getNetworkSelectionStatus();
- sbuf.append(" " + getNetworkString(network) + " "
- + networkStatus.getNetworkStatusString() + " Disable account: ");
- for (int index = networkStatus.NETWORK_SELECTION_ENABLE;
- index < networkStatus.NETWORK_SELECTION_DISABLED_MAX; index++) {
- sbuf.append(networkStatus.getDisableReasonCounter(index) + " ");
- }
- sbuf.append("\n");
+ StringBuffer sbuf = new StringBuffer("Saved Network List\n");
+ for (WifiConfiguration network : savedNetworks) {
+ WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(network.networkId);
+ WifiConfiguration.NetworkSelectionStatus status =
+ config.getNetworkSelectionStatus();
+
+ //If the configuration is temporarily disabled, try to re-enable it
+ if (status.isNetworkTemporaryDisabled()) {
+ mWifiConfigStore.tryEnableQualifiedNetwork(network.networkId);
}
- qnsLog(sbuf.toString());
+
+ //clean the cached candidate, score and seen
+ status.setCandidate(null);
+ status.setCandidateScore(Integer.MIN_VALUE);
+ status.setSeenInLastQualifiedNetworkSelection(false);
+
+ //print the debug messages
+ sbuf.append(" " + getNetworkString(network) + " " + " User Preferred BSSID:"
+ + network.BSSID + " FQDN:" + network.FQDN + " "
+ + status.getNetworkStatusString() + " Disable account: ");
+ for (int index = status.NETWORK_SELECTION_ENABLE;
+ index < status.NETWORK_SELECTION_DISABLED_MAX; index++) {
+ sbuf.append(status.getDisableReasonCounter(index) + " ");
+ }
+ sbuf.append("Connect Choice:" + status.getConnectChoice() + " set time:"
+ + status.getConnectChoiceTimestamp());
+ sbuf.append("\n");
}
+ qnsLog(sbuf.toString());
}
/**
@@ -437,7 +450,8 @@ class WifiQualifiedNetworkSelector {
// FIXME: 11/12/15 need fix auto_connect wifisatetmachine codes
String currentAssociationId = (mCurrentConnectedNetwork == null ? "Disconnected" :
mCurrentConnectedNetwork.SSID + ":" + mCurrentBssid);
- String targetAssociationId = newNetworkCandidate.SSID + ":" + newBssid;
+ String targetAssociationId = getNetworkString(newNetworkCandidate);
+
qnsLog("reconnect from " + currentAssociationId + " to " + targetAssociationId);
// the third parameter 0 means connect request from Network Selection
@@ -448,6 +462,82 @@ class WifiQualifiedNetworkSelector {
}
/**
+ * This API is called when user explicitly select a network. Currently, it is used in following
+ * cases:
+ * (1) User explicitly choose to connect to a saved network
+ * (2) User save a network after add a new network
+ * (3) User save a network after modify a saved network
+ * Following actions will be triggered:
+ * 1. if this network is disabled, we need re-enable it again
+ * 2. we considered user prefer this network over all the networks visible in latest network
+ * selection procedure
+ *
+ * @param netId new network ID for either the network the user choose or add
+ * @param persist whether user has the authority to overwrite current connect choice
+ * @return true -- There is change made to connection choice of any saved network
+ * false -- There is no change made to connection choice of any saved network
+ */
+ public boolean userSelectNetwork(int netId, boolean persist) {
+ WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId);
+ qnsLog("userSelectNetwork:" + netId + " persist:" + persist);
+ if (selected == null || selected.SSID == null) {
+ qnsLoge("userSelectNetwork: Bad configuration with nid=" + netId);
+ return false;
+ }
+
+
+ if (!selected.getNetworkSelectionStatus().isNetworkEnabled()) {
+ mWifiConfigStore.updateNetworkSelectionStatus(netId,
+ WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE);
+ }
+
+ if (!persist) {
+ qnsLog("User has no privilege to overwrite the current priority");
+ return false;
+ }
+
+ boolean change = false;
+ String key = selected.configKey();
+ long currentTime = System.currentTimeMillis();
+ List<WifiConfiguration> savedNetworks = mWifiConfigStore.getConfiguredNetworks();
+
+ for (WifiConfiguration network : savedNetworks) {
+ WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(network.networkId);
+ WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus();
+ if (config.networkId == selected.networkId) {
+ if (status.getConnectChoice() != null) {
+ qnsLog("Remove user selection preference of " + status.getConnectChoice()
+ + " Set Time: " + status.getConnectChoiceTimestamp() + " from "
+ + config.SSID + " : " + config.networkId);
+ status.setConnectChoice(null);
+ status.setConnectChoiceTimestamp(WifiConfiguration.NetworkSelectionStatus
+ .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
+ change = true;
+ }
+ continue;
+ }
+
+ if (status.getSeenInLastQualifiedNetworkSelection()
+ && (status.getConnectChoice() == null
+ || !status.getConnectChoice().equals(key))) {
+ qnsLog("Add key:" + key + " Set Time: " + currentTime + " to "
+ + getNetworkString(config));
+ status.setConnectChoice(key);
+ status.setConnectChoiceTimestamp(currentTime);
+ change = true;
+ }
+ }
+ //Write this change to file
+ if (change) {
+ mWifiConfigStore.writeKnownNetworkHistory();
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * ToDo: This should be called in Connectivity Scan Manager get scan result
* check whether a network slection is needed. If need, check all the new scan results and
* select a new qualified network/BSSID to connect to
* @param forceSelectNetwork if this one is true, start a qualified network selection anyway,
@@ -566,7 +656,17 @@ class WifiQualifiedNetworkSelector {
WifiConfiguration configurationCandidateForThisScan = null;
for (WifiConfiguration network : associatedWifiConfigurations) {
- if (!network.getNetworkSelectionStatus().isNetworkEnabled()) {
+ WifiConfiguration.NetworkSelectionStatus status =
+ network.getNetworkSelectionStatus();
+ status.setSeenInLastQualifiedNetworkSelection(true);
+ if (!status.isNetworkEnabled()) {
+ continue;
+ } else if (network.BSSID != null && !network.BSSID.equals("any")
+ && !network.BSSID.equals(scanResult.BSSID)) {
+ //in such scenario, user (APP) has specified the only BSSID to connect for this
+ // configuration. So only the matched scan result can be candidate
+ qnsLog("Network: " + getNetworkString(network) + " has specified" + "BSSID:"
+ + network.BSSID + ". Skip " + scanResult.BSSID);
continue;
}
score = calculateBssidScore(scanResult, network, mCurrentConnectedNetwork,
@@ -577,6 +677,11 @@ class WifiQualifiedNetworkSelector {
highestScore = score;
configurationCandidateForThisScan = network;
}
+ //update the cached candidate
+ if (score > status.getCandidateScore()) {
+ status.setCandidate(scanResult);
+ status.setCandidateScore(score);
+ }
}
if (highestScore > currentHighestScore || (highestScore == currentHighestScore
@@ -595,6 +700,31 @@ class WifiQualifiedNetworkSelector {
qnsLog(scoreHistory.toString());
}
+ //we need traverse the whole user preference to choose the one user like most now
+ if (scanResultCandidate != null) {
+ WifiConfiguration tempConfig = networkCandidate;
+
+ while (tempConfig.getNetworkSelectionStatus().getConnectChoice() != null) {
+ String key = tempConfig.getNetworkSelectionStatus().getConnectChoice();
+ tempConfig = mWifiConfigStore.getWifiConfiguration(key);
+
+ if (tempConfig != null) {
+ WifiConfiguration.NetworkSelectionStatus tempStatus =
+ tempConfig.getNetworkSelectionStatus();
+ if (tempStatus.getCandidate() != null && tempStatus.isNetworkEnabled()) {
+ scanResultCandidate = tempStatus.getCandidate();
+ networkCandidate = tempConfig;
+ }
+ } else {
+ //we should not come here in theory
+ qnsLoge("Connect choice: " + key + " has no corresponding saved config");
+ break;
+ }
+ }
+ qnsLog("After user choice adjust, the final candidate is:"
+ + getNetworkString(networkCandidate) + " : " + scanResultCandidate.BSSID);
+ }
+
// if we can not find scanCadidate in saved network
if (scanResultCandidate == null && mAllowUntrustedConnections) {
@@ -636,7 +766,7 @@ class WifiQualifiedNetworkSelector {
mCurrentConnectedNetwork.SSID + ":" + mCurrentBssid);
//In passpoint, saved configuration has garbage SSID
- if (!TextUtils.isEmpty(networkCandidate.FQDN)) {
+ if (networkCandidate.isPasspoint()) {
// This will updateb the passpoint configuration in WifiConfigStore
networkCandidate.SSID = "\"" + scanResultCandidate.SSID + "\"";
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index dea10765b..ec4d815d6 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -482,6 +482,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
ret = false; // Nothing to do
}
}
+ if (config.BSSID != null) {
+ bssid = config.BSSID;
+ if (DBG) {
+ Log.d(TAG, "force BSSID to " + bssid + "due to config");
+ }
+ }
+
if (VDBG) {
logd("autoRoamSetBSSID " + bssid + " key=" + config.configKey());
}
@@ -502,6 +509,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
if (config == null) {
return false;
}
+
if (config.BSSID != null) {
bssid = config.BSSID;
if (DBG) {
@@ -7171,7 +7179,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
// stick the last user choice without persisting the choice
mWifiConfigStore.setAndEnableLastSelectedConfiguration(res);
mWifiConfigStore.updateLastConnectUid(config, message.sendingUid);
- mWifiConfigStore.writeKnownNetworkHistory(false);
+ boolean persist = mWifiConfigStore
+ .checkConfigOverridePermission(message.sendingUid);
+ mWifiQualifiedNetworkSelector
+ .userSelectNetwork(res, persist);
// Remember time of last connection attempt
lastConnectAttemptTimestamp = System.currentTimeMillis();
@@ -7244,13 +7255,15 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
}
// Cancel auto roam requests
- mTargetNetworkId = netId;
autoRoamSetBSSID(netId, "any");
int uid = message.sendingUid;
+ mWifiQualifiedNetworkSelector.enableNetworkByUser(config);
ok = mWifiConfigStore.enableNetwork(netId, disableOthers, uid);
if (!ok) {
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
+ } else if (disableOthers) {
+ mTargetNetworkId = netId;
}
replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
@@ -7640,11 +7653,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
settings */
boolean persist =
mWifiConfigStore.checkConfigOverridePermission(message.sendingUid);
- mWifiConfigStore.updateNetworkSelectionStatus(config,
- WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE);
- mWifiConfigStore.setAndEnableLastSelectedConfiguration(netId);
+ mWifiConfigStore.setAndEnableLastSelectedConfiguration(netId);
+ mWifiQualifiedNetworkSelector.userSelectNetwork(netId, persist);
didDisconnect = false;
if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID
&& mLastNetworkId != netId) {
@@ -7775,10 +7787,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
if (user) {
mWifiConfigStore.updateLastConnectUid(config, message.sendingUid);
- mWifiConfigStore.writeKnownNetworkHistory(false);
+ mWifiConfigStore.writeKnownNetworkHistory();
}
//Fixme, CMD_AUTO_SAVE_NETWORK can be cleaned
- mWifiConfigStore.userSelectNetwork(
+ mWifiQualifiedNetworkSelector.userSelectNetwork(
result.getNetworkId(), persistConnect);
mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false);
}
@@ -8105,10 +8117,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
return;
if (DBG) {
logd(dbg + " " + mTargetRoamBSSID + " config " + config.configKey()
- + " config.bssid " + config.BSSID);
+ + " config.NetworkSelectionStatus.mNetworkSelectionBSSID "
+ + config.getNetworkSelectionStatus().getNetworkSelectionBSSID());
}
config.getNetworkSelectionStatus().setNetworkSelectionBSSID("any");
- config.BSSID = "any";
if (DBG) {
logd(dbg + " " + config.SSID
+ " nid=" + Integer.toString(config.networkId));
@@ -8933,7 +8945,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
.DISABLED_NO_INTERNET);
}
config.numNoInternetAccessReports += 1;
- mWifiConfigStore.writeKnownNetworkHistory(false);
+ mWifiConfigStore.writeKnownNetworkHistory();
}
}
return HANDLED;
@@ -8944,7 +8956,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
// re-enable autojoin
config.numNoInternetAccessReports = 0;
config.validatedInternetAccess = true;
- mWifiConfigStore.writeKnownNetworkHistory(false);
+ mWifiConfigStore.writeKnownNetworkHistory();
}
}
return HANDLED;
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java
index c786741cf..1368fc1c2 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java
@@ -23,6 +23,15 @@ import android.net.wifi.WifiEnterpriseConfig;
* Helper for creating and populating WifiConfigurations in unit tests.
*/
public class WifiConfigurationUtil {
+ /**
+ * These values are used to describe AP's security setting. One AP can support multiple of them,
+ * only if there is no conflict.
+ */
+ public static final int SECURITY_NONE = 0;
+ public static final int SECURITY_WEP = 1 << 0;
+ public static final int SECURITY_PSK = 1 << 1;
+ public static final int SECURITY_EAP = 1 << 2;
+
public static WifiConfiguration generateWifiConfig(int networkId, int uid, String ssid,
boolean shared, boolean enabled, String fqdn, String providerFriendlyName) {
final WifiConfiguration config = new WifiConfiguration();
@@ -39,4 +48,25 @@ public class WifiConfigurationUtil {
}
return config;
}
+
+ public static WifiConfiguration generateWifiConfig(int networkId, int uid, String ssid,
+ boolean shared, boolean enabled, String fqdn, String providerFriendlyName,
+ int security) {
+ WifiConfiguration config = generateWifiConfig(networkId, uid, ssid, shared, enabled, fqdn,
+ providerFriendlyName);
+
+ if (security == SECURITY_NONE) {
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ } else {
+ if (((security & SECURITY_WEP) != 0) || ((security & SECURITY_PSK) != 0)) {
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ }
+
+ if ((security & SECURITY_EAP) != 0) {
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ }
+ }
+ return config;
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectionTest.java b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectionTest.java
index 49b7f88d5..56f3333dc 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectionTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectionTest.java
@@ -16,8 +16,12 @@
package com.android.server.wifi;
+import static com.android.server.wifi.WifiConfigurationUtil.SECURITY_NONE;
+import static com.android.server.wifi.WifiConfigurationUtil.SECURITY_PSK;
+import static com.android.server.wifi.WifiConfigurationUtil.generateWifiConfig;
+
import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.any;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.validateMockitoUsage;
import static org.mockito.Mockito.when;
@@ -32,12 +36,14 @@ import android.net.wifi.WifiSsid;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.R;
+import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -46,6 +52,8 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
@SmallTest
public class WifiQualifiedNetworkSelectionTest {
+
+
@Before
public void setUp() throws Exception {
mWifiStateMachine = getWifiStateMachine();
@@ -159,44 +167,68 @@ public class WifiQualifiedNetworkSelectionTest {
return wifiConfigStore;
}
- @Test
/**
+ * This API is used to generate multiple simulated saved configurations used for test
+ * @param ssid array of SSID of saved configuration
+ * @param security array of securities of saved configuration
+ * @return generated new array of configurations based on input
+ */
+ private WifiConfiguration[] generateWifiConfigurations(String[] ssid, int[] security) {
+ if (ssid == null || security == null || ssid.length != security.length
+ || ssid.length == 0) {
+ return null;
+ }
+
+ WifiConfiguration[] configs = new WifiConfiguration[ssid.length];
+ for (int index = 0; index < ssid.length; index++) {
+ configs[index] = generateWifiConfig(index, 0, ssid[index], false, true, null , null,
+ security[index]);
+ }
+
+ return configs;
+ }
+
+ /**
+ * Case #1
* In this test. we simulate following scenario
* WifiStateMachine is under disconnected state
* Two networks test1, test2 are secured network
* Both network are enabled
- * test1 is @ 2GHz with RSSI
+ * test1 is @ 2GHz with RSSI -50
+ * test2 is @ 5Ghz with RSSI -65
+ * Expected behavior: test2 is chosen
*/
- public void chooseNetworkDisconnect5GOver2G() {
+ @Test
+ public void chooseNetworkDisconnect5GOver2GTest() {
String[] ssids = {"\"test1\"", "\"test2\""};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] frequencies = {2437, 5180};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
int[] levels = {-50, -65};
+ int[] security = {SECURITY_PSK, SECURITY_PSK};
List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
when(mWifiStateMachine.getScanResultsListNoCopyUnsync()).thenReturn(scanDetails);
- when(mWifiStateMachine.isConnected()).thenReturn(false);
when(mWifiStateMachine.isDisconnected()).thenReturn(true);
- WifiConfiguration configuration1 = new WifiConfiguration();
- configuration1.networkId = 0;
- configuration1.SSID = "\"test1\"";
- WifiConfiguration configuration2 = new WifiConfiguration();
- configuration2.networkId = 1;
- configuration2.SSID = "\"test2\"";
-
- List<WifiConfiguration> savedNetwork = new ArrayList<WifiConfiguration>();
- savedNetwork.add(configuration1);
- savedNetwork.add(configuration2);
-
- when(mWifiConfigStore.isOpenNetwork(any(WifiConfiguration.class))).thenReturn(false);
- when(mWifiConfigStore.isOpenNetwork(any(ScanResult.class))).thenReturn(false);
- when(mWifiConfigStore.getWifiConfiguration(0)).thenReturn(configuration1);
- when(mWifiConfigStore.getWifiConfiguration(1)).thenReturn(configuration2);
+ final List<WifiConfiguration> savedNetwork =
+ Arrays.asList(generateWifiConfigurations(ssids, security));
+
+ WifiConfiguration configuration1 = savedNetwork.get(0);
+ WifiConfiguration configuration2 = savedNetwork.get(1);
+
+ when(mWifiConfigStore.getWifiConfiguration(anyInt()))
+ .then(new AnswerWithArguments<Boolean>() {
+ public WifiConfiguration answer(int netId) {
+ if (netId >= 0 && netId < savedNetwork.size()) {
+ return savedNetwork.get(netId);
+ } else {
+ return null;
+ }
+ }
+ });
+
when(mWifiConfigStore.getConfiguredNetworks()).thenReturn(savedNetwork);
- when(mWifiConfigStore.getLastSelectedConfiguration()).thenReturn(null);
- when(mWifiConfigStore.isBssidBlacklisted(any(String.class))).thenReturn(false);
List<WifiConfiguration> associateWithScanResult1 = new ArrayList<WifiConfiguration>();
associateWithScanResult1.add(configuration1);
@@ -208,10 +240,123 @@ public class WifiQualifiedNetworkSelectionTest {
associateWithScanResult1);
when(mWifiConfigStore.updateSavedNetworkWithNewScanDetail(scanDetails.get(1))).thenReturn(
associateWithScanResult2);
- ScanResult scanResult = scanDetails.get(1).getScanResult();
+ ScanResult chosenScanResult = scanDetails.get(scanDetails.size() - 1).getScanResult();
+
+ mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false);
+ assertEquals("choose the wrong SSID", chosenScanResult.SSID,
+ mWifiQualifiedNetworkSelector.getConnetionTargetNetwork().SSID);
+ }
+
+ /**
+ * Case #2
+ * In this test. we simulate following scenario
+ * There are three saved networks: test1, test2 and test3. Now user select the network test3
+ */
+ @Test
+ public void userSelectsNetworkForFirstTime() {
+ String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\""};
+ int[] security = {SECURITY_PSK, SECURITY_PSK, SECURITY_NONE};
+
+ final WifiConfiguration[] configs = generateWifiConfigurations(ssids, security);
+
+ when(mWifiConfigStore.getWifiConfiguration(anyInt()))
+ .then(new AnswerWithArguments<Boolean>() {
+ public WifiConfiguration answer(int netId) {
+ if (netId >= 0 && netId < configs.length) {
+ return configs[netId];
+ } else {
+ return null;
+ }
+ }
+ });
+
+ when(mWifiConfigStore.getConfiguredNetworks()).thenReturn(Arrays.asList(configs));
+ for (WifiConfiguration network : configs) {
+ WifiConfiguration.NetworkSelectionStatus status = network.getNetworkSelectionStatus();
+ status.setSeenInLastQualifiedNetworkSelection(true);
+ }
+
+ mWifiQualifiedNetworkSelector.userSelectNetwork(configs.length - 1, true);
+ String key = configs[configs.length - 1].configKey();
+ for (int index = 0; index < configs.length; index++) {
+ WifiConfiguration config = configs[index];
+ WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus();
+ if (index == configs.length - 1) {
+ assertEquals("User selected network should not have prefernce over it", null,
+ status.getConnectChoice());
+ } else {
+ assertEquals("Wrong user preference", key, status.getConnectChoice());
+ }
+ }
+ }
+
+ /**
+ * case #3
+ * In this test, we simulate following scenario:
+ * There are three networks: test1, test2, test3 and test3 is the user preference
+ * All three networks are enabled
+ * test1 is @ 2.4GHz with RSSI -50 PSK
+ * test2 is @ 5Ghz with RSSI -65 PSK
+ * test3 is @ 2.4GHz with RSSI -55
+ * Expected behavior: test3 is chosen
+ */
+ @Test
+ public void chooseUserPreferredNetwork() {
+ //Generate mocked saved configurations
+ String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\""};
+ int[] security = {SECURITY_PSK, SECURITY_PSK, SECURITY_NONE};
+ final WifiConfiguration[] configs = generateWifiConfigurations(ssids, security);
+ for (WifiConfiguration network : configs) {
+ WifiConfiguration.NetworkSelectionStatus status = network.getNetworkSelectionStatus();
+ status.setSeenInLastQualifiedNetworkSelection(true);
+ }
+
+ when(mWifiConfigStore.getConfiguredNetworks()).thenReturn(Arrays.asList(configs));
+
+ when(mWifiConfigStore.getWifiConfiguration(anyInt()))
+ .then(new AnswerWithArguments<Boolean>() {
+ public WifiConfiguration answer(int netId) {
+ if (netId >= 0 && netId < configs.length) {
+ return configs[netId];
+ } else {
+ return null;
+ }
+ }
+ });
+
+ //set user preference
+ mWifiQualifiedNetworkSelector.userSelectNetwork(ssids.length - 1, true);
+ //Generate mocked recent scan results
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "6c:f3:7f:ae:8c:f5"};
+ int[] frequencies = {2437, 5180, 2437};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]", "NONE"};
+ int[] levels = {-50, -65, -55};
+
+ List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
+ when(mWifiStateMachine.getScanResultsListNoCopyUnsync()).thenReturn(scanDetails);
+ when(mWifiStateMachine.isDisconnected()).thenReturn(true);
+
+ List<WifiConfiguration> associateWithScanResult1 = new ArrayList<WifiConfiguration>();
+ associateWithScanResult1.add(configs[0]);
+
+ List<WifiConfiguration> associateWithScanResult2 = new ArrayList<WifiConfiguration>();
+ associateWithScanResult2.add(configs[1]);
+
+ List<WifiConfiguration> associateWithScanResult3 = new ArrayList<WifiConfiguration>();
+ associateWithScanResult3.add(configs[2]);
+
+ when(mWifiConfigStore.updateSavedNetworkWithNewScanDetail(scanDetails.get(0))).thenReturn(
+ associateWithScanResult1);
+ when(mWifiConfigStore.updateSavedNetworkWithNewScanDetail(scanDetails.get(1))).thenReturn(
+ associateWithScanResult2);
+ when(mWifiConfigStore.updateSavedNetworkWithNewScanDetail(scanDetails.get(2))).thenReturn(
+ associateWithScanResult3);
+ ScanResult chosenScanResult = scanDetails.get(scanDetails.size() - 1).getScanResult();
+ when(mWifiConfigStore.getWifiConfiguration(configs[2].configKey()))
+ .thenReturn(configs[2]);
mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false);
- assertEquals("choose the wrong SSID", scanResult.SSID,
+ assertEquals("choose the wrong SSID", chosenScanResult.SSID,
mWifiQualifiedNetworkSelector.getConnetionTargetNetwork().SSID);
}
}