Use a LRU to in memory store the network connection order
In memory use a LRU to determine the network connection order for non-passpoint network.
And persist a bool on the disk, only set 16(or whatever overlay config) most recently connected
network to true.
Bug: 150799593
Test: atest com.android.server.wifi
Change-Id: Ic4594810409fbfe91e0c7d840d8a6d9f571e184f
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 1fd3c51..b13251d 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -52,6 +52,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wifi.hotspot2.PasspointManager;
+import com.android.server.wifi.util.LruConnectionTracker;
import com.android.server.wifi.util.MissingCounterTimerLockList;
import com.android.server.wifi.util.TelephonyUtil;
import com.android.server.wifi.util.WifiPermissionsUtil;
@@ -234,6 +235,8 @@
private final MacAddressUtil mMacAddressUtil;
private final TelephonyUtil mTelephonyUtil;
private final WifiScoreCard mWifiScoreCard;
+ // Keep order of network connection.
+ private final LruConnectionTracker mLruConnectionTracker;
/**
* Local log used for debugging any WifiConfigManager issues.
@@ -256,7 +259,6 @@
*/
private final MissingCounterTimerLockList<String> mUserTemporarilyDisabledList;
-
/**
* Framework keeps a mapping from configKey to the randomized MAC address so that
* when a user forgets a network and thne adds it back, the same randomized MAC address
@@ -331,7 +333,8 @@
NetworkListUserStoreData networkListUserStoreData,
RandomizedMacStoreData randomizedMacStoreData,
FrameworkFacade frameworkFacade, Handler handler,
- DeviceConfigFacade deviceConfigFacade, WifiScoreCard wifiScoreCard) {
+ DeviceConfigFacade deviceConfigFacade, WifiScoreCard wifiScoreCard,
+ LruConnectionTracker lruConnectionTracker) {
mContext = context;
mClock = clock;
mUserManager = userManager;
@@ -365,6 +368,7 @@
mLocalLog = new LocalLog(
context.getSystemService(ActivityManager.class).isLowRamDevice() ? 128 : 256);
mMacAddressUtil = mWifiInjector.getMacAddressUtil();
+ mLruConnectionTracker = lruConnectionTracker;
}
/**
@@ -1429,6 +1433,9 @@
if (networkId == mLastSelectedNetworkId) {
clearLastSelectedNetwork();
}
+ if (!config.ephemeral && !config.isPasspoint()) {
+ mLruConnectionTracker.removeNetwork(config);
+ }
sendConfiguredNetworkChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED);
// Unless the removed network is ephemeral or Passpoint, persist the network removal.
if (!config.ephemeral && !config.isPasspoint()) {
@@ -1953,6 +1960,11 @@
if (config == null) {
return false;
}
+
+ // Only record connection order for non-passpoint from user saved or suggestion.
+ if (!config.isPasspoint() && (config.fromWifiNetworkSuggestion || !config.ephemeral)) {
+ mLruConnectionTracker.addNetwork(config);
+ }
config.lastConnected = mClock.getWallClockMillis();
config.numAssociation++;
config.getNetworkSelectionStatus().clearDisableReasonCounter();
@@ -3109,6 +3121,10 @@
} catch (IllegalArgumentException e) {
Log.e(TAG, "Failed to add network to config map", e);
}
+
+ if (configuration.isMostRecentlyConnected) {
+ mLruConnectionTracker.addNetwork(configuration);
+ }
}
}
@@ -3280,6 +3296,9 @@
continue;
}
+ config.isMostRecentlyConnected =
+ mLruConnectionTracker.isMostRecentlyConnected(config);
+
// We push all shared networks & private networks not belonging to the current
// user to the shared store. Ideally, private networks for other users should
// not even be in memory,
@@ -3428,5 +3447,4 @@
}
return scanMaxRssi;
}
-
}
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index f388d23..93fe2b5b 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -53,6 +53,7 @@
import com.android.server.wifi.p2p.WifiP2pMonitor;
import com.android.server.wifi.p2p.WifiP2pNative;
import com.android.server.wifi.rtt.RttMetrics;
+import com.android.server.wifi.util.LruConnectionTracker;
import com.android.server.wifi.util.NetdWrapper;
import com.android.server.wifi.util.SettingsMigrationDataHolder;
import com.android.server.wifi.util.TelephonyUtil;
@@ -75,6 +76,10 @@
public class WifiInjector {
private static final String TAG = "WifiInjector";
private static final String BOOT_DEFAULT_WIFI_COUNTRY_CODE = "ro.boot.wificountrycode";
+ /**
+ * Maximum number in-memory store network connection order;
+ */
+ private static final int MAX_RECENTLY_CONNECTED_NETWORK = 100;
static WifiInjector sWifiInjector = null;
@@ -162,6 +167,7 @@
private final WifiScanAlwaysAvailableSettingsCompatibility
mWifiScanAlwaysAvailableSettingsCompatibility;
private final SettingsMigrationDataHolder mSettingsMigrationDataHolder;
+ private final LruConnectionTracker mLruConnectionTracker;
public WifiInjector(Context context) {
if (context == null) {
@@ -258,6 +264,8 @@
mFrameworkFacade, mContext, wifiHandler);
String l2KeySeed = Secure.getString(mContext.getContentResolver(), Secure.ANDROID_ID);
mWifiScoreCard = new WifiScoreCard(mClock, l2KeySeed, mDeviceConfigFacade);
+ mLruConnectionTracker = new LruConnectionTracker(MAX_RECENTLY_CONNECTED_NETWORK,
+ mContext);
// Config Manager
mWifiConfigManager = new WifiConfigManager(mContext, mClock,
mUserManager, mTelephonyUtil,
@@ -266,7 +274,7 @@
new NetworkListSharedStoreData(mContext),
new NetworkListUserStoreData(mContext),
new RandomizedMacStoreData(), mFrameworkFacade, wifiHandler, mDeviceConfigFacade,
- mWifiScoreCard);
+ mWifiScoreCard, mLruConnectionTracker);
mSettingsConfigStore = new WifiSettingsConfigStore(context, wifiHandler,
mSettingsMigrationDataHolder, mWifiConfigManager, mWifiConfigStore);
mSettingsStore = new WifiSettingsStore(mContext, mSettingsConfigStore);
@@ -292,7 +300,7 @@
mWifiMetrics.setWifiNetworkSelector(mWifiNetworkSelector);
mWifiNetworkSuggestionsManager = new WifiNetworkSuggestionsManager(mContext, wifiHandler,
this, mWifiPermissionsUtil, mWifiConfigManager, mWifiConfigStore, mWifiMetrics,
- mTelephonyUtil, mWifiKeyStore);
+ mTelephonyUtil, mWifiKeyStore, mLruConnectionTracker);
mPasspointManager = new PasspointManager(mContext, this,
wifiHandler, mWifiNative, mWifiKeyStore, mClock, new PasspointObjectFactory(),
mWifiConfigManager, mWifiConfigStore, mWifiMetrics, mTelephonyUtil);
diff --git a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
index d59d2a0..c82539b 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
@@ -57,6 +57,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.server.wifi.util.ExternalCallbackTracker;
+import com.android.server.wifi.util.LruConnectionTracker;
import com.android.server.wifi.util.TelephonyUtil;
import com.android.server.wifi.util.WifiPermissionsUtil;
import com.android.wifi.resources.R;
@@ -139,6 +140,8 @@
private final FrameworkFacade mFrameworkFacade;
private final TelephonyUtil mTelephonyUtil;
private final WifiKeyStore mWifiKeyStore;
+ // Keep order of network connection.
+ private final LruConnectionTracker mLruConnectionTracker;
/**
* Per app meta data to store network suggestions, status, etc for each app providing network
@@ -391,6 +394,17 @@
private class NetworkSuggestionDataSource implements NetworkSuggestionStoreData.DataSource {
@Override
public Map<String, PerAppInfo> toSerialize() {
+ for (Map.Entry<String, PerAppInfo> entry : mActiveNetworkSuggestionsPerApp.entrySet()) {
+ Set<ExtendedWifiNetworkSuggestion> extNetworkSuggestions =
+ entry.getValue().extNetworkSuggestions;
+ for (ExtendedWifiNetworkSuggestion ewns : extNetworkSuggestions) {
+ if (ewns.wns.passpointConfiguration != null) {
+ continue;
+ }
+ ewns.wns.wifiConfiguration.isMostRecentlyConnected = mLruConnectionTracker
+ .isMostRecentlyConnected(ewns.createInternalWifiConfiguration());
+ }
+ }
// Clear the flag after writing to disk.
// TODO(b/115504887): Don't reset the flag on write failure.
mHasNewDataToSerialize = false;
@@ -414,6 +428,10 @@
if (ewns.wns.passpointConfiguration != null) {
addToPasspointInfoMap(ewns);
} else {
+ if (ewns.wns.wifiConfiguration.isMostRecentlyConnected) {
+ mLruConnectionTracker
+ .addNetwork(ewns.createInternalWifiConfiguration());
+ }
addToScanResultMatchInfoMap(ewns);
}
}
@@ -551,13 +569,10 @@
};
public WifiNetworkSuggestionsManager(Context context, Handler handler,
- WifiInjector wifiInjector,
- WifiPermissionsUtil wifiPermissionsUtil,
- WifiConfigManager wifiConfigManager,
- WifiConfigStore wifiConfigStore,
- WifiMetrics wifiMetrics,
- TelephonyUtil telephonyUtil,
- WifiKeyStore keyStore) {
+ WifiInjector wifiInjector, WifiPermissionsUtil wifiPermissionsUtil,
+ WifiConfigManager wifiConfigManager, WifiConfigStore wifiConfigStore,
+ WifiMetrics wifiMetrics, TelephonyUtil telephonyUtil,
+ WifiKeyStore keyStore, LruConnectionTracker lruConnectionTracker) {
mContext = context;
mResources = context.getResources();
mHandler = handler;
@@ -589,6 +604,7 @@
mIntentFilter.addAction(NOTIFICATION_USER_DISALLOWED_CARRIER_INTENT_ACTION);
mContext.registerReceiver(mBroadcastReceiver, mIntentFilter, null, handler);
+ mLruConnectionTracker = lruConnectionTracker;
}
/**
@@ -662,6 +678,8 @@
mActiveScanResultMatchInfoWithBssid.remove(lookupPair);
if (!mActiveScanResultMatchInfoWithNoBssid.containsKey(scanResultMatchInfo)) {
removeNetworkFromScoreCard(extNetworkSuggestion.wns.wifiConfiguration);
+ mLruConnectionTracker.removeNetwork(
+ extNetworkSuggestion.wns.wifiConfiguration);
}
}
} else {
@@ -678,6 +696,8 @@
if (extNetworkSuggestionsForScanResultMatchInfo.isEmpty()) {
mActiveScanResultMatchInfoWithNoBssid.remove(scanResultMatchInfo);
removeNetworkFromScoreCard(extNetworkSuggestion.wns.wifiConfiguration);
+ mLruConnectionTracker.removeNetwork(
+ extNetworkSuggestion.wns.wifiConfiguration);
}
}
}
@@ -1716,7 +1736,6 @@
if (!(connectedNetwork.fromWifiNetworkSuggestion || connectedNetwork.isOpenNetwork())) {
return;
}
-
Set<ExtendedWifiNetworkSuggestion> matchingExtNetworkSuggestions =
getNetworkSuggestionsForWifiConfiguration(connectedNetwork, connectedBssid);
diff --git a/service/java/com/android/server/wifi/util/LruConnectionTracker.java b/service/java/com/android/server/wifi/util/LruConnectionTracker.java
new file mode 100644
index 0000000..2567288
--- /dev/null
+++ b/service/java/com/android/server/wifi/util/LruConnectionTracker.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.util;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+
+import com.android.server.wifi.ScanResultMatchInfo;
+import com.android.wifi.resources.R;
+
+/**
+ * Create a lru list to store the network connection order. sorted by most recently connected
+ * first.
+ */
+public class LruConnectionTracker {
+ private final LruList<ScanResultMatchInfo> mList;
+ private final Context mContext;
+ public LruConnectionTracker(int size, Context context) {
+ mList = new LruList<>(size);
+ mContext = context;
+ }
+ /**
+ * Check if a WifiConfiguration is in the most recently connected list.
+ */
+ public boolean isMostRecentlyConnected(@NonNull WifiConfiguration config) {
+ return getAgeIndexOfNetwork(config) < mContext.getResources()
+ .getInteger(R.integer.config_wifiMaxPnoSsidCount);
+ }
+
+ /**
+ * Add a WifiConfiguration into the most recently connected list.
+ */
+ public void addNetwork(@NonNull WifiConfiguration config) {
+ mList.add(ScanResultMatchInfo.fromWifiConfiguration(config));
+ }
+
+ /**
+ * Remove a network from the list.
+ */
+ public void removeNetwork(@NonNull WifiConfiguration config) {
+ mList.remove(ScanResultMatchInfo.fromWifiConfiguration(config));
+ }
+
+ /**
+ * Get the index of the input config inside the MostRecentlyConnectNetworkList.
+ * If input config is in the list will return index number,
+ * otherwise return {@code Integer.MAX_VALUE}
+ */
+ public int getAgeIndexOfNetwork(@NonNull WifiConfiguration config) {
+ int index = mList.indexOf(ScanResultMatchInfo.fromWifiConfiguration(config));
+ // Not in the most recently connected list will return the MAX_INT
+ if (index < 0) {
+ return Integer.MAX_VALUE;
+ }
+ return index;
+ }
+}
diff --git a/service/java/com/android/server/wifi/util/LruList.java b/service/java/com/android/server/wifi/util/LruList.java
index 3be2357..69ed851 100644
--- a/service/java/com/android/server/wifi/util/LruList.java
+++ b/service/java/com/android/server/wifi/util/LruList.java
@@ -62,6 +62,20 @@
}
/**
+ * Remove an entry from list.
+ */
+ public void remove(@NonNull E entry) {
+ if (entry == null) {
+ return;
+ }
+ int index = mLinkedList.indexOf(entry);
+ if (index < 0) {
+ return;
+ }
+ mLinkedList.remove(index);
+ }
+
+ /**
* Returns the list of entries sorted by most recently added entries first.
* @return
*/
@@ -75,4 +89,13 @@
public int size() {
return mLinkedList.size();
}
+
+ /**
+ * Get the index in the list of the input entry.
+ * If not in the list will return -1.
+ * If in the list, smaller index is more recently added.
+ */
+ public int indexOf(E entry) {
+ return mLinkedList.indexOf(entry);
+ }
}
diff --git a/service/java/com/android/server/wifi/util/XmlUtil.java b/service/java/com/android/server/wifi/util/XmlUtil.java
index da22f8b..d20ee7e 100644
--- a/service/java/com/android/server/wifi/util/XmlUtil.java
+++ b/service/java/com/android/server/wifi/util/XmlUtil.java
@@ -355,6 +355,7 @@
public static final String XML_TAG_CARRIER_ID = "CarrierId";
public static final String XML_TAG_IS_AUTO_JOIN = "AutoJoinEnabled";
public static final String XML_TAG_IS_TRUSTED = "Trusted";
+ private static final String XML_TAG_IS_MOST_RECENTLY_CONNECTED = "IsMostRecentlyConnected";
/**
* Write WepKeys to the XML stream.
@@ -520,6 +521,8 @@
XmlUtil.writeNextValue(out, XML_TAG_MAC_RANDOMIZATION_SETTING,
configuration.macRandomizationSetting);
XmlUtil.writeNextValue(out, XML_TAG_CARRIER_ID, configuration.carrierId);
+ XmlUtil.writeNextValue(out, XML_TAG_IS_MOST_RECENTLY_CONNECTED,
+ configuration.isMostRecentlyConnected);
}
/**
@@ -713,6 +716,9 @@
case XML_TAG_IS_TRUSTED:
configuration.trusted = (boolean) value;
break;
+ case XML_TAG_IS_MOST_RECENTLY_CONNECTED:
+ configuration.isMostRecentlyConnected = (boolean) value;
+ break;
default:
Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]);
break;
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 76741b1..e51e640 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -369,6 +369,9 @@
<!-- Enable the PNO frequency culling optimization. -->
<bool translatable="false" name="config_wifiPnoRecencySortingEnabled">true</bool>
+ <!-- Maximum number of SSIDs that can be PNO scanned concurrently-->
+ <integer translatable="false" name="config_wifiMaxPnoSsidCount">16</integer>
+
<!-- Suspend optimization. -->
<bool translatable="false" name="config_wifiSuspendOptimizationsEnabled">true</bool>
diff --git a/service/res/values/overlayable.xml b/service/res/values/overlayable.xml
index ff73200..a6a37a3 100644
--- a/service/res/values/overlayable.xml
+++ b/service/res/values/overlayable.xml
@@ -117,6 +117,7 @@
<item type="bool" name="config_wifiLinkSpeedMetricsEnabled" />
<item type="bool" name="config_wifiPnoFrequencyCullingEnabled" />
<item type="bool" name="config_wifiPnoRecencySortingEnabled" />
+ <item type="integer" name="config_wifiMaxPnoSsidCount" />
<item type="bool" name="config_wifiSuspendOptimizationsEnabled" />
<item type="bool" name="config_wifiHighMovementNetworkSelectionOptimizationEnabled" />
<item type="integer" name="config_wifiHighMovementNetworkSelectionOptimizationScanDelayMs" />
diff --git a/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java
index 88bcc92..4e2eee4 100644
--- a/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java
@@ -106,6 +106,7 @@
+ "<string name=\"RandomizedMacAddress\">%s</string>\n"
+ "<int name=\"MacRandomizationSetting\" value=\"1\" />\n"
+ "<int name=\"CarrierId\" value=\"-1\" />\n"
+ + "<boolean name=\"IsMostRecentlyConnected\" value=\"false\" />\n"
+ "</WifiConfiguration>\n"
+ "<NetworkStatus>\n"
+ "<string name=\"SelectionStatus\">NETWORK_SELECTION_ENABLED</string>\n"
@@ -161,6 +162,7 @@
+ "<string name=\"RandomizedMacAddress\">%s</string>\n"
+ "<int name=\"MacRandomizationSetting\" value=\"1\" />\n"
+ "<int name=\"CarrierId\" value=\"-1\" />\n"
+ + "<boolean name=\"IsMostRecentlyConnected\" value=\"false\" />\n"
+ "</WifiConfiguration>\n"
+ "<NetworkStatus>\n"
+ "<string name=\"SelectionStatus\">NETWORK_SELECTION_ENABLED</string>\n"
@@ -237,6 +239,7 @@
+ "<string name=\"RandomizedMacAddress\">%s</string>\n"
+ "<int name=\"MacRandomizationSetting\" value=\"1\" />\n"
+ "<int name=\"CarrierId\" value=\"-1\" />\n"
+ + "<boolean name=\"IsMostRecentlyConnected\" value=\"false\" />\n"
+ "</WifiConfiguration>\n"
+ "<NetworkStatus>\n"
+ "<string name=\"SelectionStatus\">NETWORK_SELECTION_ENABLED</string>\n"
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index 244cad4..1147dd9 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -50,6 +50,7 @@
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.wifi.WifiScoreCard.PerNetwork;
+import com.android.server.wifi.util.LruConnectionTracker;
import com.android.server.wifi.util.TelephonyUtil;
import com.android.server.wifi.util.WifiPermissionsUtil;
import com.android.server.wifi.util.WifiPermissionsWrapper;
@@ -140,6 +141,7 @@
@Mock private WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
@Mock private WifiScoreCard mWifiScoreCard;
@Mock private PerNetwork mPerNetwork;
+ @Mock private LruConnectionTracker mLruConnectionTracker;
private MockResources mResources;
private InOrder mContextConfigStoreMockOrder;
@@ -150,6 +152,7 @@
private MockitoSession mSession;
private TelephonyUtil mTelephonyUtil;
+
/**
* Setup the mocks and an instance of WifiConfigManager before each test.
*/
@@ -4843,7 +4846,7 @@
mNetworkListSharedStoreData, mNetworkListUserStoreData,
mRandomizedMacStoreData,
mFrameworkFacade, new Handler(mLooper.getLooper()), mDeviceConfigFacade,
- mWifiScoreCard);
+ mWifiScoreCard, mLruConnectionTracker);
mWifiConfigManager.enableVerboseLogging(1);
}
@@ -5313,6 +5316,10 @@
// Verify if the config store write was triggered without this new configuration.
verifyNetworkNotInConfigStoreData(configuration);
verify(mBssidBlocklistMonitor, atLeastOnce()).handleNetworkRemoved(configuration.SSID);
+ ArgumentCaptor<WifiConfiguration> captor = ArgumentCaptor.forClass(WifiConfiguration.class);
+ verify(mLruConnectionTracker).removeNetwork(captor.capture());
+ assertEquals(configuration.networkId, captor.getValue().networkId);
+ reset(mLruConnectionTracker);
}
/**
@@ -5508,6 +5515,9 @@
WifiConfiguration retrievedNetwork = mWifiConfigManager.getConfiguredNetwork(networkId);
assertTrue("hasEverConnected expected to be true after connection.",
retrievedNetwork.getNetworkSelectionStatus().hasEverConnected());
+ ArgumentCaptor<WifiConfiguration> captor = ArgumentCaptor.forClass(WifiConfiguration.class);
+ verify(mLruConnectionTracker).addNetwork(captor.capture());
+ assertEquals(networkId, captor.getValue().networkId);
}
/**
@@ -5632,4 +5642,23 @@
assertEquals(mWifiConfigManager.findScanRssi(result.getNetworkId(), 5000),
WifiInfo.INVALID_RSSI);
}
+
+ /**
+ * Verify when save to store, isMostRecentlyConnected flag will be set.
+ */
+ @Test
+ public void testMostRecentlyConnectedNetwork() {
+ WifiConfiguration testNetwork1 = WifiConfigurationTestUtil.createOpenNetwork();
+ verifyAddNetworkToWifiConfigManager(testNetwork1);
+ WifiConfiguration testNetwork2 = WifiConfigurationTestUtil.createOpenNetwork();
+ verifyAddNetworkToWifiConfigManager(testNetwork2);
+ when(mLruConnectionTracker.isMostRecentlyConnected(any()))
+ .thenReturn(false).thenReturn(true);
+ mWifiConfigManager.saveToStore(true);
+ Pair<List<WifiConfiguration>, List<WifiConfiguration>> networkStoreData =
+ captureWriteNetworksListStoreData();
+ List<WifiConfiguration> sharedNetwork = networkStoreData.first;
+ assertFalse(sharedNetwork.get(0).isMostRecentlyConnected);
+ assertTrue(sharedNetwork.get(1).isMostRecentlyConnected);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
index ca36873..8341654 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
@@ -118,6 +118,7 @@
+ "<string name=\"RandomizedMacAddress\">%s</string>\n"
+ "<int name=\"MacRandomizationSetting\" value=\"1\" />\n"
+ "<int name=\"CarrierId\" value=\"-1\" />\n"
+ + "<boolean name=\"IsMostRecentlyConnected\" value=\"false\" />\n"
+ "</WifiConfiguration>\n"
+ "<NetworkStatus>\n"
+ "<string name=\"SelectionStatus\">NETWORK_SELECTION_ENABLED</string>\n"
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
index 0ec2eb9..f26ceb6 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
@@ -77,6 +77,7 @@
import com.android.server.wifi.WifiNetworkSuggestionsManager.ExtendedWifiNetworkSuggestion;
import com.android.server.wifi.WifiNetworkSuggestionsManager.PerAppInfo;
import com.android.server.wifi.hotspot2.PasspointManager;
+import com.android.server.wifi.util.LruConnectionTracker;
import com.android.server.wifi.util.TelephonyUtil;
import com.android.server.wifi.util.WifiPermissionsUtil;
import com.android.wifi.resources.R;
@@ -91,6 +92,7 @@
import org.mockito.quality.Strictness;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -146,6 +148,7 @@
private @Mock AlertDialog mAlertDialog;
private @Mock Notification.Builder mNotificationBuilder;
private @Mock Notification mNotification;
+ private @Mock LruConnectionTracker mLruConnectionTracker;
private TestLooper mLooper;
private ArgumentCaptor<AppOpsManager.OnOpChangedListener> mAppOpChangedListenerCaptor =
ArgumentCaptor.forClass(AppOpsManager.OnOpChangedListener.class);
@@ -266,7 +269,7 @@
mWifiNetworkSuggestionsManager =
new WifiNetworkSuggestionsManager(mContext, new Handler(mLooper.getLooper()),
mWifiInjector, mWifiPermissionsUtil, mWifiConfigManager, mWifiConfigStore,
- mWifiMetrics, mTelephonyUtil, mWifiKeyStore);
+ mWifiMetrics, mTelephonyUtil, mWifiKeyStore, mLruConnectionTracker);
verify(mContext).getResources();
verify(mContext).getSystemService(Context.APP_OPS_SERVICE);
verify(mContext).getSystemService(Context.NOTIFICATION_SERVICE);
@@ -382,6 +385,7 @@
verify(mPasspointManager).removeProvider(eq(TEST_UID_2), eq(false),
eq(passpointConfiguration.getUniqueId()), isNull());
verify(mWifiScoreCard).removeNetwork(anyString());
+ verify(mLruConnectionTracker).removeNetwork(any());
assertTrue(mWifiNetworkSuggestionsManager.getAllNetworkSuggestions().isEmpty());
@@ -426,6 +430,7 @@
TEST_UID_1, TEST_PACKAGE_1));
// Make sure remove the keyStore with the internal config
verify(mWifiKeyStore).removeKeys(networkSuggestion1.wifiConfiguration.enterpriseConfig);
+ verify(mLruConnectionTracker).removeNetwork(any());
}
/**
@@ -464,6 +469,7 @@
assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
mWifiNetworkSuggestionsManager.remove(new ArrayList<>(), TEST_UID_1,
TEST_PACKAGE_1));
+ verify(mLruConnectionTracker).removeNetwork(any());
assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
mWifiNetworkSuggestionsManager.remove(new ArrayList<>(), TEST_UID_2,
TEST_PACKAGE_2));
@@ -3588,6 +3594,37 @@
}
/**
+ * Verify if a suggestion is mostRecently connected, flag will be persist.
+ */
+ @Test
+ public void testIsMostRecentlyConnectedSuggestion() {
+ WifiConfiguration network = WifiConfigurationTestUtil.createOpenNetwork();
+ WifiNetworkSuggestion networkSuggestion =
+ new WifiNetworkSuggestion(network, null, false, false, true, true);
+ List<WifiNetworkSuggestion> networkSuggestionList = Arrays.asList(networkSuggestion);
+ assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+ mWifiNetworkSuggestionsManager
+ .add(networkSuggestionList, TEST_UID_1, TEST_PACKAGE_1, TEST_FEATURE));
+ mWifiNetworkSuggestionsManager.setHasUserApprovedForApp(true, TEST_PACKAGE_1);
+ when(mLruConnectionTracker.isMostRecentlyConnected(any())).thenReturn(true);
+ Map<String, PerAppInfo> suggestionStore = mDataSource.toSerialize();
+ PerAppInfo perAppInfo = suggestionStore.get(TEST_PACKAGE_1);
+ ExtendedWifiNetworkSuggestion ewns = perAppInfo.extNetworkSuggestions.iterator().next();
+ assertTrue(ewns.wns.wifiConfiguration.isMostRecentlyConnected);
+ mDataSource.fromDeserialized(suggestionStore);
+ verify(mLruConnectionTracker).addNetwork(any());
+ reset(mLruConnectionTracker);
+
+ when(mLruConnectionTracker.isMostRecentlyConnected(any())).thenReturn(false);
+ suggestionStore = mDataSource.toSerialize();
+ perAppInfo = suggestionStore.get(TEST_PACKAGE_1);
+ ewns = perAppInfo.extNetworkSuggestions.iterator().next();
+ assertFalse(ewns.wns.wifiConfiguration.isMostRecentlyConnected);
+ mDataSource.fromDeserialized(suggestionStore);
+ verify(mLruConnectionTracker, never()).addNetwork(any());
+ }
+
+ /**
* Helper function for creating a test configuration with user credential.
*
* @return {@link PasspointConfiguration}
diff --git a/tests/wifitests/src/com/android/server/wifi/util/LruConnectionTrackerTest.java b/tests/wifitests/src/com/android/server/wifi/util/LruConnectionTrackerTest.java
new file mode 100644
index 0000000..eb5ae5b
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/util/LruConnectionTrackerTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.util;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.wifi.MockResources;
+import com.android.server.wifi.WifiConfigurationTestUtil;
+import com.android.wifi.resources.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class LruConnectionTrackerTest {
+ private static final int TEST_MAX_SIZE = 4;
+ private LruConnectionTracker mList;
+ private MockResources mResources;
+
+ @Mock private Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mResources = new MockResources();
+ mResources.setInteger(R.integer.config_wifiMaxPnoSsidCount, TEST_MAX_SIZE - 1);
+ when(mContext.getResources()).thenReturn(mResources);
+ mList = new LruConnectionTracker(TEST_MAX_SIZE, mContext);
+ }
+
+ @Test
+ public void testAddRemoveNetwork() {
+ WifiConfiguration network = WifiConfigurationTestUtil.createOpenNetwork();
+ assertEquals(Integer.MAX_VALUE, mList.getAgeIndexOfNetwork(network));
+ mList.addNetwork(network);
+ assertEquals(0, mList.getAgeIndexOfNetwork(network));
+ mList.removeNetwork(network);
+ assertEquals(Integer.MAX_VALUE, mList.getAgeIndexOfNetwork(network));
+ }
+
+ @Test
+ public void testConnectionOrderStore() {
+ WifiConfiguration network1 = WifiConfigurationTestUtil.createOpenNetwork();
+ WifiConfiguration network2 = WifiConfigurationTestUtil.createOpenNetwork();
+ WifiConfiguration network3 = WifiConfigurationTestUtil.createOpenNetwork();
+ WifiConfiguration network4 = WifiConfigurationTestUtil.createOpenNetwork();
+ WifiConfiguration network5 = WifiConfigurationTestUtil.createOpenNetwork();
+ mList.addNetwork(network1);
+ mList.addNetwork(network2);
+ mList.addNetwork(network3);
+ mList.addNetwork(network4);
+ // Expect reverse order of the added order
+ assertEquals(0, mList.getAgeIndexOfNetwork(network4));
+ assertEquals(1, mList.getAgeIndexOfNetwork(network3));
+ assertEquals(2, mList.getAgeIndexOfNetwork(network2));
+ assertEquals(3, mList.getAgeIndexOfNetwork(network1));
+ // Exceed the size of the list, should remove the oldest one.
+ mList.addNetwork(network5);
+ assertEquals(Integer.MAX_VALUE, mList.getAgeIndexOfNetwork(network1));
+ assertEquals(0, mList.getAgeIndexOfNetwork(network5));
+ // Add one already in the list, move it to the head of the list.
+ mList.addNetwork(network3);
+ assertEquals(0, mList.getAgeIndexOfNetwork(network3));
+ assertEquals(1, mList.getAgeIndexOfNetwork(network5));
+ assertEquals(2, mList.getAgeIndexOfNetwork(network4));
+ assertEquals(3, mList.getAgeIndexOfNetwork(network2));
+ }
+
+ @Test
+ public void testIsMostRecentlyNetwork() {
+ WifiConfiguration network1 = WifiConfigurationTestUtil.createOpenNetwork();
+ WifiConfiguration network2 = WifiConfigurationTestUtil.createOpenNetwork();
+ WifiConfiguration network3 = WifiConfigurationTestUtil.createOpenNetwork();
+ WifiConfiguration network4 = WifiConfigurationTestUtil.createOpenNetwork();
+ mList.addNetwork(network1);
+ mList.addNetwork(network2);
+ mList.addNetwork(network3);
+ assertTrue(mList.isMostRecentlyConnected(network1));
+ assertTrue(mList.isMostRecentlyConnected(network2));
+ assertTrue(mList.isMostRecentlyConnected(network3));
+ assertFalse(mList.isMostRecentlyConnected(network4));
+ // network in the list is more than the threshold, will mark the oldest false.
+ mList.addNetwork(network4);
+ assertFalse(mList.isMostRecentlyConnected(network1));
+ assertTrue(mList.isMostRecentlyConnected(network4));
+ // Add network in the list and which is true. Should not change other network flag.
+ mList.addNetwork(network2);
+ assertFalse(mList.isMostRecentlyConnected(network1));
+ assertTrue(mList.isMostRecentlyConnected(network2));
+ assertTrue(mList.isMostRecentlyConnected(network3));
+ assertTrue(mList.isMostRecentlyConnected(network4));
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/util/LruListTest.java b/tests/wifitests/src/com/android/server/wifi/util/LruListTest.java
index 27cb4e7..00122b1 100644
--- a/tests/wifitests/src/com/android/server/wifi/util/LruListTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/util/LruListTest.java
@@ -66,4 +66,30 @@
mLruList.add(null);
assertEquals(0, mLruList.size());
}
+
+ @Test
+ public void getIndex() {
+ for (int i = 0; i < TEST_MAX_SIZE; i++) {
+ mLruList.add(i);
+ }
+ for (int i = 0; i < TEST_MAX_SIZE; i++) {
+ assertEquals(i, mLruList.indexOf(TEST_MAX_SIZE - i - 1));
+ }
+ // Verify not in the list will return -1.
+ assertEquals(-1, mLruList.indexOf(3));
+ mLruList.add(3);
+ // Verify add more elements more than list size, will remove oldest one.
+ assertEquals(0, mLruList.indexOf(3));
+ assertEquals(-1, mLruList.indexOf(0));
+ // Verify add an element in the list will make it the most recently one.
+ mLruList.add(1);
+ assertEquals(0, mLruList.indexOf(1));
+ assertEquals(1, mLruList.indexOf(3));
+ assertEquals(2, mLruList.indexOf(2));
+ // Verify remove one element in the list, all element behind it index should decrease 1.
+ mLruList.remove(1);
+ assertEquals(-1, mLruList.indexOf(1));
+ assertEquals(0, mLruList.indexOf(3));
+ assertEquals(1, mLruList.indexOf(2));
+ }
}