From 46adcb39a183597343cc1184521c0684212e6c5e Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 7 Oct 2019 06:14:58 -0700 Subject: WifiNetworkFactory: Use the latest cached scan results Before starting scans for processing a network request, fetch the latest cached scan results to speed up the matching process. The cached scan results are filtered out to remove scan results that are older than 20 seconds. As long as there was a previous scan in the last 20 seconds, there are 2 benefits with this change: a) There is currently a delay of 2-3 seconds after the request where the user sees a blank screen when platform is performing the first scan. This can be avoided and we can present the user with matches immediately when the request is received. b) If the request is for a specific bssid and there is an approved match in the cached scan results, then we can bypass the UI and trigger connection. Also, renames "PreviouslyApproved" -> "Approved" in test name to ensure the test names fit in one line :) Bug: 134712530 Test: atest com.android.server.wifi Test: Manually verified with CtsVerifier tests that the UI does not start out with a blank page (because the matched networks are already found by using the cached results). Change-Id: I7a788777aabd11562077be88fcc4c9cd45e5b9ab Merged-In: I7a788777aabd11562077be88fcc4c9cd45e5b9ab (cherry-picked from 0ab35f26f0da8885a5d249a678187993da425447) --- .../android/server/wifi/WifiNetworkFactory.java | 113 ++++++++++++++------- 1 file changed, 78 insertions(+), 35 deletions(-) (limited to 'service') diff --git a/service/java/com/android/server/wifi/WifiNetworkFactory.java b/service/java/com/android/server/wifi/WifiNetworkFactory.java index 48797f773..be6ac6473 100644 --- a/service/java/com/android/server/wifi/WifiNetworkFactory.java +++ b/service/java/com/android/server/wifi/WifiNetworkFactory.java @@ -82,6 +82,8 @@ public class WifiNetworkFactory extends NetworkFactory { @VisibleForTesting private static final int SCORE_FILTER = 60; @VisibleForTesting + public static final int CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS = 20 * 1000; // 20 seconds + @VisibleForTesting public static final int PERIODIC_SCAN_INTERVAL_MS = 10 * 1000; // 10 seconds @VisibleForTesting public static final int NETWORK_CONNECTION_TIMEOUT_MS = 30 * 1000; // 30 seconds @@ -230,37 +232,10 @@ public class WifiNetworkFactory extends NetworkFactory { if (mVerboseLoggingEnabled) { Log.v(TAG, "Received " + scanResults.length + " scan results"); } - List matchedScanResults = - getNetworksMatchingActiveNetworkRequest(scanResults); - if (mActiveMatchedScanResults == null) { - // only note the first match size in metrics (chances of this changing in further - // scans is pretty low) - mWifiMetrics.incrementNetworkRequestApiMatchSizeHistogram( - matchedScanResults.size()); - } - mActiveMatchedScanResults = matchedScanResults; - - ScanResult approvedScanResult = null; - if (isActiveRequestForSingleAccessPoint()) { - approvedScanResult = - findUserApprovedAccessPointForActiveRequestFromActiveMatchedScanResults(); - } - if (approvedScanResult != null - && !mWifiConfigManager.wasEphemeralNetworkDeleted( - ScanResultUtil.createQuotedSSID(approvedScanResult.SSID))) { - Log.v(TAG, "Approved access point found in matching scan results. " - + "Triggering connect " + approvedScanResult); - handleConnectToNetworkUserSelectionInternal( - ScanResultUtil.createNetworkFromScanResult(approvedScanResult)); - mWifiMetrics.incrementNetworkRequestApiNumUserApprovalBypass(); - // TODO (b/122658039): Post notification. - } else { - if (mVerboseLoggingEnabled) { - Log.v(TAG, "No approved access points found in matching scan results. " - + "Sending match callback"); - } - sendNetworkRequestMatchCallbacksForActiveRequest(matchedScanResults); - // Didn't find an approved match, schedule the next scan. + if (!handleScanResultsAndTriggerConnectIfUserApprovedMatchFound(scanResults)) { + // Didn't find an approved match, send the matching results to UI and schedule the + // next scan. + sendNetworkRequestMatchCallbacksForActiveRequest(mActiveMatchedScanResults); scheduleNextPeriodicScan(); } } @@ -612,10 +587,19 @@ public class WifiNetworkFactory extends NetworkFactory { wns.requestorUid, wns.requestorPackageName); mWifiMetrics.incrementNetworkRequestApiNumRequest(); - // Start UI to let the user grant/disallow this request from the app. - startUi(); - // Trigger periodic scans for finding a network in the request. - startPeriodicScans(); + // Fetch the latest cached scan results to speed up network matching. + ScanResult[] cachedScanResults = getFilteredCachedScanResults(); + if (mVerboseLoggingEnabled) { + Log.v(TAG, "Using cached " + cachedScanResults.length + " scan results"); + } + if (!handleScanResultsAndTriggerConnectIfUserApprovedMatchFound(cachedScanResults)) { + // Start UI to let the user grant/disallow this request from the app. + startUi(); + // Didn't find an approved match, send the matching results to UI and trigger + // periodic scans for finding a network in the request. + sendNetworkRequestMatchCallbacksForActiveRequest(mActiveMatchedScanResults); + startPeriodicScans(); + } } } @@ -1330,6 +1314,65 @@ public class WifiNetworkFactory extends NetworkFactory { saveToStore(); } + /** + * Handle scan results + * a) Find all scan results matching the active network request. + * b) If the request is for a single bssid, check if the matching ScanResult was pre-approved + * by the user. + * c) If yes to (b), trigger a connect immediately and returns true. Else, returns false. + * + * @param scanResults Array of {@link ScanResult} to be processed. + * @return true if a pre-approved network was found for connection, false otherwise. + */ + private boolean handleScanResultsAndTriggerConnectIfUserApprovedMatchFound( + ScanResult[] scanResults) { + List matchedScanResults = + getNetworksMatchingActiveNetworkRequest(scanResults); + if ((mActiveMatchedScanResults == null || mActiveMatchedScanResults.isEmpty()) + && !matchedScanResults.isEmpty()) { + // only note the first match size in metrics (chances of this changing in further + // scans is pretty low) + mWifiMetrics.incrementNetworkRequestApiMatchSizeHistogram( + matchedScanResults.size()); + } + mActiveMatchedScanResults = matchedScanResults; + + ScanResult approvedScanResult = null; + if (isActiveRequestForSingleAccessPoint()) { + approvedScanResult = + findUserApprovedAccessPointForActiveRequestFromActiveMatchedScanResults(); + } + if (approvedScanResult != null + && !mWifiConfigManager.wasEphemeralNetworkDeleted( + ScanResultUtil.createQuotedSSID(approvedScanResult.SSID))) { + Log.v(TAG, "Approved access point found in matching scan results. " + + "Triggering connect " + approvedScanResult); + handleConnectToNetworkUserSelectionInternal( + ScanResultUtil.createNetworkFromScanResult(approvedScanResult)); + mWifiMetrics.incrementNetworkRequestApiNumUserApprovalBypass(); + return true; + } + if (mVerboseLoggingEnabled) { + Log.v(TAG, "No approved access points found in matching scan results"); + } + return false; + } + + /** + * Retrieve the latest cached scan results from wifi scanner and filter out any + * {@link ScanResult} older than {@link #CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS}. + */ + private @NonNull ScanResult[] getFilteredCachedScanResults() { + List cachedScanResults = mWifiScanner.getSingleScanResults(); + if (cachedScanResults == null || cachedScanResults.isEmpty()) return new ScanResult[0]; + long currentTimeInMillis = mClock.getElapsedSinceBootMillis(); + return cachedScanResults.stream() + .filter(scanResult + -> ((currentTimeInMillis - (scanResult.timestamp / 1000)) + < CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS)) + .toArray(ScanResult[]::new); + } + /** * Clean up least recently used Access Points if specified app reach the limit. */ -- cgit v1.2.3