summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2018-01-29 22:57:09 -0800
committerRoshan Pius <rpius@google.com>2018-03-19 13:16:14 -0700
commit4f11976612567e57eefb0b58c7aef1059f52b45c (patch)
tree2c0acc1e787500d7b88035e6c4e40631d4c6a354
parent6ef9e33f9bd16064df5f5696731f36f8fab286ae (diff)
ScanRequestProxy: Add scan throttling
This is a port of the existing scan throttling for background apps in WifiServiceImpl. We're now going to throttle all external scan requests, except for requests coming in from apps holding NETWORK_SETTINGS permission. TODO: WifiServiceImpl.startScan() should return the status from ScanRequestProxy.startScan(). Bug: 68987915 Test: Unit tests Test: Scans from settings UI still works. Change-Id: Ib388752df554de85ca5c29e424b344ef07a7d5b2 Merged-In: I78e4113317b9835dec6e816f2c5a0ba309d73061
-rw-r--r--service/java/com/android/server/wifi/ScanRequestProxy.java59
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java2
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java93
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java155
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java97
5 files changed, 192 insertions, 214 deletions
diff --git a/service/java/com/android/server/wifi/ScanRequestProxy.java b/service/java/com/android/server/wifi/ScanRequestProxy.java
index 588ea6c99..39b9d8ae1 100644
--- a/service/java/com/android/server/wifi/ScanRequestProxy.java
+++ b/service/java/com/android/server/wifi/ScanRequestProxy.java
@@ -24,8 +24,10 @@ import android.net.wifi.WifiScanner;
import android.os.Binder;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wifi.util.WifiPermissionsUtil;
import java.util.ArrayList;
@@ -47,17 +49,18 @@ import javax.annotation.concurrent.NotThreadSafe;
* c) Will send out the {@link WifiManager#SCAN_RESULTS_AVAILABLE_ACTION} broadcast when new
* scan results are available.
* Note: This class is not thread-safe. It needs to be invoked from WifiStateMachine thread only.
- * TODO (b/68987915): Port over scan throttling logic from WifiService for all apps.
- * TODO: Port over idle mode handling from WifiService.
*/
@NotThreadSafe
public class ScanRequestProxy {
private static final String TAG = "WifiScanRequestProxy";
+ @VisibleForTesting
+ public static final int SCAN_REQUEST_THROTTLE_INTERVAL_MS = 30 * 1000;
private final Context mContext;
private final WifiInjector mWifiInjector;
private final WifiConfigManager mWifiConfigManager;
private final WifiPermissionsUtil mWifiPermissionsUtil;
+ private final Clock mClock;
private WifiScanner mWifiScanner;
// Verbose logging flag.
@@ -66,6 +69,8 @@ public class ScanRequestProxy {
private boolean mScanningForHiddenNetworksEnabled = false;
// Flag to indicate that we're waiting for scan results from an existing request.
private boolean mIsScanProcessingComplete = true;
+ // Timestamps for the last scan requested by each app.
+ private final ArrayMap<String, Long> mLastScanTimestampsForApps = 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.
@@ -118,11 +123,12 @@ public class ScanRequestProxy {
};
ScanRequestProxy(Context context, WifiInjector wifiInjector, WifiConfigManager configManager,
- WifiPermissionsUtil wifiPermissionUtil) {
+ WifiPermissionsUtil wifiPermissionUtil, Clock clock) {
mContext = context;
mWifiInjector = wifiInjector;
mWifiConfigManager = configManager;
mWifiPermissionsUtil = wifiPermissionUtil;
+ mClock = clock;
}
/**
@@ -184,15 +190,55 @@ public class ScanRequestProxy {
}
/**
+ * Helper method to send the scan request failure broadcast to specified package.
+ */
+ private void sendScanResultFailureBroadcastToPackage(String packageName) {
+ // clear calling identity to send broadcast
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
+ intent.setPackage(packageName);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ } finally {
+ // restore calling identity
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ /**
+ * Checks if the scan request from the app (specified by packageName) needs
+ * to be throttled.
+ */
+ private boolean shouldScanRequestBeThrottledForApp(String packageName) {
+ long lastScanMs = mLastScanTimestampsForApps.getOrDefault(packageName, 0L);
+ long elapsedRealtime = mClock.getElapsedSinceBootMillis();
+ if (lastScanMs != 0 && (elapsedRealtime - lastScanMs) < SCAN_REQUEST_THROTTLE_INTERVAL_MS) {
+ return true;
+ }
+ // Proceed with the scan request and record the time.
+ mLastScanTimestampsForApps.put(packageName, elapsedRealtime);
+ return false;
+ }
+
+ /**
* Initiate a wifi scan.
*
* @param callingUid The uid initiating the wifi scan. Blame will be given to this uid.
* @return true if the scan request was placed or a scan is already ongoing, false otherwise.
*/
- public boolean startScan(int callingUid) {
+ public boolean startScan(int callingUid, String packageName) {
if (!retrieveWifiScannerIfNecessary()) {
Log.e(TAG, "Failed to retrieve wifiscanner");
- sendScanResultBroadcast(false);
+ sendScanResultFailureBroadcastToPackage(packageName);
+ return false;
+ }
+ boolean fromSettings = mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid);
+ // Check and throttle scan request from apps without NETWORK_SETTINGS permission.
+ if (!fromSettings && shouldScanRequestBeThrottledForApp(packageName)) {
+ Log.i(TAG, "Scan request from " + packageName + " throttled");
+ sendScanResultFailureBroadcastToPackage(packageName);
return false;
}
// Create a worksource using the caller's UID.
@@ -201,7 +247,7 @@ public class ScanRequestProxy {
// Create the scan settings.
WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
// Scan requests from apps with network settings will be of high accuracy type.
- if (mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)) {
+ if (fromSettings) {
settings.type = WifiScanner.TYPE_HIGH_ACCURACY;
}
// always do full scans
@@ -234,5 +280,6 @@ public class ScanRequestProxy {
*/
public void clearScanResults() {
mLastScanResults.clear();
+ mLastScanTimestampsForApps.clear();
}
}
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 28e36169b..00d547abe 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -238,7 +238,7 @@ public class WifiInjector {
mPasspointManager, mWifiConfigManager, mConnectivityLocalLog);
mWifiMetrics.setPasspointManager(mPasspointManager);
mScanRequestProxy = new ScanRequestProxy(mContext, this, mWifiConfigManager,
- mWifiPermissionsUtil);
+ mWifiPermissionsUtil, mClock);
// mWifiStateMachine has an implicit dependency on mJavaRuntime due to WifiDiagnostics.
mJavaRuntime = Runtime.getRuntime();
mWifiStateMachine = new WifiStateMachine(mContext, mFrameworkFacade,
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 9d292e05a..a88b20d62 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -92,8 +92,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
import android.provider.Settings;
-import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Log;
import android.util.MutableInt;
import android.util.Slog;
@@ -159,14 +157,12 @@ public class WifiServiceImpl extends IWifiManager.Stub {
private final Context mContext;
private final FrameworkFacade mFacade;
private final Clock mClock;
- private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
private final PowerManager mPowerManager;
private final AppOpsManager mAppOps;
private final UserManager mUserManager;
private final ActivityManager mActivityManager;
private final WifiCountryCode mCountryCode;
- private long mBackgroundThrottleInterval;
// Debug counter tracking scan requests sent by WifiManager
private int scanRequestCounter = 0;
@@ -181,9 +177,6 @@ public class WifiServiceImpl extends IWifiManager.Stub {
/* Backup/Restore Module */
private final WifiBackupRestore mWifiBackupRestore;
- // Map of package name of background scan apps and last scan timestamp.
- private final ArrayMap<String, Long> mLastScanTimestamps;
-
private WifiLog mLog;
/**
@@ -482,9 +475,6 @@ public class WifiServiceImpl extends IWifiManager.Stub {
mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
mLog = mWifiInjector.makeLog(TAG);
mFrameworkFacade = wifiInjector.getFrameworkFacade();
- mLastScanTimestamps = new ArrayMap<>();
- updateBackgroundThrottleInterval();
- updateBackgroundThrottlingWhitelist();
mIfaceIpModes = new ConcurrentHashMap<>();
mLocalOnlyHotspotRequests = new HashMap<>();
enableVerboseLoggingInternal(getVerboseLoggingLevel());
@@ -524,7 +514,6 @@ public class WifiServiceImpl extends IWifiManager.Stub {
(wifiEnabled ? "enabled" : "disabled"));
registerForScanModeChange();
- registerForBackgroundThrottleChanges();
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
@@ -629,18 +618,6 @@ public class WifiServiceImpl extends IWifiManager.Stub {
int callingUid = Binder.getCallingUid();
mLog.info("startScan uid=%").c(callingUid).flush();
- // Check and throttle background apps for wifi scan.
- if (isRequestFromBackground(packageName)) {
- long lastScanMs = mLastScanTimestamps.getOrDefault(packageName, 0L);
- long elapsedRealtime = mClock.getElapsedSinceBootMillis();
-
- if (lastScanMs != 0 && (elapsedRealtime - lastScanMs) < mBackgroundThrottleInterval) {
- sendFailedScanBroadcast();
- return;
- }
- // Proceed with the scan request and record the time.
- mLastScanTimestamps.put(packageName, elapsedRealtime);
- }
synchronized (this) {
if (mInIdleMode) {
// Need to send an immediate scan result broadcast in case the
@@ -656,7 +633,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
}
boolean success = mWifiInjector.getWifiStateMachineHandler().runWithScissors(() -> {
- if (!mScanRequestProxy.startScan(callingUid)) {
+ if (!mScanRequestProxy.startScan(callingUid, packageName)) {
Log.e(TAG, "Failed to start scan");
}
}, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
@@ -683,29 +660,6 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
- // Check if the request comes from background.
- private boolean isRequestFromBackground(String packageName) {
- // Requests from system or wifi are not background.
- if (Binder.getCallingUid() == Process.SYSTEM_UID
- || Binder.getCallingUid() == Process.WIFI_UID) {
- return false;
- }
- mAppOps.checkPackage(Binder.getCallingUid(), packageName);
- if (mBackgroundThrottlePackageWhitelist.contains(packageName)) {
- return false;
- }
-
- // getPackageImportance requires PACKAGE_USAGE_STATS permission, so clearing the incoming
- // identify so the permission check can be done on system process where wifi runs in.
- long callingIdentity = Binder.clearCallingIdentity();
- try {
- return mActivityManager.getPackageImportance(packageName)
- > BACKGROUND_IMPORTANCE_CUTOFF;
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- }
-
/**
* WPS support in Client mode is deprecated. Return null.
*/
@@ -2414,51 +2368,6 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
- // Monitors settings changes related to background wifi scan throttling.
- private void registerForBackgroundThrottleChanges() {
- mFrameworkFacade.registerContentObserver(
- mContext,
- Settings.Global.getUriFor(
- Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS),
- false,
- new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- updateBackgroundThrottleInterval();
- }
- }
- );
- mFrameworkFacade.registerContentObserver(
- mContext,
- Settings.Global.getUriFor(
- Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
- false,
- new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- updateBackgroundThrottlingWhitelist();
- }
- }
- );
- }
-
- private void updateBackgroundThrottleInterval() {
- mBackgroundThrottleInterval = mFrameworkFacade.getLongSetting(
- mContext,
- Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS,
- DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS);
- }
-
- private void updateBackgroundThrottlingWhitelist() {
- String setting = mFrameworkFacade.getStringSetting(
- mContext,
- Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
- mBackgroundThrottlePackageWhitelist.clear();
- if (setting != null) {
- mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(",")));
- }
- }
-
private void registerForBroadcasts() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_PRESENT);
diff --git a/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java b/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java
index 759fbe27b..aa7a821eb 100644
--- a/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ScanRequestProxyTest.java
@@ -47,6 +47,8 @@ import java.util.List;
@SmallTest
public class ScanRequestProxyTest {
private static final int TEST_UID = 5;
+ private static final String TEST_PACKAGE_NAME_1 = "com.test.1";
+ private static final String TEST_PACKAGE_NAME_2 = "com.test.2";
private static final List<WifiScanner.ScanSettings.HiddenNetwork> TEST_HIDDEN_NETWORKS_LIST =
new ArrayList<WifiScanner.ScanSettings.HiddenNetwork>() {{
add(new WifiScanner.ScanSettings.HiddenNetwork("test_ssid_1"));
@@ -59,6 +61,7 @@ public class ScanRequestProxyTest {
@Mock private WifiConfigManager mWifiConfigManager;
@Mock private WifiScanner mWifiScanner;
@Mock private WifiPermissionsUtil mWifiPermissionsUtil;
+ @Mock private Clock mClock;
private ArgumentCaptor<WorkSource> mWorkSourceArgumentCaptor =
ArgumentCaptor.forClass(WorkSource.class);
private ArgumentCaptor<WifiScanner.ScanSettings> mScanSettingsArgumentCaptor =
@@ -87,7 +90,8 @@ public class ScanRequestProxyTest {
mTestScanDatas2 = ScanTestUtil.createScanDatas(new int[][]{ { 2412, 2422, 5200, 5210 } });
mScanRequestProxy =
- new ScanRequestProxy(mContext, mWifiInjector, mWifiConfigManager, mWifiPermissionsUtil);
+ new ScanRequestProxy(mContext, mWifiInjector, mWifiConfigManager,
+ mWifiPermissionsUtil, mClock);
}
@After
@@ -101,8 +105,8 @@ public class ScanRequestProxyTest {
@Test
public void testStartScanFailWithoutScanner() {
when(mWifiInjector.getWifiScanner()).thenReturn(null);
- assertFalse(mScanRequestProxy.startScan(TEST_UID));
- validateScanResultsAvailableBroadcastSent(false);
+ assertFalse(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
+ validateScanResultsFailureBroadcastSent(TEST_PACKAGE_NAME_1);
verifyNoMoreInteractions(mWifiScanner, mWifiConfigManager, mContext);
}
@@ -112,7 +116,7 @@ public class ScanRequestProxyTest {
*/
@Test
public void testStartScanSuccess() {
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
assertTrue(mWorkSourceArgumentCaptor.getValue().equals(new WorkSource(TEST_UID)));
@@ -127,7 +131,7 @@ public class ScanRequestProxyTest {
@Test
public void testStartScanSuccessFromAppWithNetworkSettings() {
when(mWifiPermissionsUtil.checkNetworkSettingsPermission(TEST_UID)).thenReturn(true);
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
assertTrue(mWorkSourceArgumentCaptor.getValue().equals(new WorkSource(TEST_UID)));
@@ -143,7 +147,7 @@ public class ScanRequestProxyTest {
@Test
public void testStartScanWithHiddenNetworkScanningDisabled() {
mScanRequestProxy.enableScanningForHiddenNetworks(false);
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiConfigManager, never()).retrieveHiddenNetworkList();
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
@@ -159,7 +163,7 @@ public class ScanRequestProxyTest {
@Test
public void testStartScanWithHiddenNetworkScanningEnabled() {
mScanRequestProxy.enableScanningForHiddenNetworks(true);
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiConfigManager).retrieveHiddenNetworkList();
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
@@ -213,7 +217,7 @@ public class ScanRequestProxyTest {
@Test
public void testScanSuccessOverwritesPreviousResults() {
// Make scan request 1.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Verify the scan results processing for request 1.
mScanListenerArgumentCaptor.getValue().onResults(mTestScanDatas1);
@@ -224,7 +228,7 @@ public class ScanRequestProxyTest {
mScanRequestProxy.getScanResults().stream().toArray(ScanResult[]::new));
// Make scan request 2.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_2));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Verify the scan results processing for request 2.
mScanListenerArgumentCaptor.getValue().onResults(mTestScanDatas2);
@@ -243,7 +247,7 @@ public class ScanRequestProxyTest {
@Test
public void testScanFailureDoesNotOverwritePreviousResults() {
// Make scan request 1.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Verify the scan results processing for request 1.
mScanListenerArgumentCaptor.getValue().onResults(mTestScanDatas1);
@@ -254,7 +258,7 @@ public class ScanRequestProxyTest {
mScanRequestProxy.getScanResults().stream().toArray(ScanResult[]::new));
// Make scan request 2.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_2));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Verify the scan failure processing.
mScanListenerArgumentCaptor.getValue().onFailure(0, "failed");
@@ -277,12 +281,12 @@ public class ScanRequestProxyTest {
WifiScanner.ScanListener listener1;
WifiScanner.ScanListener listener2;
// Make scan request 1.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
listener1 = mScanListenerArgumentCaptor.getValue();
// Make scan request 2.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_2));
// Ensure that we did send a second scan request to scanner.
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
listener2 = mScanListenerArgumentCaptor.getValue();
@@ -314,7 +318,7 @@ public class ScanRequestProxyTest {
@Test
public void testNewScanRequestAfterPreviousScanSucceeds() {
// Make scan request 1.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Now send the scan results for request 1.
mScanListenerArgumentCaptor.getValue().onResults(mTestScanDatas1);
@@ -325,7 +329,7 @@ public class ScanRequestProxyTest {
mScanRequestProxy.getScanResults().stream().toArray(ScanResult[]::new));
// Make scan request 2.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_2));
// Ensure that we did send a second scan request to scanner.
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Now send the scan results for request 2.
@@ -347,7 +351,7 @@ public class ScanRequestProxyTest {
@Test
public void testNewScanRequestAfterPreviousScanSucceedsWithInvalidScanDatas() {
// Make scan request 1.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Now send scan success for request 1, but with invalid scan datas.
@@ -358,7 +362,7 @@ public class ScanRequestProxyTest {
assertTrue(mScanRequestProxy.getScanResults().isEmpty());
// Make scan request 2.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_2));
// Ensure that we did send a second scan request to scanner.
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Now send the scan results for request 2.
@@ -380,7 +384,7 @@ public class ScanRequestProxyTest {
@Test
public void testNewScanRequestAfterPreviousScanFailure() {
// Make scan request 1.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Now send scan failure for request 1.
@@ -390,7 +394,7 @@ public class ScanRequestProxyTest {
assertTrue(mScanRequestProxy.getScanResults().isEmpty());
// Make scan request 2.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_2));
// Ensure that we did send a second scan request to scanner.
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Now send the scan results for request 2.
@@ -410,7 +414,7 @@ public class ScanRequestProxyTest {
@Test
public void testClearScanResults() {
// Make scan request 1.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
// Verify the scan results processing for request 1.
mScanListenerArgumentCaptor.getValue().onResults(mTestScanDatas1);
@@ -433,12 +437,12 @@ public class ScanRequestProxyTest {
WifiScanner.ScanListener listener1;
WifiScanner.ScanListener listener2;
// Make scan request 1.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_1));
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
listener1 = mScanListenerArgumentCaptor.getValue();
// Make scan request 2.
- assertTrue(mScanRequestProxy.startScan(TEST_UID));
+ assertTrue(mScanRequestProxy.startScan(TEST_UID, TEST_PACKAGE_NAME_2));
// Ensure that we did send a second scan request to scanner.
mInOrder.verify(mWifiScanner).startScan(any(), any(), any());
listener2 = mScanListenerArgumentCaptor.getValue();
@@ -448,6 +452,96 @@ public class ScanRequestProxyTest {
verifyNoMoreInteractions(mWifiScanner, mWifiConfigManager, mContext);
}
+ /**
+ * Ensure new scan requests from the same app are rejected if it's before
+ * {@link ScanRequestProxy#SCAN_REQUEST_THROTTLE_INTERVAL_MS}
+ */
+ @Test
+ public void testSuccessiveScanRequestFromSameAppThrottled() {
+ 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_MS - 1;
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(secondRequestMs);
+ // 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);
+
+ verifyNoMoreInteractions(mWifiScanner, mWifiConfigManager, mContext);
+ }
+
+ /**
+ * Ensure new scan requests from the same app are not rejected if it's after
+ * {@link ScanRequestProxy#SCAN_REQUEST_THROTTLE_INTERVAL_MS}
+ */
+ @Test
+ public void testSuccessiveScanRequestFromSameAppNotThrottled() {
+ 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_MS + 1;
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(secondRequestMs);
+ // Make scan request 2 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());
+
+ verifyNoMoreInteractions(mWifiScanner, mWifiConfigManager, mContext);
+ }
+
+ /**
+ * Ensure new scan requests from the same app with NETWORK_SETTINGS permission are not
+ * throttled.
+ */
+ @Test
+ public void testSuccessiveScanRequestFromSameAppWithNetworkSettingsPermissionNotThrottled() {
+ when(mWifiPermissionsUtil.checkNetworkSettingsPermission(TEST_UID)).thenReturn(true);
+
+ 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_MS - 1;
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(secondRequestMs);
+ // Make scan request 2 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());
+
+ verifyNoMoreInteractions(mWifiScanner, mWifiConfigManager, mContext);
+ }
+
+ /**
+ * Ensure new scan requests from different apps are not throttled.
+ */
+ @Test
+ public void testSuccessiveScanRequestFromDifferentAppsNotThrottled() {
+ 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());
+
+ // 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());
+
+ verifyNoMoreInteractions(mWifiScanner, mWifiConfigManager, mContext);
+ }
+
private void validateScanSettings(WifiScanner.ScanSettings scanSettings,
boolean expectHiddenNetworks) {
validateScanSettings(scanSettings, expectHiddenNetworks, false);
@@ -502,4 +596,21 @@ public class ScanRequestProxyTest {
boolean scanSucceeded = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
assertEquals(expectScanSuceeded, scanSucceeded);
}
+
+ private void validateScanResultsFailureBroadcastSent(String expectedPackageName) {
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ ArgumentCaptor<UserHandle> userHandleCaptor = ArgumentCaptor.forClass(UserHandle.class);
+ mInOrder.verify(mContext).sendBroadcastAsUser(
+ intentCaptor.capture(), userHandleCaptor.capture());
+
+ assertEquals(userHandleCaptor.getValue(), UserHandle.ALL);
+
+ Intent intent = intentCaptor.getValue();
+ assertEquals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION, intent.getAction());
+ assertEquals(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, intent.getFlags());
+ boolean scanSucceeded = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
+ assertFalse(scanSucceeded);
+ String packageName = intent.getPackage();
+ assertEquals(expectedPackageName, packageName);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index 6f99f5521..efd9b9fc0 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -89,7 +89,6 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.UserManager;
import android.os.test.TestLooper;
-import android.provider.Settings;
import android.support.test.filters.SmallTest;
import com.android.internal.os.PowerProfile;
@@ -126,9 +125,7 @@ public class WifiServiceImplTest {
private static final String TAG = "WifiServiceImplTest";
private static final String SCAN_PACKAGE_NAME = "scanPackage";
- private static final String WHITE_LIST_SCAN_PACKAGE_NAME = "whiteListScanPackage";
private static final int DEFAULT_VERBOSE_LOGGING = 0;
- private static final long WIFI_BACKGROUND_SCAN_INTERVAL = 10000;
private static final String ANDROID_SYSTEM_PACKAGE = "android";
private static final String TEST_PACKAGE_NAME = "TestPackage";
private static final String SYSUI_PACKAGE_NAME = "com.android.systemui";
@@ -286,15 +283,6 @@ public class WifiServiceImplTest {
anyBoolean(), any());
when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(mActivityManager);
when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
- when(mFrameworkFacade.getLongSetting(
- eq(mContext),
- eq(Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS),
- anyLong()))
- .thenReturn(WIFI_BACKGROUND_SCAN_INTERVAL);
- when(mFrameworkFacade.getStringSetting(
- eq(mContext),
- eq(Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST)))
- .thenReturn(WHITE_LIST_SCAN_PACKAGE_NAME);
IPowerManager powerManagerService = mock(IPowerManager.class);
mPowerManager = new PowerManager(mContext, powerManagerService, new Handler());
when(mContext.getSystemServiceName(PowerManager.class)).thenReturn(Context.POWER_SERVICE);
@@ -1029,80 +1017,6 @@ public class WifiServiceImplTest {
}
/**
- * Ensure foreground apps can always do wifi scans.
- */
- @Test
- public void testWifiScanStartedForeground() {
- setupWifiStateMachineHandlerForRunWithScissors();
-
- when(mActivityManager.getPackageImportance(SCAN_PACKAGE_NAME)).thenReturn(
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
- mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
- verify(mScanRequestProxy).startScan(Process.myUid());
- verifyCheckChangePermission(SCAN_PACKAGE_NAME);
- }
-
- /**
- * Ensure background apps get throttled when the previous scan is too close.
- */
- @Test
- public void testWifiScanBackgroundThrottled() {
- setupWifiStateMachineHandlerForRunWithScissors();
-
- when(mActivityManager.getPackageImportance(SCAN_PACKAGE_NAME)).thenReturn(
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED);
- long startMs = 1000;
- when(mClock.getElapsedSinceBootMillis()).thenReturn(startMs);
- mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
- verify(mScanRequestProxy).startScan(Process.myUid());
-
- when(mClock.getElapsedSinceBootMillis()).thenReturn(
- startMs + WIFI_BACKGROUND_SCAN_INTERVAL - 1000);
- mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
- verify(mScanRequestProxy, times(1)).startScan(Process.myUid());
- }
-
- /**
- * Ensure background apps can do wifi scan when the throttle interval reached.
- */
- @Test
- public void testWifiScanBackgroundNotThrottled() {
- setupWifiStateMachineHandlerForRunWithScissors();
-
- when(mActivityManager.getPackageImportance(SCAN_PACKAGE_NAME)).thenReturn(
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED);
- long startMs = 1000;
- when(mClock.getElapsedSinceBootMillis()).thenReturn(startMs);
- mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
- verify(mScanRequestProxy).startScan(Process.myUid());
-
- when(mClock.getElapsedSinceBootMillis()).thenReturn(
- startMs + WIFI_BACKGROUND_SCAN_INTERVAL + 1000);
- mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
- verify(mScanRequestProxy, times(2)).startScan(Process.myUid());
- }
-
- /**
- * Ensure background apps can do wifi scan when the throttle interval reached.
- */
- @Test
- public void testWifiScanBackgroundWhiteListed() {
- setupWifiStateMachineHandlerForRunWithScissors();
-
- when(mActivityManager.getPackageImportance(WHITE_LIST_SCAN_PACKAGE_NAME)).thenReturn(
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED);
- long startMs = 1000;
- when(mClock.getElapsedSinceBootMillis()).thenReturn(startMs);
- mWifiServiceImpl.startScan(null, null, WHITE_LIST_SCAN_PACKAGE_NAME);
- verify(mScanRequestProxy).startScan(Process.myUid());
-
- when(mClock.getElapsedSinceBootMillis()).thenReturn(
- startMs + WIFI_BACKGROUND_SCAN_INTERVAL - 1000);
- mWifiServiceImpl.startScan(null, null, WHITE_LIST_SCAN_PACKAGE_NAME);
- verify(mScanRequestProxy, times(2)).startScan(Process.myUid());
- }
-
- /**
* Ensure that we handle scan request failure when posting the runnable to handler fails.
*/
@Ignore
@@ -1111,11 +1025,8 @@ public class WifiServiceImplTest {
setupWifiStateMachineHandlerForRunWithScissors();
doReturn(false).when(mHandlerSpyForWsmRunWithScissors)
.runWithScissors(any(), anyLong());
-
- when(mActivityManager.getPackageImportance(SCAN_PACKAGE_NAME)).thenReturn(
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
- verify(mScanRequestProxy, never()).startScan(Process.myUid());
+ verify(mScanRequestProxy, never()).startScan(Process.myUid(), SCAN_PACKAGE_NAME);
}
static final String TEST_SSID = "Sid's Place";
@@ -2614,14 +2525,14 @@ public class WifiServiceImplTest {
// Send a scan request while the device is idle.
mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
// No scans must be made yet as the device is idle.
- verify(mScanRequestProxy, never()).startScan(Process.myUid());
+ verify(mScanRequestProxy, never()).startScan(Process.myUid(), SCAN_PACKAGE_NAME);
// Tell the wifi service that idle mode ended.
when(mPowerManager.isDeviceIdleMode()).thenReturn(false);
TestUtil.sendIdleModeChanged(mBroadcastReceiverCaptor.getValue(), mContext);
// Must scan now.
- verify(mScanRequestProxy, times(1)).startScan(Process.myUid());
+ verify(mScanRequestProxy).startScan(Process.myUid(), TEST_PACKAGE_NAME);
// The app ops check is executed with this package's identity (not the identity of the
// original remote caller who requested the scan while idle).
verify(mAppOpsManager).noteOp(
@@ -2630,7 +2541,7 @@ public class WifiServiceImplTest {
// Send another scan request. The device is not idle anymore, so it must be executed
// immediately.
mWifiServiceImpl.startScan(null, null, SCAN_PACKAGE_NAME);
- verify(mScanRequestProxy, times(2)).startScan(Process.myUid());
+ verify(mScanRequestProxy).startScan(Process.myUid(), SCAN_PACKAGE_NAME);
}
private class IdleModeIntentMatcher implements ArgumentMatcher<IntentFilter> {