diff options
author | xshu <xshu@google.com> | 2020-02-19 16:42:36 -0800 |
---|---|---|
committer | xshu <xshu@google.com> | 2020-02-25 13:53:39 -0800 |
commit | 560f74b8c633834ad952a44a2a650ad63b618f83 (patch) | |
tree | f869c701558f288bf6a66bae479f28ac7b391dbe | |
parent | 20f200f9df903e448da4d4e3f71615baaa87171f (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
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. |