summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxshu <xshu@google.com>2020-02-19 16:42:36 -0800
committerxshu <xshu@google.com>2020-02-25 13:53:39 -0800
commit560f74b8c633834ad952a44a2a650ad63b618f83 (patch)
treef869c701558f288bf6a66bae479f28ac7b391dbe
parent20f200f9df903e448da4d4e3f71615baaa87171f (diff)
High movement - trigger delayed partial scan
Add delayed partial scan to check if the device is moving in respect to APs. Also enables the feature by default. Bug: 141446972 Test: atest com.android.server.wifi Test: manually verified log Change-Id: Ie219648c2fb07d466f117a0b77a538970294c725
-rw-r--r--service/java/com/android/server/wifi/WifiConnectivityManager.java61
-rw-r--r--service/res/values/config.xml2
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java42
3 files changed, 99 insertions, 6 deletions
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index ad626e003..86cf26698 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -74,6 +74,8 @@ public class WifiConnectivityManager {
"WifiConnectivityManager Restart Single Scan";
public static final String RESTART_CONNECTIVITY_SCAN_TIMER_TAG =
"WifiConnectivityManager Restart Scan";
+ public static final String DELAYED_PARTIAL_SCAN_TIMER_TAG =
+ "WifiConnectivityManager Schedule Delayed Partial Scan Timer";
private static final long RESET_TIME_STAMP = Long.MIN_VALUE;
// Constants to indicate whether a scan should start immediately or
@@ -173,6 +175,7 @@ public class WifiConnectivityManager {
private long mLastPeriodicSingleScanTimeStamp = RESET_TIME_STAMP;
private boolean mPnoScanStarted = false;
private boolean mPeriodicScanTimerSet = false;
+ private boolean mDelayedPartialScanTimerSet = false;
// Device configs
private boolean mWaitForFullBandScanResults = false;
@@ -245,6 +248,33 @@ public class WifiConnectivityManager {
}
};
+ private final AlarmManager.OnAlarmListener mDelayedPartialScanTimerListener =
+ new AlarmManager.OnAlarmListener() {
+ public void onAlarm() {
+ if (mCachedWifiCandidates == null
+ || mCachedWifiCandidates.frequencies == null
+ || mCachedWifiCandidates.frequencies.size() == 0) {
+ return;
+ }
+ ScanSettings settings = new ScanSettings();
+ settings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY;
+ settings.band = getScanBand(false);
+ settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT
+ | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
+ settings.numBssidsPerScan = 0;
+ int index = 0;
+ settings.channels =
+ new WifiScanner.ChannelSpec[mCachedWifiCandidates.frequencies.size()];
+ for (Integer freq : mCachedWifiCandidates.frequencies) {
+ settings.channels[index++] = new WifiScanner.ChannelSpec(freq);
+ }
+ SingleScanListener singleScanListener = new SingleScanListener(false);
+ mScanner.startScan(settings, new HandlerExecutor(mEventHandler),
+ singleScanListener, WIFI_WORK_SOURCE);
+ mWifiMetrics.incrementConnectivityOneshotScanCount();
+ }
+ };
+
/**
* Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener.
* Executes selection of potential network candidates, initiation of connection attempt to that
@@ -309,9 +339,9 @@ public class WifiConnectivityManager {
return null;
}
+ long minimumTimeBetweenScansMs = mContext.getResources().getInteger(
+ R.integer.config_wifiHighMovementNetworkSelectionOptimizationScanDelayMs);
if (mCachedWifiCandidates != null && mCachedWifiCandidates.candidateRssiMap != null) {
- long minimumTimeBetweenScansMs = mContext.getResources().getInteger(
- R.integer.config_wifiHighMovementNetworkSelectionOptimizationScanDelayMs);
// cached candidates are too recent, wait for next scan
if (mClock.getElapsedSinceBootMillis() - mCachedWifiCandidates.timeSinceBootMs
< minimumTimeBetweenScansMs) {
@@ -337,13 +367,13 @@ public class WifiConnectivityManager {
}
// Either no cached candidates, or all candidates got filtered out.
- // Update the cached candidates here
+ // Update the cached candidates here and schedule a delayed partial scan.
if (isNotPartialScan) {
mCachedWifiCandidates = new CachedWifiCandidates(mClock.getElapsedSinceBootMillis(),
candidates);
localLog("Found " + candidates.size() + " candidates at high mobility state. "
+ "Re-doing scan to confirm network quality.");
- // todo: schedule delayed partial scan.
+ scheduleDelayedPartialScan(minimumTimeBetweenScansMs);
}
return null;
}
@@ -358,15 +388,19 @@ public class WifiConnectivityManager {
private class CachedWifiCandidates {
public final long timeSinceBootMs;
public final Map<WifiCandidates.Key, Integer> candidateRssiMap;
+ public final Set<Integer> frequencies;
CachedWifiCandidates(long timeSinceBootMs, List<WifiCandidates.Candidate> candidates) {
this.timeSinceBootMs = timeSinceBootMs;
if (candidates == null) {
this.candidateRssiMap = null;
+ this.frequencies = null;
} else {
- candidateRssiMap = new ArrayMap<WifiCandidates.Key, Integer>();
+ this.candidateRssiMap = new ArrayMap<WifiCandidates.Key, Integer>();
+ this.frequencies = new HashSet<Integer>();
for (WifiCandidates.Candidate c : candidates) {
candidateRssiMap.put(c.getKey(), c.getScanRssi());
+ frequencies.add(c.getFrequency());
}
}
}
@@ -1291,6 +1325,22 @@ public class WifiConnectivityManager {
mWatchdogListener, mEventHandler);
}
+ // Schedules a delayed partial scan, which will scan the frequencies in mCachedWifiCandidates.
+ private void scheduleDelayedPartialScan(long delayMillis) {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mClock.getElapsedSinceBootMillis() + delayMillis, DELAYED_PARTIAL_SCAN_TIMER_TAG,
+ mDelayedPartialScanTimerListener, mEventHandler);
+ mDelayedPartialScanTimerSet = true;
+ }
+
+ // Cancel the delayed partial scan timer.
+ private void cancelDelayedPartialScan() {
+ if (mDelayedPartialScanTimerSet) {
+ mAlarmManager.cancel(mDelayedPartialScanTimerListener);
+ mDelayedPartialScanTimerSet = false;
+ }
+ }
+
// Set up periodic scan timer
private void schedulePeriodicScanTimer(int intervalMs) {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
@@ -1370,6 +1420,7 @@ public class WifiConnectivityManager {
// Due to b/28020168, timer based single scan will be scheduled
// to provide periodic scan in an exponential backoff fashion.
cancelPeriodicScanTimer();
+ cancelDelayedPartialScan();
stopPnoScan();
mScanRestartCount = 0;
}
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 0f446522f..31156f359 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -370,7 +370,7 @@
<bool translatable="false" name="config_wifiSuspendOptimizationsEnabled">true</bool>
<!-- Network selection optimization at DEVICE_MOBILITY_STATE_HIGH_MVMT -->
- <bool translatable="false" name="config_wifiHighMovementNetworkSelectionOptimizationEnabled">false</bool>
+ <bool translatable="false" name="config_wifiHighMovementNetworkSelectionOptimizationEnabled">true</bool>
<!-- Duration for the delayed scan used to verify access points are staying relatively stationary
to the device at high mobility state. (default = 10 seconds) -->
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index c157f4e2c..3c37cdfee 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -21,6 +21,7 @@ import static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConf
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.argThat;
import android.app.test.MockAnswerUtil.AnswerWithArguments;
import android.app.test.TestAlarmManager;
@@ -55,6 +56,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
@@ -190,6 +192,7 @@ public class WifiConnectivityManagerTest extends WifiBaseTest {
private static final String CANDIDATE_SSID = "\"AnSsid\"";
private static final String CANDIDATE_BSSID = "6c:f3:7f:ae:8c:f3";
private static final String INVALID_SCAN_RESULT_BSSID = "6c:f3:7f:ae:8c:f4";
+ private static final int TEST_FREQUENCY = 2420;
private static final long CURRENT_SYSTEM_TIME_MS = 1000;
private static final int MAX_BSSID_BLACKLIST_SIZE = 16;
private static final int[] VALID_CONNECTED_SINGLE_SCAN_SCHEDULE = {10, 30, 50};
@@ -315,6 +318,7 @@ public class WifiConnectivityManagerTest extends WifiBaseTest {
WifiCandidates.Key key = mock(WifiCandidates.Key.class);
when(mCandidate1.getKey()).thenReturn(key);
when(mCandidate1.getScanRssi()).thenReturn(-40);
+ when(mCandidate1.getFrequency()).thenReturn(TEST_FREQUENCY);
when(mCandidate2.getKey()).thenReturn(key);
when(mCandidate2.getScanRssi()).thenReturn(-60);
mCandidateList = new ArrayList<WifiCandidates.Candidate>();
@@ -723,6 +727,44 @@ public class WifiConnectivityManagerTest extends WifiBaseTest {
}
/**
+ * Verify that the device is initiating partial scans to verify AP stability in the high
+ * movement mobility state.
+ */
+ @Test
+ public void testHighMovementTriggerPartialScan() {
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
+ // Enable high movement optimization
+ mResources.setBoolean(R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled,
+ true);
+ mWifiConnectivityManager.setDeviceMobilityState(
+ WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT);
+
+ // Set WiFi to disconnected state to trigger scan
+ mWifiConnectivityManager.handleConnectionStateChanged(
+ WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
+ mLooper.dispatchAll();
+ // Verify there is no connection due to currently having no cached candidates.
+ verify(mClientModeImpl, never()).startConnectToNetwork(
+ CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
+
+ // Move time forward and verify that a delayed partial scan is scheduled.
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(HIGH_MVMT_SCAN_DELAY_MS + 1L);
+ mAlarmManager.dispatch(WifiConnectivityManager.DELAYED_PARTIAL_SCAN_TIMER_TAG);
+ mLooper.dispatchAll();
+
+ verify(mWifiScanner).startScan((ScanSettings) argThat(new WifiPartialScanSettingMatcher()),
+ any(), any(), any());
+ }
+
+ private class WifiPartialScanSettingMatcher implements ArgumentMatcher<ScanSettings> {
+ @Override
+ public boolean matches(ScanSettings scanSettings) {
+ return scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED
+ && scanSettings.channels[0].frequency == TEST_FREQUENCY;
+ }
+ }
+
+ /**
* Verify that in the high movement mobility state, when the RSSI delta of a BSSID from
* 2 consecutive scans becomes greater than a threshold, the candidate get ignored from
* network selection.