diff options
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); } } |