summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Schwarzenbach <easchwar@google.com>2018-03-13 12:38:08 -0700
committerEric Schwarzenbach <easchwar@google.com>2018-03-29 16:24:12 -0700
commit4f894bd0f4b378972d10f64390ab710da54d5cc6 (patch)
tree2482114a6ab1887e5d27d699cd1d9409344e660a
parent9adae7cd853e952b4528d6faa874556772ba3b4d (diff)
Fix WifiWake locking behavior.
To prevent a single non-representative scan from determining the state of the WakeupLock, we no longer initialize the lock with solely the results from WifiScanner.getSingleScanResults(). Instead, we iteratively build the lock up over 3 scans (capped by a timeout). The WakeupLock is now responsible for determining whether to add or remove the networks from the lock based on its initialization state (see WakeupLock#update()). All DFS channels are excluded from consideration for both locking and waking. The initialization state is not persisted to the StoreData, but rather any loaded StoreData is assumed to be initialized. Bug: 74259229 Test: runtest, manual Change-Id: I062f000546079dee1be1aa565a515237ab0c745f
-rw-r--r--service/java/com/android/server/wifi/WakeupController.java102
-rw-r--r--service/java/com/android/server/wifi/WakeupLock.java171
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java3
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java102
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java135
5 files changed, 390 insertions, 123 deletions
diff --git a/service/java/com/android/server/wifi/WakeupController.java b/service/java/com/android/server/wifi/WakeupController.java
index 9743390ed..97919ca72 100644
--- a/service/java/com/android/server/wifi/WakeupController.java
+++ b/service/java/com/android/server/wifi/WakeupController.java
@@ -26,7 +26,6 @@ import android.net.wifi.WifiScanner;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
-import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -38,6 +37,7 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
/**
@@ -175,17 +175,16 @@ public class WakeupController {
if (isEnabled()) {
mWakeupOnboarding.maybeShowNotification();
- Set<ScanResultMatchInfo> mostRecentSavedScanResults = getMostRecentSavedScanResults();
-
+ Set<ScanResultMatchInfo> savedNetworksFromLatestScan = getSavedNetworksFromLatestScan();
if (mVerboseLoggingEnabled) {
- Log.d(TAG, "Saved networks in most recent scan:" + mostRecentSavedScanResults);
+ Log.d(TAG, "Saved networks in most recent scan:" + savedNetworksFromLatestScan);
}
- mWifiWakeMetrics.recordStartEvent(mostRecentSavedScanResults.size());
- mWakeupLock.initialize(mostRecentSavedScanResults);
+ mWifiWakeMetrics.recordStartEvent(savedNetworksFromLatestScan.size());
+ mWakeupLock.setLock(savedNetworksFromLatestScan);
+ // TODO(b/77291248): request low latency scan here
}
}
-
/**
* Stops listening for scans.
*
@@ -212,18 +211,30 @@ public class WakeupController {
mWakeupLock.enableVerboseLogging(mVerboseLoggingEnabled);
}
- /** Returns a list of saved networks from the last full scan. */
- private Set<ScanResultMatchInfo> getMostRecentSavedScanResults() {
- Set<ScanResultMatchInfo> goodSavedNetworks = getGoodSavedNetworks();
+ /** Returns a filtered list of saved networks from the last full scan. */
+ private Set<ScanResultMatchInfo> getSavedNetworksFromLatestScan() {
+ Set<ScanResult> filteredScanResults =
+ filterScanResults(mWifiInjector.getWifiScanner().getSingleScanResults());
+ Set<ScanResultMatchInfo> goodMatchInfos = toMatchInfos(filteredScanResults);
+ goodMatchInfos.retainAll(getGoodSavedNetworks());
+
+ return goodMatchInfos;
+ }
- List<ScanResult> scanResults = mWifiInjector.getWifiScanner().getSingleScanResults();
- Set<ScanResultMatchInfo> lastSeenNetworks = new HashSet<>(scanResults.size());
- for (ScanResult scanResult : scanResults) {
- lastSeenNetworks.add(ScanResultMatchInfo.fromScanResult(scanResult));
+ /** Returns a set of ScanResults with all DFS channels removed. */
+ private Set<ScanResult> filterScanResults(Collection<ScanResult> scanResults) {
+ int[] dfsChannels = mWifiInjector.getWifiNative()
+ .getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY);
+ if (dfsChannels == null) {
+ dfsChannels = new int[0];
}
- lastSeenNetworks.retainAll(goodSavedNetworks);
- return lastSeenNetworks;
+ final Set<Integer> dfsChannelSet = Arrays.stream(dfsChannels).boxed()
+ .collect(Collectors.toSet());
+
+ return scanResults.stream()
+ .filter(scanResult -> !dfsChannelSet.contains(scanResult.frequency))
+ .collect(Collectors.toSet());
}
/** Returns a filtered list of saved networks from WifiConfigManager. */
@@ -245,16 +256,18 @@ public class WakeupController {
}
//TODO(b/69271702) implement WAN filtering
- private boolean isWideAreaNetwork(WifiConfiguration wifiConfiguration) {
+ private static boolean isWideAreaNetwork(WifiConfiguration config) {
return false;
}
/**
* Handles incoming scan results.
*
- * <p>The controller updates the WakeupLock with the incoming scan results. If WakeupLock is
- * empty, it evaluates scan results for a match with saved networks. If a match exists, it
- * enables wifi.
+ * <p>The controller updates the WakeupLock with the incoming scan results. If WakeupLock is not
+ * yet fully initialized, it adds the current scanResults to the lock and returns. If WakeupLock
+ * is initialized but not empty, the controller updates the lock with the current scan. If it is
+ * both initialized and empty, it evaluates scan results for a match with saved networks. If a
+ * match exists, it enables wifi.
*
* <p>The feature must be enabled and the store data must be loaded in order for the controller
* to handle scan results.
@@ -267,43 +280,31 @@ public class WakeupController {
return;
}
- // only count scan as handled if isEnabled
- mNumScansHandled++;
-
- if (mVerboseLoggingEnabled) {
- Log.d(TAG, "Incoming scan. Total scans handled: " + mNumScansHandled);
- Log.d(TAG, "ScanResults: " + scanResults);
- }
+ Set<ScanResult> filteredScanResults = filterScanResults(scanResults);
// need to show notification here in case user enables Wifi Wake when Wifi is off
+ // TODO(b/72399908) make onboarding not blocking
mWakeupOnboarding.maybeShowNotification();
if (!mWakeupOnboarding.isOnboarded()) {
- return;
- }
-
- // only update the wakeup lock if it's not already empty
- if (!mWakeupLock.isEmpty()) {
if (mVerboseLoggingEnabled) {
- Log.d(TAG, "WakeupLock not empty. Updating.");
+ Log.d(TAG, "handleScanResults: Scan not handled because user is not onboarded.");
}
+ return;
+ }
- Set<ScanResultMatchInfo> networks = new ArraySet<>();
- for (ScanResult scanResult : scanResults) {
- networks.add(ScanResultMatchInfo.fromScanResult(scanResult));
- }
- mWakeupLock.update(networks);
-
- // if wakeup lock is still not empty, return
- if (!mWakeupLock.isEmpty()) {
- return;
- }
+ // only count scan as handled if isEnabled and user onboarded
+ mNumScansHandled++;
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Incoming scan #" + mNumScansHandled);
+ }
- Log.d(TAG, "WakeupLock emptied");
- mWifiWakeMetrics.recordUnlockEvent(mNumScansHandled);
+ mWakeupLock.update(toMatchInfos(filteredScanResults));
+ if (!mWakeupLock.isUnlocked()) {
+ return;
}
ScanResult network =
- mWakeupEvaluator.findViableNetwork(scanResults, getGoodSavedNetworks());
+ mWakeupEvaluator.findViableNetwork(filteredScanResults, getGoodSavedNetworks());
if (network != null) {
Log.d(TAG, "Enabling wifi for network: " + network.SSID);
@@ -312,6 +313,15 @@ public class WakeupController {
}
/**
+ * Converts ScanResults to ScanResultMatchInfos.
+ */
+ private static Set<ScanResultMatchInfo> toMatchInfos(Collection<ScanResult> scanResults) {
+ return scanResults.stream()
+ .map(ScanResultMatchInfo::fromScanResult)
+ .collect(Collectors.toSet());
+ }
+
+ /**
* Enables wifi.
*
* <p>This method ignores all checks and assumes that {@link WifiStateMachine} is currently
diff --git a/service/java/com/android/server/wifi/WakeupLock.java b/service/java/com/android/server/wifi/WakeupLock.java
index 9e617a498..8a7422f46 100644
--- a/service/java/com/android/server/wifi/WakeupLock.java
+++ b/service/java/com/android/server/wifi/WakeupLock.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -29,7 +30,7 @@ import java.util.Map;
import java.util.Set;
/**
- * A lock to determine whether Auto Wifi can re-enable Wifi.
+ * A lock to determine whether Wifi Wake can re-enable Wifi.
*
* <p>Wakeuplock manages a list of networks to determine whether the device's location has changed.
*/
@@ -39,44 +40,144 @@ public class WakeupLock {
@VisibleForTesting
static final int CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT = 3;
-
+ @VisibleForTesting
+ static final long MAX_LOCK_TIME_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
private final WifiConfigManager mWifiConfigManager;
private final Map<ScanResultMatchInfo, Integer> mLockedNetworks = new ArrayMap<>();
+ private final WifiWakeMetrics mWifiWakeMetrics;
+ private final Clock mClock;
+
private boolean mVerboseLoggingEnabled;
+ private long mLockTimestamp;
+ private boolean mIsInitialized;
+ private int mNumScans;
- public WakeupLock(WifiConfigManager wifiConfigManager) {
+ public WakeupLock(WifiConfigManager wifiConfigManager, WifiWakeMetrics wifiWakeMetrics,
+ Clock clock) {
mWifiConfigManager = wifiConfigManager;
+ mWifiWakeMetrics = wifiWakeMetrics;
+ mClock = clock;
}
/**
- * Initializes the WakeupLock with the given {@link ScanResultMatchInfo} list.
+ * Sets the WakeupLock with the given {@link ScanResultMatchInfo} list.
*
- * <p>This saves the wakeup lock to the store.
+ * <p>This saves the wakeup lock to the store and begins the initialization process.
*
* @param scanResultList list of ScanResultMatchInfos to start the lock with
*/
- public void initialize(Collection<ScanResultMatchInfo> scanResultList) {
+ public void setLock(Collection<ScanResultMatchInfo> scanResultList) {
+ mLockTimestamp = mClock.getElapsedSinceBootMillis();
+ mIsInitialized = false;
+ mNumScans = 0;
+
mLockedNetworks.clear();
for (ScanResultMatchInfo scanResultMatchInfo : scanResultList) {
mLockedNetworks.put(scanResultMatchInfo, CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT);
}
- Log.d(TAG, "Lock initialized. Number of networks: " + mLockedNetworks.size());
+ Log.d(TAG, "Lock set. Number of networks: " + mLockedNetworks.size());
mWifiConfigManager.saveToStore(false /* forceWrite */);
}
/**
- * Updates the lock with the given {@link ScanResultMatchInfo} list.
+ * Maybe sets the WakeupLock as initialized based on total scans handled.
+ *
+ * @param numScans total number of elapsed scans in the current WifiWake session
+ * @return Whether the lock transitioned into its initialized state.
+ */
+ private boolean maybeSetInitializedByScans(int numScans) {
+ if (mIsInitialized) {
+ return false;
+ }
+ boolean shouldBeInitialized = numScans >= CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT;
+ if (shouldBeInitialized) {
+ mIsInitialized = true;
+
+ Log.d(TAG, "Lock initialized by handled scans. Scans: " + numScans);
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "State of lock: " + mLockedNetworks);
+ }
+ }
+ return mIsInitialized;
+ }
+
+ /**
+ * Maybe sets the WakeupLock as initialized based on elapsed time.
+ *
+ * @param timestampMillis current timestamp
+ * @return Whether the lock transitioned into its initialized state.
+ */
+ private boolean maybeSetInitializedByTimeout(long timestampMillis) {
+ if (mIsInitialized) {
+ return false;
+ }
+ long elapsedTime = timestampMillis - mLockTimestamp;
+ boolean shouldBeInitialized = elapsedTime > MAX_LOCK_TIME_MILLIS;
+
+ if (shouldBeInitialized) {
+ mIsInitialized = true;
+
+ Log.d(TAG, "Lock initialized by timeout. Elapsed time: " + elapsedTime);
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "State of lock: " + mLockedNetworks);
+ }
+ }
+ return mIsInitialized;
+ }
+
+ /** Returns whether the lock has been fully initialized. */
+ public boolean isInitialized() {
+ return mIsInitialized;
+ }
+
+ /**
+ * Adds the given networks to the lock.
+ *
+ * <p>This is called during the initialization step.
+ *
+ * @param networkList The list of networks to be added
+ */
+ private void addToLock(Collection<ScanResultMatchInfo> networkList) {
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Initializing lock with networks: " + networkList);
+ }
+
+ boolean hasChanged = false;
+
+ for (ScanResultMatchInfo network : networkList) {
+ if (!mLockedNetworks.containsKey(network)) {
+ mLockedNetworks.put(network, CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT);
+ hasChanged = true;
+ }
+ }
+
+ if (hasChanged) {
+ mWifiConfigManager.saveToStore(false /* forceWrite */);
+ }
+
+ // Set initialized if the lock has handled enough scans, and log the event
+ if (maybeSetInitializedByScans(mNumScans)) {
+ // TODO(easchwar) log metric
+ }
+ }
+
+ /**
+ * Removes networks from the lock if not present in the given {@link ScanResultMatchInfo} list.
*
* <p>If a network in the lock is not present in the list, reduce the number of scans
* required to evict by one. Remove any entries in the list with 0 scans required to evict. If
* any entries in the lock are removed, the store is updated.
*
- * @param scanResultList list of present ScanResultMatchInfos to update the lock with
+ * @param networkList list of present ScanResultMatchInfos to update the lock with
*/
- public void update(Collection<ScanResultMatchInfo> scanResultList) {
+ private void removeFromLock(Collection<ScanResultMatchInfo> networkList) {
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Filtering lock with networks: " + networkList);
+ }
+
boolean hasChanged = false;
Iterator<Map.Entry<ScanResultMatchInfo, Integer>> it =
mLockedNetworks.entrySet().iterator();
@@ -84,7 +185,7 @@ public class WakeupLock {
Map.Entry<ScanResultMatchInfo, Integer> entry = it.next();
// if present in scan list, reset to max
- if (scanResultList.contains(entry.getKey())) {
+ if (networkList.contains(entry.getKey())) {
if (mVerboseLoggingEnabled) {
Log.d(TAG, "Found network in lock: " + entry.getKey().networkSsid);
}
@@ -104,13 +205,50 @@ public class WakeupLock {
if (hasChanged) {
mWifiConfigManager.saveToStore(false /* forceWrite */);
}
+
+ if (isUnlocked()) {
+ Log.d(TAG, "Lock emptied. Recording unlock event.");
+ mWifiWakeMetrics.recordUnlockEvent(mNumScans);
+ }
}
/**
- * Returns whether the internal network set is empty.
+ * Updates the lock with the given {@link ScanResultMatchInfo} list.
+ *
+ * <p>Based on the current initialization state of the lock, either adds or removes networks
+ * from the lock.
+ *
+ * <p>The lock is initialized after {@link #CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT}
+ * scans have been handled, or after {@link #MAX_LOCK_TIME_MILLIS} milliseconds have elapsed
+ * since {@link #setLock(Collection, long)}.
+ *
+ * @param networkList list of present ScanResultMatchInfos to update the lock with
*/
- public boolean isEmpty() {
- return mLockedNetworks.isEmpty();
+ public void update(Collection<ScanResultMatchInfo> networkList) {
+ // update is no-op if already unlocked
+ if (isUnlocked()) {
+ return;
+ }
+ mNumScans++;
+
+ // Before checking mIsInitialized, we check to see whether we've exceeded the maximum time
+ // allowed for initialization. If so, we set initialized and treat this scan as a
+ // "removeFromLock()" instead of an "addToLock()".
+ if (maybeSetInitializedByTimeout(mClock.getElapsedSinceBootMillis())) {
+ // TODO(easchwar) log metric
+ }
+
+ // add or remove networks based on initialized status
+ if (mIsInitialized) {
+ removeFromLock(networkList);
+ } else {
+ addToLock(networkList);
+ }
+ }
+
+ /** Returns whether the WakeupLock is unlocked */
+ public boolean isUnlocked() {
+ return mIsInitialized && mLockedNetworks.isEmpty();
}
/** Returns the data source for the WakeupLock config store data. */
@@ -121,6 +259,8 @@ public class WakeupLock {
/** Dumps wakeup lock contents. */
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("WakeupLock: ");
+ pw.println("mNumScans: " + mNumScans);
+ pw.println("mIsInitialized: " + mIsInitialized);
pw.println("Locked networks: " + mLockedNetworks.size());
for (Map.Entry<ScanResultMatchInfo, Integer> entry : mLockedNetworks.entrySet()) {
pw.println(entry.getKey() + ", scans to evict: " + entry.getValue());
@@ -146,7 +286,8 @@ public class WakeupLock {
for (ScanResultMatchInfo network : data) {
mLockedNetworks.put(network, CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT);
}
-
+ // lock is considered initialized if loaded from store
+ mIsInitialized = true;
}
}
}
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 4313ff4cf..6d15e87f7 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -272,7 +272,8 @@ public class WifiInjector {
mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade,
wakeupNotificationFactory);
mWakeupController = new WakeupController(mContext,
- mWifiStateMachineHandlerThread.getLooper(), new WakeupLock(mWifiConfigManager),
+ mWifiStateMachineHandlerThread.getLooper(),
+ new WakeupLock(mWifiConfigManager, mWifiMetrics.getWakeupMetrics(), mClock),
WakeupEvaluator.fromContext(mContext), wakeupOnboarding, mWifiConfigManager,
mWifiConfigStore, mWifiMetrics.getWakeupMetrics(), this, mFrameworkFacade);
mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService());
diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
index f246c4884..3c7517bf3 100644
--- a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
@@ -23,7 +23,6 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -49,14 +48,16 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
+import java.util.Set;
/**
* Unit tests for {@link WakeupController}.
*/
public class WakeupControllerTest {
+ private static final int DFS_CHANNEL = 5540;
+
@Mock private Context mContext;
@Mock private WakeupLock mWakeupLock;
@Mock private WakeupEvaluator mWakeupEvaluator;
@@ -69,6 +70,7 @@ public class WakeupControllerTest {
@Mock private WifiSettingsStore mWifiSettingsStore;
@Mock private WifiWakeMetrics mWifiWakeMetrics;
@Mock private WifiController mWifiController;
+ @Mock private WifiNative mWifiNative;
private TestLooper mLooper;
private WakeupController mWakeupController;
@@ -84,6 +86,10 @@ public class WakeupControllerTest {
when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner);
when(mWifiInjector.getWifiSettingsStore()).thenReturn(mWifiSettingsStore);
when(mWifiInjector.getWifiController()).thenReturn(mWifiController);
+ when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative);
+ when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY))
+ .thenReturn(new int[]{DFS_CHANNEL});
+
when(mWifiSettingsStore.handleWifiToggled(anyBoolean())).thenReturn(true);
mLooper = new TestLooper();
@@ -92,6 +98,7 @@ public class WakeupControllerTest {
mTestScanResult = new ScanResult();
mTestScanResult.SSID = "open ssid 1";
mTestScanResult.capabilities = "";
+ mTestScanResult.frequency = 2412;
ScanResult[] scanResults = new ScanResult[1];
scanResults[0] = mTestScanResult;
mTestScanDatas = new WifiScanner.ScanData[1];
@@ -191,43 +198,43 @@ public class WakeupControllerTest {
}
/**
- * Verify that start initializes the wakeup lock.
+ * Verify that start sets the wakeup lock.
*/
@Test
- public void startInitializesWakeupLock() {
+ public void startSetsWakeupLock() {
initializeWakeupController(true /* enabled */);
mWakeupController.start();
- verify(mWakeupLock).initialize(any());
+ verify(mWakeupLock).setLock(any());
verify(mWifiWakeMetrics).recordStartEvent(anyInt());
}
/**
- * Verify that start does not initialize the wakeup lock when feature is disabled.
+ * Verify that start does not set the wakeup lock when feature is disabled.
*/
@Test
- public void startDoesNotInitializeWakeupLockWhenDisabled() {
+ public void startDoesNotSetWakeupLockWhenDisabled() {
initializeWakeupController(false /* enabled */);
mWakeupController.start();
- verify(mWakeupLock, never()).initialize(any());
+ verify(mWakeupLock, never()).setLock(any());
verify(mWifiWakeMetrics, never()).recordStartEvent(anyInt());
}
/**
- * Verify that start does not re-initialize the wakeup lock if the controller is already active.
+ * Verify that start does not set the wakeup lock if the controller is already active.
*/
@Test
- public void startDoesNotInitializeWakeupLockIfAlreadyActive() {
+ public void startDoesNotSetWakeupLockIfAlreadyActive() {
initializeWakeupController(true /* enabled */);
InOrder lockInOrder = Mockito.inOrder(mWakeupLock);
InOrder metricsInOrder = Mockito.inOrder(mWifiWakeMetrics);
mWakeupController.start();
- lockInOrder.verify(mWakeupLock).initialize(any());
+ lockInOrder.verify(mWakeupLock).setLock(any());
metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt());
mWakeupController.stop();
mWakeupController.start();
- lockInOrder.verify(mWakeupLock, never()).initialize(any());
+ lockInOrder.verify(mWakeupLock, never()).setLock(any());
metricsInOrder.verify(mWifiWakeMetrics, never()).recordStartEvent(anyInt());
}
@@ -256,7 +263,7 @@ public class WakeupControllerTest {
* Verify that reset sets active to false.
*
* <p>This is accomplished by initiating another call to start and verifying that the wakeup
- * lock is re-initialized.
+ * lock is re-set.
*/
@Test
public void resetSetsActiveToFalse() {
@@ -265,7 +272,7 @@ public class WakeupControllerTest {
InOrder metricsInOrder = Mockito.inOrder(mWifiWakeMetrics);
mWakeupController.start();
- lockInOrder.verify(mWakeupLock).initialize(any());
+ lockInOrder.verify(mWakeupLock).setLock(any());
metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt());
mWakeupController.stop();
@@ -273,7 +280,7 @@ public class WakeupControllerTest {
metricsInOrder.verify(mWifiWakeMetrics).recordResetEvent(0 /* numScans */);
mWakeupController.start();
- lockInOrder.verify(mWakeupLock).initialize(any());
+ lockInOrder.verify(mWakeupLock).setLock(any());
metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt());
}
@@ -297,17 +304,49 @@ public class WakeupControllerTest {
// scan results from most recent scan
ScanResult savedScanResult = createOpenScanResult(ssid1);
+ savedScanResult.frequency = 2412;
ScanResult unsavedScanResult = createOpenScanResult(ssid2);
+ savedScanResult.frequency = 2412;
+
when(mWifiScanner.getSingleScanResults())
.thenReturn(Arrays.asList(savedScanResult, unsavedScanResult));
// intersection of most recent scan + saved configs
- Collection<ScanResultMatchInfo> expectedMatchInfos =
+ Set<ScanResultMatchInfo> expectedMatchInfos =
Collections.singleton(ScanResultMatchInfo.fromScanResult(savedScanResult));
initializeWakeupController(true /* enabled */);
mWakeupController.start();
- verify(mWakeupLock).initialize(eq(expectedMatchInfos));
+ verify(mWakeupLock).setLock(eq(expectedMatchInfos));
+ verify(mWifiWakeMetrics).recordStartEvent(expectedMatchInfos.size());
+ }
+
+ /**
+ * Verify that start filters out DFS channels.
+ */
+ @Test
+ public void startFiltersOutDfsScanResults() {
+ String ssid = "test_ssid";
+ String quotedSsid = ScanResultUtil.createQuotedSSID(ssid);
+
+ // saved config
+ WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(quotedSsid);
+ openNetwork.getNetworkSelectionStatus().setHasEverConnected(true);
+ when(mWifiConfigManager.getSavedNetworks())
+ .thenReturn(Collections.singletonList(openNetwork));
+
+ // scan result from most recent scan
+ ScanResult scanResult = createOpenScanResult(ssid);
+ scanResult.frequency = DFS_CHANNEL;
+
+ when(mWifiScanner.getSingleScanResults()).thenReturn(Collections.singletonList(scanResult));
+
+ // intersection of most recent scan + saved configs
+ Set<ScanResultMatchInfo> expectedMatchInfos = Collections.emptySet();
+
+ initializeWakeupController(true /* enabled */);
+ mWakeupController.start();
+ verify(mWakeupLock).setLock(eq(expectedMatchInfos));
verify(mWifiWakeMetrics).recordStartEvent(expectedMatchInfos.size());
}
@@ -333,16 +372,13 @@ public class WakeupControllerTest {
}
/**
- * Verify that WifiWakeMetrics logs the unlock event when the WakeupLock is emptied.
+ * Verify that onResults filters out DFS channels.
*/
@Test
- public void recordMetricsWhenWakeupLockIsEmptied() {
+ public void onResultsFiltersOutDfsScanResults() {
initializeWakeupController(true /* enabled */);
mWakeupController.start();
- // Simulates emptying the lock: first returns false then returns true
- when(mWakeupLock.isEmpty()).thenReturn(false).thenReturn(true);
-
ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor =
ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
@@ -350,20 +386,20 @@ public class WakeupControllerTest {
WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue();
// incoming scan results
+ mTestScanResult.frequency = DFS_CHANNEL;
scanListener.onResults(mTestScanDatas);
- verify(mWakeupLock, times(2)).isEmpty();
- verify(mWifiWakeMetrics).recordUnlockEvent(1 /* numScans */);
+ verify(mWakeupLock).update(eq(Collections.emptySet()));
}
/**
* Verify that the controller searches for viable networks during onResults when WakeupLock is
- * empty.
+ * unlocked.
*/
@Test
- public void onResultsSearchesForViableNetworkWhenWakeupLockIsEmpty() {
- // empty wakeup lock
- when(mWakeupLock.isEmpty()).thenReturn(true);
+ public void onResultsSearchesForViableNetworkWhenWakeupLockIsUnlocked() {
+ // unlock wakeup lock
+ when(mWakeupLock.isUnlocked()).thenReturn(true);
// do not find viable network
when(mWakeupEvaluator.findViableNetwork(any(), any())).thenReturn(null);
@@ -401,7 +437,7 @@ public class WakeupControllerTest {
// incoming scan results
scanListener.onResults(mTestScanDatas);
- verify(mWakeupLock, never()).isEmpty();
+ verify(mWakeupLock, never()).isUnlocked();
verify(mWakeupLock, never()).update(any());
verifyDoesNotEnableWifi();
@@ -412,8 +448,8 @@ public class WakeupControllerTest {
*/
@Test
public void onResultsEnablesWifi() {
- // empty wakeup lock
- when(mWakeupLock.isEmpty()).thenReturn(true);
+ // unlock wakeup lock
+ when(mWakeupLock.isUnlocked()).thenReturn(true);
// find viable network
when(mWakeupEvaluator.findViableNetwork(any(), any())).thenReturn(mTestScanResult);
@@ -451,9 +487,9 @@ public class WakeupControllerTest {
// incoming scan results
scanListener.onResults(mTestScanDatas);
- verify(mWakeupLock, never()).initialize(any());
+ verify(mWakeupLock, never()).setLock(any());
verify(mWakeupLock, never()).update(any());
- verify(mWakeupLock, never()).isEmpty();
+ verify(mWakeupLock, never()).isUnlocked();
verify(mWakeupOnboarding, never()).maybeShowNotification();
verify(mWakeupEvaluator, never()).findViableNetwork(any(), any());
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
index 7144ecf3f..f3126c7a9 100644
--- a/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
@@ -40,6 +40,8 @@ public class WakeupLockTest {
private static final String SSID_2 = "ssid2";
@Mock private WifiConfigManager mWifiConfigManager;
+ @Mock private WifiWakeMetrics mWifiWakeMetrics;
+ @Mock private Clock mClock;
private ScanResultMatchInfo mNetwork1;
private ScanResultMatchInfo mNetwork2;
@@ -52,6 +54,8 @@ public class WakeupLockTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
+
mNetwork1 = new ScanResultMatchInfo();
mNetwork1.networkSsid = SSID_1;
mNetwork1.networkType = ScanResultMatchInfo.NETWORK_TYPE_OPEN;
@@ -60,7 +64,7 @@ public class WakeupLockTest {
mNetwork2.networkSsid = SSID_2;
mNetwork2.networkType = ScanResultMatchInfo.NETWORK_TYPE_EAP;
- mWakeupLock = new WakeupLock(mWifiConfigManager);
+ mWakeupLock = new WakeupLock(mWifiConfigManager, mWifiWakeMetrics, mClock);
}
/**
@@ -71,7 +75,7 @@ public class WakeupLockTest {
*/
private void updateEnoughTimesToEvictWithAsserts(Collection<ScanResultMatchInfo> networks) {
for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT; i++) {
- assertFalse("Lock empty after " + i + " scans", mWakeupLock.isEmpty());
+ assertFalse("Lock empty after " + i + " scans", mWakeupLock.isUnlocked());
mWakeupLock.update(networks);
}
}
@@ -89,33 +93,82 @@ public class WakeupLockTest {
}
/**
+ * Verify that calling update {@link WakeupLock#CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT}
+ * times sets the lock to be initialized.
+ */
+ @Test
+ public void verifyInitializingLockByScans() {
+ List<ScanResultMatchInfo> networks = Collections.singletonList(mNetwork1);
+ mWakeupLock.setLock(networks);
+ assertFalse(mWakeupLock.isInitialized());
+
+ mWakeupLock.update(networks);
+ assertFalse(mWakeupLock.isInitialized());
+ mWakeupLock.update(networks);
+ assertFalse(mWakeupLock.isInitialized());
+ mWakeupLock.update(networks);
+ assertTrue(mWakeupLock.isInitialized());
+ }
+
+ /**
+ * Verify that calling update after {@link WakeupLock#MAX_LOCK_TIME_MILLIS} milliseconds sets
+ * the lock to be initialized and does not add the scans to the lock.
+ */
+ @Test
+ public void verifyInitializingLockByTimeout() {
+ when(mClock.getElapsedSinceBootMillis())
+ .thenReturn(0L, WakeupLock.MAX_LOCK_TIME_MILLIS + 1);
+ mWakeupLock.setLock(Collections.emptyList());
+ assertFalse(mWakeupLock.isInitialized());
+
+ List<ScanResultMatchInfo> networks = Collections.singletonList(mNetwork1);
+ mWakeupLock.update(networks);
+ assertTrue(mWakeupLock.isInitialized());
+ assertTrue(mWakeupLock.isUnlocked());
+ }
+
+ /**
+ * Verify that addToLock saves to the store if it changes the contents of the lock.
+ */
+ @Test
+ public void addToLockSavesToStore() {
+ mWakeupLock.setLock(Collections.emptyList());
+
+ List<ScanResultMatchInfo> networks = Collections.singletonList(mNetwork1);
+ mWakeupLock.update(networks);
+
+ // want 2 invocations, once for setLock(), once for addToLock
+ verify(mWifiConfigManager, times(2)).saveToStore(false);
+ }
+
+ /**
* Verify that the WakeupLock is not empty immediately after being initialized with networks.
*/
@Test
- public void verifyNotEmptyWhenInitializedWithNetworkList() {
- mWakeupLock.initialize(Arrays.asList(mNetwork1, mNetwork2));
- assertFalse(mWakeupLock.isEmpty());
+ public void verifyNotEmptyWhenSetWithNetworkList() {
+ setLockAndInitializeByTimeout(Arrays.asList(mNetwork1, mNetwork2));
+ assertFalse(mWakeupLock.isUnlocked());
}
/**
- * Verify that the WakeupLock is empty when initialized with an empty list.
+ * Verify that the WakeupLock is unlocked when initialized with an empty list.
*/
@Test
public void isEmptyWhenInitializedWithEmptyList() {
- mWakeupLock.initialize(Collections.emptyList());
- assertTrue(mWakeupLock.isEmpty());
+ setLockAndInitializeByTimeout(Collections.emptyList());
+ assertTrue(mWakeupLock.isUnlocked());
}
/**
- * Verify that initializing the WakeupLock clears out previous entries.
+ * Verify that setting the lock clears out previous entries.
*/
@Test
- public void initializingLockClearsPreviousNetworks() {
- mWakeupLock.initialize(Collections.singletonList(mNetwork1));
- assertFalse(mWakeupLock.isEmpty());
+ public void setLockClearsPreviousNetworks() {
+ setLockAndInitializeByTimeout(Collections.singletonList(mNetwork1));
+ assertFalse(mWakeupLock.isUnlocked());
- mWakeupLock.initialize(Collections.emptyList());
- assertTrue(mWakeupLock.isEmpty());
+ setLockAndInitializeByTimeout(Collections.emptyList());
+ assertTrue(mWakeupLock.isUnlocked());
}
/**
@@ -124,11 +177,11 @@ public class WakeupLockTest {
*/
@Test
public void updateShouldRemoveNetworksAfterConsecutiveMissedScans() {
- mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+ setLockAndInitializeByTimeout(Collections.singletonList(mNetwork1));
updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork2));
- assertTrue(mWakeupLock.isEmpty());
+ assertTrue(mWakeupLock.isUnlocked());
}
/**
@@ -139,7 +192,7 @@ public class WakeupLockTest {
List<ScanResultMatchInfo> lockedNetworks = Collections.singletonList(mNetwork1);
List<ScanResultMatchInfo> updateNetworks = Collections.singletonList(mNetwork2);
- mWakeupLock.initialize(lockedNetworks);
+ setLockAndInitializeByTimeout(lockedNetworks);
// one update without network
mWakeupLock.update(updateNetworks);
@@ -148,7 +201,7 @@ public class WakeupLockTest {
updateEnoughTimesToEvictWithAsserts(updateNetworks);
- assertTrue(mWakeupLock.isEmpty());
+ assertTrue(mWakeupLock.isUnlocked());
}
/**
@@ -157,13 +210,13 @@ public class WakeupLockTest {
@Test
public void updateWithLockedNetworkAfterItIsRemovedDoesNotReset() {
List<ScanResultMatchInfo> lockedNetworks = Collections.singletonList(mNetwork1);
- mWakeupLock.initialize(lockedNetworks);
+ setLockAndInitializeByTimeout(lockedNetworks);
updateEnoughTimesToEvictWithAsserts(Collections.emptyList());
- assertTrue(mWakeupLock.isEmpty());
+ assertTrue(mWakeupLock.isUnlocked());
mWakeupLock.update(lockedNetworks);
- assertTrue(mWakeupLock.isEmpty());
+ assertTrue(mWakeupLock.isUnlocked());
}
/**
@@ -173,13 +226,13 @@ public class WakeupLockTest {
@Test
public void networksCanBeRemovedIncrementallyFromLock() {
List<ScanResultMatchInfo> lockedNetworks = Arrays.asList(mNetwork1, mNetwork2);
- mWakeupLock.initialize(lockedNetworks);
+ setLockAndInitializeByTimeout(lockedNetworks);
updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork1));
- assertFalse(mWakeupLock.isEmpty());
+ assertFalse(mWakeupLock.isUnlocked());
updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork2));
- assertTrue(mWakeupLock.isEmpty());
+ assertTrue(mWakeupLock.isUnlocked());
}
/**
@@ -187,7 +240,7 @@ public class WakeupLockTest {
*/
@Test
public void initializeShouldSaveSsidsToStore() {
- mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+ setLockAndInitializeByTimeout(Collections.singletonList(mNetwork1));
verify(mWifiConfigManager).saveToStore(eq(false));
}
@@ -196,7 +249,7 @@ public class WakeupLockTest {
*/
@Test
public void updateShouldOnlySaveIfLockChanges() {
- mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+ setLockAndInitializeByTimeout(Collections.singletonList(mNetwork1));
updateEnoughTimesToEvictWithoutAsserts(Collections.emptyList());
// need exactly 2 invocations: 1 for initialize, 1 for successful update
@@ -208,7 +261,33 @@ public class WakeupLockTest {
*/
@Test
public void updateShouldNotSaveIfLockDoesNotChange() {
- mWakeupLock.update(Collections.singletonList(mNetwork1));
- verify(mWifiConfigManager, never()).saveToStore(anyBoolean());
+ List<ScanResultMatchInfo> networks = Collections.singletonList(mNetwork1);
+ setLockAndInitializeByTimeout(networks);
+ verify(mWifiConfigManager, times(1)).saveToStore(anyBoolean());
+ mWakeupLock.update(networks);
+ }
+
+ /**
+ * Verify that on unlock, records the unlock event with WifiWakeMetrics with the correct number
+ * of scans.
+ */
+ @Test
+ public void unlockingShouldRecordEventInMetrics() {
+ when(mClock.getElapsedSinceBootMillis())
+ .thenReturn(0L, WakeupLock.MAX_LOCK_TIME_MILLIS + 1);
+ List<ScanResultMatchInfo> networks = Collections.singletonList(mNetwork1);
+ mWakeupLock.setLock(networks);
+ for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT; i++) {
+ mWakeupLock.update(Collections.emptyList());
+ }
+ verify(mWifiWakeMetrics).recordUnlockEvent(3 /* numScans */);
+ }
+
+ private void setLockAndInitializeByTimeout(Collection<ScanResultMatchInfo> networks) {
+ when(mClock.getElapsedSinceBootMillis())
+ .thenReturn(0L, WakeupLock.MAX_LOCK_TIME_MILLIS + 1);
+ mWakeupLock.setLock(networks);
+ mWakeupLock.update(networks);
+ assertTrue(mWakeupLock.isInitialized());
}
}