From ac9ad3283508db15b65b1cbb89b841278973276b Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 27 Jan 2016 17:36:42 -0800 Subject: Update network priorities before PNO is triggered The max SSID watch list size for PNO supported by wlan drivers is fixed to a certain size. wpa_supplicant sorts this SSID watch list based on the priorities assigned to those networks. This may result in us losing some frequently used networks from the PNO list because they have lower priorities. This is a side effect of how we assign priorities to network configuration as they're added. So before we trigger PNO, re-sort the network list based on the 'numAssociation' value and assign them relative priorities. This will make sure that the PNO SSID watch list contains all the frequent SSID's to which we were connected to. PS: This change has a side-effect of ignoring the configured priorities during PNO. While there, 1. Add a common test utils class for common utility functions for all tests. 2. Annotate all tests in WifiConfigStore so that |WifiTestUtil.getTestMethod| works reliably. BUG: 26763375 Change-Id: I2c82254b2cb83aef0dd4da9e7d9b2eb5b376bead TEST: `adb shell am instrument -e class 'com.android.server.wifi.WifiConfigStoreTest' -w 'com.android.server.wifi.test/android.support.test.runner.AndroidJUnitRunner'` --- .../com/android/server/wifi/WifiConfigStore.java | 78 ++++++++++++++++++++++ .../java/com/android/server/wifi/WifiNative.java | 63 +++++++++++++++-- .../com/android/server/wifi/WifiStateMachine.java | 4 +- 3 files changed, 138 insertions(+), 7 deletions(-) (limited to 'service') diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index 77757a8b3..cc9e5068f 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -1363,6 +1363,84 @@ public class WifiConfigStore extends IpConfigStore { } } + + /** + * PnoNetwork list sorting algorithm: + * 1, Place the fully enabled networks first. Among the fully enabled networks, + * sort them in descending order of their |numAssociation| values. If networks have + * the same |numAssociation|, then sort them in descending order of their |priority| + * values. + * 2. Next place all the temporarily disabled networks. Among the temporarily disabled + * networks, sort them in the same order as the fully enabled networks. + * 3. Place the permanently disabled networks last. The order among permanently disabled + * networks doesn't matter. + */ + private static final Comparator sPnoListSortComparator = + new Comparator() { + public int compare(WifiConfiguration a, WifiConfiguration b) { + boolean isConfigAEnabled = a.getNetworkSelectionStatus().isNetworkEnabled(); + boolean isConfigBEnabled = b.getNetworkSelectionStatus().isNetworkEnabled(); + boolean isConfigATempDisabled = + a.getNetworkSelectionStatus().isNetworkTemporaryDisabled(); + boolean isConfigBTempDisabled = + b.getNetworkSelectionStatus().isNetworkTemporaryDisabled(); + if ((isConfigAEnabled && isConfigBEnabled) + || (isConfigATempDisabled && isConfigBTempDisabled)) { + // If 2 networks have the same saved |numAssociation| value, sort them + // according to their priority. + if (a.numAssociation != b.numAssociation) { + return Long.compare(b.numAssociation, a.numAssociation); + } else { + return Integer.compare(b.priority, a.priority); + } + } else if (isConfigAEnabled != isConfigBEnabled) { + return Boolean.compare(isConfigBEnabled, isConfigAEnabled); + } else { + return Boolean.compare(isConfigBTempDisabled, isConfigATempDisabled); + } + } + }; + + /** + * Retrieves an updated list of priorities for all the saved networks before + * enabling/disabling PNO. + * + * wpa_supplicant uses the priority of networks to build the list of SSID's to monitor + * during PNO. If there are a lot of saved networks, this list will be truncated and we + * might end up not connecting to the networks we use most frequently. So, We want the networks + * to be re-sorted based on the relative |numAssociation| values. + * + * @param enablePno boolean indicating whether PNO is being enabled or disabled. + * @return list of networks with updated priorities. + */ + ArrayList retrievePnoNetworkPriorityList(boolean enablePno) { + ArrayList pnoList = + new ArrayList(); + ArrayList wifiConfigurations = + new ArrayList(mConfiguredNetworks.valuesForCurrentUser()); + if (enablePno) { + Collections.sort(wifiConfigurations, sPnoListSortComparator); + // Let's use the network list size as the highest priority and then go down from there. + // So, the most frequently connected network has the highest priority now. + int priority = wifiConfigurations.size(); + if (DBG) { + Log.d(TAG, "Retrieve network priorities before PNO. Max priority: " + priority); + } + for (WifiConfiguration config : wifiConfigurations) { + pnoList.add(new WifiNative.PnoNetworkPriority(config.networkId, priority)); + priority--; + } + } else { + // Revert the priorities back to the saved config values after PNO. + if (DBG) Log.d(TAG, "Retrieve network priorities after PNO."); + for (WifiConfiguration config : wifiConfigurations) { + pnoList.add(new WifiNative.PnoNetworkPriority(config.networkId, config.priority)); + } + } + return pnoList; + } + + String[] getWhiteListedSsids(WifiConfiguration config) { int num_ssids = 0; String nonQuoteSSID; diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index 20f5ab3c7..9246c2ea9 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -880,6 +880,29 @@ public class WifiNative { return doBooleanCommand("DRIVER COUNTRY"); } + + /** + * Object holding the network ID and the corresponding priority to be set before enabling/ + * disabling PNO. + */ + public static class PnoNetworkPriority { + public int networkId; + public int priority; + + PnoNetworkPriority(int networkId, int priority) { + this.networkId = networkId; + this.priority = priority; + } + + @Override + public String toString() { + StringBuilder sbuf = new StringBuilder(); + sbuf.append(" Network ID=").append(this.networkId); + sbuf.append(" Priority=").append(this.priority); + return sbuf.toString(); + } + } + //PNO Monitor private class PnoMonitor { private static final int MINIMUM_PNO_GAP = 5 * 1000; @@ -887,6 +910,7 @@ public class WifiNative { "com.android.server.Wifi.action.TOGGLE_PNO"; long mLastPnoChangeTimeStamp = -1L; boolean mExpectedPnoState = false; + List mExpectedPnoNetworkPriorityList = null; boolean mCurrentPnoState = false;; boolean mWaitForTimer = false; final Object mPnoLock = new Object(); @@ -909,7 +933,8 @@ public class WifiNative { if (mCurrentPnoState != mExpectedPnoState) { if (DBG) Log.d(mTAG, "change PNO from " + mCurrentPnoState + " to " + mExpectedPnoState); - boolean ret = setPno(mExpectedPnoState); + boolean ret = setPno( + mExpectedPnoState, mExpectedPnoNetworkPriorityList); if (!ret) { Log.e(mTAG, "set PNO failure"); } @@ -923,7 +948,27 @@ public class WifiNative { new IntentFilter(ACTION_TOGGLE_PNO)); } - private boolean setPno(boolean enable) { + /* Enable/Disable PNO with updated network priorities. + * + * @param enable boolean indicating whether PNO is being enabled or disabled. + * @param pnoNetworkList list of networks with priorities to be set before PNO setting. + */ + private boolean setPno(boolean enable, List pnoNetworkList) { + // TODO: Couple of cases yet to be handled: + // 1. What if the network priority update fails, should we bail out of PNO setting? + // 2. If PNO setting fails below, should we go back and revert this priority change? + if (pnoNetworkList != null) { + if (DBG) Log.i(mTAG, "Update priorities for PNO. Enable: " + enable); + for (PnoNetworkPriority pnoNetwork : pnoNetworkList) { + // What if this fails? Should we bail out? + boolean isSuccess = setNetworkVariable(pnoNetwork.networkId, + WifiConfiguration.priorityVarName, + Integer.toString(pnoNetwork.priority)); + if (DBG && !isSuccess) { + Log.e(mTAG, "Update priority failed for :" + pnoNetwork.networkId); + } + } + } String cmd = enable ? "SET pno 1" : "SET pno 0"; boolean ret = doBooleanCommand(cmd); mLastPnoChangeTimeStamp = System.currentTimeMillis(); @@ -933,11 +978,14 @@ public class WifiNative { return ret; } - public boolean enableBackgroundScan(boolean enable) { + public boolean enableBackgroundScan( + boolean enable, + List pnoNetworkList) { synchronized(mPnoLock) { if (mWaitForTimer) { //already has a timer mExpectedPnoState = enable; + mExpectedPnoNetworkPriorityList = pnoNetworkList; if (DBG) Log.d(mTAG, "update expected PNO to " + mExpectedPnoState); } else { if (mCurrentPnoState == enable) { @@ -945,9 +993,10 @@ public class WifiNative { } long timeDifference = System.currentTimeMillis() - mLastPnoChangeTimeStamp; if (timeDifference >= MINIMUM_PNO_GAP) { - return setPno(enable); + return setPno(enable, pnoNetworkList); } else { mExpectedPnoState = enable; + mExpectedPnoNetworkPriorityList = pnoNetworkList; mWaitForTimer = true; if (DBG) Log.d(mTAG, "start PNO timer with delay:" + timeDifference); mAlarmManager.set(AlarmManager.RTC_WAKEUP, @@ -959,9 +1008,11 @@ public class WifiNative { } } - public boolean enableBackgroundScan(boolean enable) { + public boolean enableBackgroundScan( + boolean enable, + List pnoNetworkList) { if (mPnoMonitor != null) { - return mPnoMonitor.enableBackgroundScan(enable); + return mPnoMonitor.enableBackgroundScan(enable, pnoNetworkList); } else { return false; } diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index f600f308f..eae00a607 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -2509,7 +2509,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno if (enable) { mWifiConfigStore.enableAllNetworks(); } - boolean ret = mWifiNative.enableBackgroundScan(enable); + List pnoList = + mWifiConfigStore.retrievePnoNetworkPriorityList(enable); + boolean ret = mWifiNative.enableBackgroundScan(enable, pnoList); if (ret) { mLegacyPnoEnabled = enable; } else { -- cgit v1.2.3