summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2018-04-04 18:57:52 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2018-04-04 18:57:52 +0000
commitf4ec51d3b9d8b4d7f6f9d4b9cf0832293a8cfb14 (patch)
treef081ba0d7497c8e18c24cfe6c109c242a6021034
parent9f64c6e98f79d43699ba15e286bf7c49c4c1df07 (diff)
parentce90a2a975df45de66b9655c63d5e7b27a9c2688 (diff)
Merge "ScanRequestProxy: Allow short bursts of scan requests" into pi-dev
-rw-r--r--service/java/com/android/server/wifi/ScanRequestProxy.java61
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java91
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();
}
/**