diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2018-04-04 18:57:52 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-04-04 18:57:52 +0000 |
commit | f4ec51d3b9d8b4d7f6f9d4b9cf0832293a8cfb14 (patch) | |
tree | f081ba0d7497c8e18c24cfe6c109c242a6021034 | |
parent | 9f64c6e98f79d43699ba15e286bf7c49c4c1df07 (diff) | |
parent | ce90a2a975df45de66b9655c63d5e7b27a9c2688 (diff) |
Merge "ScanRequestProxy: Allow short bursts of scan requests" into pi-dev
-rw-r--r-- | service/java/com/android/server/wifi/ScanRequestProxy.java | 61 | ||||
-rw-r--r-- | tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java | 91 |
2 files changed, 95 insertions, 57 deletions
diff --git a/service/java/com/android/server/wifi/ScanRequestProxy.java b/service/java/com/android/server/wifi/ScanRequestProxy.java index d4c9b3ef0..b9e48ea56 100644 --- a/service/java/com/android/server/wifi/ScanRequestProxy.java +++ b/service/java/com/android/server/wifi/ScanRequestProxy.java @@ -34,6 +34,8 @@ import com.android.server.wifi.util.WifiPermissionsUtil; import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import javax.annotation.concurrent.NotThreadSafe; @@ -51,15 +53,21 @@ import javax.annotation.concurrent.NotThreadSafe; * c) Will send out the {@link WifiManager#SCAN_RESULTS_AVAILABLE_ACTION} broadcast when new * scan results are available. * d) Throttle scan requests from non-setting apps: - * d.1) For foreground apps, throttle to a max of 1 scan per app every 30 seconds. - * d.2) For background apps, throttle to a max of 1 scan from any app every 30 minutes. + * a) Each foreground app can request a max of + * {@link #SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS} scan every + * {@link #SCAN_REQUEST_THROTTLE_TIME_WINDOW_FG_APPS_MS}. + * b) Background apps combined can request 1 scan every + * {@link #SCAN_REQUEST_THROTTLE_INTERVAL_BG_APPS_MS}. * Note: This class is not thread-safe. It needs to be invoked from WifiStateMachine thread only. */ @NotThreadSafe public class ScanRequestProxy { private static final String TAG = "WifiScanRequestProxy"; + + @VisibleForTesting + public static final int SCAN_REQUEST_THROTTLE_TIME_WINDOW_FG_APPS_MS = 120 * 1000; @VisibleForTesting - public static final int SCAN_REQUEST_THROTTLE_INTERVAL_FG_APPS_MS = 30 * 1000; + public static final int SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS = 4; @VisibleForTesting public static final int SCAN_REQUEST_THROTTLE_INTERVAL_BG_APPS_MS = 30 * 60 * 1000; @@ -81,8 +89,8 @@ public class ScanRequestProxy { private boolean mIsScanProcessingComplete = true; // Timestamps for the last scan requested by any background app. private long mLastScanTimestampForBgApps = 0; - // Timestamps for the last scan requested by each foreground app. - private final ArrayMap<String, Long> mLastScanTimestampsForFgApps = new ArrayMap(); + // Timestamps for the list of last few scan requests by each foreground app. + private final ArrayMap<String, LinkedList<Long>> mLastScanTimestampsForFgApps = new ArrayMap(); // Scan results cached from the last full single scan request. private final List<ScanResult> mLastScanResults = new ArrayList<>(); // Common scan listener for scan requests. @@ -223,19 +231,47 @@ public class ScanRequestProxy { } } + private void trimPastScanRequestTimesForForegroundApp( + List<Long> scanRequestTimestamps, long currentTimeMillis) { + Iterator<Long> timestampsIter = scanRequestTimestamps.iterator(); + while (timestampsIter.hasNext()) { + Long scanRequestTimeMillis = timestampsIter.next(); + if ((currentTimeMillis - scanRequestTimeMillis) + > SCAN_REQUEST_THROTTLE_TIME_WINDOW_FG_APPS_MS) { + timestampsIter.remove(); + } else { + // This list is sorted by timestamps, so we can skip any more checks + break; + } + } + } + + private LinkedList<Long> getOrCreateScanRequestTimestampsForForegroundApp(String packageName) { + LinkedList<Long> scanRequestTimestamps = mLastScanTimestampsForFgApps.get(packageName); + if (scanRequestTimestamps == null) { + scanRequestTimestamps = new LinkedList<>(); + mLastScanTimestampsForFgApps.put(packageName, scanRequestTimestamps); + } + return scanRequestTimestamps; + } + /** * Checks if the scan request from the app (specified by packageName) needs * to be throttled. + * The throttle limit allows a max of {@link #SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS} + * in {@link #SCAN_REQUEST_THROTTLE_TIME_WINDOW_FG_APPS_MS} window. */ private boolean shouldScanRequestBeThrottledForForegroundApp(String packageName) { - long lastScanMs = mLastScanTimestampsForFgApps.getOrDefault(packageName, 0L); - long elapsedRealtime = mClock.getElapsedSinceBootMillis(); - if (lastScanMs != 0 - && (elapsedRealtime - lastScanMs) < SCAN_REQUEST_THROTTLE_INTERVAL_FG_APPS_MS) { + LinkedList<Long> scanRequestTimestamps = + getOrCreateScanRequestTimestampsForForegroundApp(packageName); + long currentTimeMillis = mClock.getElapsedSinceBootMillis(); + // First evict old entries from the list. + trimPastScanRequestTimesForForegroundApp(scanRequestTimestamps, currentTimeMillis); + if (scanRequestTimestamps.size() >= SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS) { return true; } // Proceed with the scan request and record the time. - mLastScanTimestampsForFgApps.put(packageName, elapsedRealtime); + scanRequestTimestamps.addLast(currentTimeMillis); return false; } @@ -275,11 +311,6 @@ public class ScanRequestProxy { /** * Checks if the scan request from the app (specified by callingUid & packageName) needs * to be throttled. - * - * a) Each foreground app can request 1 scan every - * {@link #SCAN_REQUEST_THROTTLE_INTERVAL_FG_APPS_MS}. - * b) Background apps combined can request 1 scan every - * {@link #SCAN_REQUEST_THROTTLE_INTERVAL_BG_APPS_MS}. */ private boolean shouldScanRequestBeThrottledForApp(int callingUid, String packageName) { boolean isThrottled; diff --git a/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java b/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java index 6a2f72d3a..b42f53648 100644 --- a/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java @@ -18,6 +18,9 @@ package com.android.server.wifi; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE; +import static com.android.server.wifi.ScanRequestProxy.SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS; +import static com.android.server.wifi.ScanRequestProxy.SCAN_REQUEST_THROTTLE_TIME_WINDOW_FG_APPS_MS; + import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -459,48 +462,50 @@ public class ScanRequestProxyTest { } /** - * Ensure new scan requests from the same app are rejected if it's before - * {@link ScanRequestProxy#SCAN_REQUEST_THROTTLE_INTERVAL_FG_APPS_MS} + * Ensure new scan requests from the same app are rejected if there are more than + * {@link ScanRequestProxy#SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS} requests in + * {@link ScanRequestProxy#SCAN_REQUEST_THROTTLE_TIME_WINDOW_FG_APPS_MS} */ @Test - public void testSuccessiveScanRequestFromSameAppThrottled() { + public void testSuccessiveScanRequestFromSameFgAppThrottled() { long firstRequestMs = 782; when(mClock.getElapsedSinceBootMillis()).thenReturn(firstRequestMs); - // Make scan request 1. - assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); - mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); - - long secondRequestMs = - firstRequestMs + ScanRequestProxy.SCAN_REQUEST_THROTTLE_INTERVAL_FG_APPS_MS - 1; - when(mClock.getElapsedSinceBootMillis()).thenReturn(secondRequestMs); - // Make scan request 2 from the same package name & ensure that it is throttled. + for (int i = 0; i < SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS; i++) { + when(mClock.getElapsedSinceBootMillis()).thenReturn(firstRequestMs + i); + assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); + mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); + } + // Make next scan request from the same package name & ensure that it is throttled. assertFalse(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); validateScanResultsFailureBroadcastSent(TEST_PACKAGE_NAME_1); - verify(mWifiMetrics, times(2)).incrementExternalAppOneshotScanRequestsCount(); + verify(mWifiMetrics, times(SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS + 1)) + .incrementExternalAppOneshotScanRequestsCount(); verify(mWifiMetrics).incrementExternalForegroundAppOneshotScanRequestsThrottledCount(); } /** - * Ensure new scan requests from the same app are not rejected if it's after - * {@link ScanRequestProxy#SCAN_REQUEST_THROTTLE_INTERVAL_FG_APPS_MS} + * Ensure new scan requests from the same app are rejected if there are more than + * {@link ScanRequestProxy#SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS} requests after + * {@link ScanRequestProxy#SCAN_REQUEST_THROTTLE_TIME_WINDOW_FG_APPS_MS} */ @Test - public void testSuccessiveScanRequestFromSameAppNotThrottled() { + public void testSuccessiveScanRequestFromSameFgAppNotThrottled() { long firstRequestMs = 782; when(mClock.getElapsedSinceBootMillis()).thenReturn(firstRequestMs); - // Make scan request 1. - assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); - mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); - - long secondRequestMs = - firstRequestMs + ScanRequestProxy.SCAN_REQUEST_THROTTLE_INTERVAL_FG_APPS_MS + 1; - when(mClock.getElapsedSinceBootMillis()).thenReturn(secondRequestMs); - // Make scan request 2 from the same package name & ensure that it is not throttled. + for (int i = 0; i < SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS; i++) { + when(mClock.getElapsedSinceBootMillis()).thenReturn(firstRequestMs + i); + assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); + mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); + } + long lastRequestMs = firstRequestMs + SCAN_REQUEST_THROTTLE_TIME_WINDOW_FG_APPS_MS + 1; + when(mClock.getElapsedSinceBootMillis()).thenReturn(lastRequestMs); + // Make next scan request from the same package name & ensure that it is not throttled. assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); - verify(mWifiMetrics, times(2)).incrementExternalAppOneshotScanRequestsCount(); + verify(mWifiMetrics, times(SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS + 1)) + .incrementExternalAppOneshotScanRequestsCount(); } /** @@ -513,14 +518,12 @@ public class ScanRequestProxyTest { long firstRequestMs = 782; when(mClock.getElapsedSinceBootMillis()).thenReturn(firstRequestMs); - // Make scan request 1. - assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); - mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); - - long secondRequestMs = - firstRequestMs + ScanRequestProxy.SCAN_REQUEST_THROTTLE_INTERVAL_FG_APPS_MS - 1; - when(mClock.getElapsedSinceBootMillis()).thenReturn(secondRequestMs); - // Make scan request 2 from the same package name & ensure that it is not throttled. + for (int i = 0; i < SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS; i++) { + when(mClock.getElapsedSinceBootMillis()).thenReturn(firstRequestMs + i); + assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); + mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); + } + // Make next scan request from the same package name & ensure that it is not throttled. assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); } @@ -529,23 +532,27 @@ public class ScanRequestProxyTest { * Ensure new scan requests from different apps are not throttled. */ @Test - public void testSuccessiveScanRequestFromDifferentAppsNotThrottled() { + public void testSuccessiveScanRequestFromDifferentFgAppsNotThrottled() { long firstRequestMs = 782; when(mClock.getElapsedSinceBootMillis()).thenReturn(firstRequestMs); - // Make scan request 1. + for (int i = 0; i < SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS / 2; i++) { + when(mClock.getElapsedSinceBootMillis()).thenReturn(firstRequestMs + i); + assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); + mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); + } + for (int i = 0; i < SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS / 2; i++) { + when(mClock.getElapsedSinceBootMillis()).thenReturn(firstRequestMs + i); + assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_2)); + mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); + } + // Make next scan request from both the package name & ensure that it is not throttled. assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); - - // Make scan request 2 from the same package name & ensure that it is throttled. - assertFalse(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1)); - validateScanResultsFailureBroadcastSent(TEST_PACKAGE_NAME_1); - - // Make scan request 3 from a different package name & ensure that it is not throttled. assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_2)); mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); - verify(mWifiMetrics, times(3)).incrementExternalAppOneshotScanRequestsCount(); - verify(mWifiMetrics).incrementExternalForegroundAppOneshotScanRequestsThrottledCount(); + verify(mWifiMetrics, times(SCAN_REQUEST_THROTTLE_MAX_IN_TIME_WINDOW_FG_APPS + 2)) + .incrementExternalAppOneshotScanRequestsCount(); } /** |