summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2019-01-16 10:57:13 -0800
committerRoshan Pius <rpius@google.com>2019-01-18 08:02:25 -0800
commit812bc06ef69c687f0a440449273ad78d46da15e0 (patch)
tree08e1e8e9c37f62b9d31cb6df1c0162f71ff156f6
parent768dcd10ef7113a7a91e8a3352cd491aee11c925 (diff)
downloadandroid_frameworks_opt_net_wifi-812bc06ef69c687f0a440449273ad78d46da15e0.tar.gz
android_frameworks_opt_net_wifi-812bc06ef69c687f0a440449273ad78d46da15e0.tar.bz2
android_frameworks_opt_net_wifi-812bc06ef69c687f0a440449273ad78d46da15e0.zip
WifiNetworkFactory: Allow user approval bypass
Whenever user approves a network for a request from an app, store the exact SSID + BSSID that the user approved. If the same app makes a network request for a specific SSID & BSSID which has been previously approved, then the device will immediately trigger connection bypassing the user approval phase. Also, added a method to remove all of the approvals for the app when the app is uninstalled & via shell commands (for ACTS testing). Bug: 122658039 Test: ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh Test: act.py -c wifi_manager.config -tb dut-name -tc WifiNetworkRequestTest Test: act.py -c wifi_manager.config -tb dut-name -tc WifiNetworkRequestTest:test_connect_to_wpa_psk_2g_which_is_already_approved Change-Id: I85b8c872f53d682d47477d067df347352d5aa2d9
-rw-r--r--service/java/com/android/server/wifi/ClientModeImpl.java8
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkFactory.java205
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java1
-rw-r--r--service/java/com/android/server/wifi/WifiShellCommand.java7
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java276
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java5
6 files changed, 492 insertions, 10 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 7906a7576..afd9b127a 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -22,6 +22,7 @@ import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
@@ -6030,6 +6031,13 @@ public class ClientModeImpl extends StateMachine {
}
/**
+ * Remove all approved access points from {@link WifiNetworkFactory} for the provided package.
+ */
+ public void removeNetworkRequestUserApprovedAccessPointsForApp(@NonNull String packageName) {
+ mNetworkFactory.removeUserApprovedAccessPointsForApp(packageName);
+ }
+
+ /**
* Gets the factory MAC address of wlan0 (station interface).
* @return String representation of the factory MAC address.
*/
diff --git a/service/java/com/android/server/wifi/WifiNetworkFactory.java b/service/java/com/android/server/wifi/WifiNetworkFactory.java
index 57d1635db..0552d2c90 100644
--- a/service/java/com/android/server/wifi/WifiNetworkFactory.java
+++ b/service/java/com/android/server/wifi/WifiNetworkFactory.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.wifi.util.NativeUtil.addEnclosingQuotes;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
@@ -41,6 +42,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.os.PatternMatcher;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -49,14 +51,21 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wifi.ScanResultMatchInfo.NetworkType;
import com.android.server.wifi.util.ExternalCallbackTracker;
+import com.android.server.wifi.util.ScanResultUtil;
import com.android.server.wifi.util.WifiPermissionsUtil;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.Set;
/**
@@ -96,6 +105,9 @@ public class WifiNetworkFactory extends NetworkFactory {
private final ConnectionTimeoutAlarmListener mConnectionTimeoutAlarmListener;
private final ExternalCallbackTracker<INetworkRequestMatchCallback> mRegisteredCallbacks;
private final Messenger mSrcMessenger;
+ // Store all user approved access points for apps.
+ // TODO(b/122658039): Persist this.
+ private final Map<String, Set<AccessPoint>> mUserApprovedAccessPointMap = new HashMap<>();
private WifiScanner mWifiScanner;
private int mGenericConnectionReqCount = 0;
@@ -117,6 +129,51 @@ public class WifiNetworkFactory extends NetworkFactory {
private boolean mIsPeriodicScanPaused = false;
private boolean mWifiEnabled = false;
+ /**
+ * Helper class to store an access point that the user previously approved for a specific app.
+ */
+ private static class AccessPoint {
+ public final String ssid;
+ public final MacAddress bssid;
+ public final @NetworkType int networkType;
+
+ AccessPoint(@NonNull String ssid, @NonNull MacAddress bssid, @NetworkType int networkType) {
+ this.ssid = ssid;
+ this.bssid = bssid;
+ this.networkType = networkType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ssid, bssid, networkType);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof AccessPoint)) {
+ return false;
+ }
+ AccessPoint other = (AccessPoint) obj;
+ return TextUtils.equals(this.ssid, other.ssid)
+ && Objects.equals(this.bssid, other.bssid)
+ && this.networkType == other.networkType;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("AccessPoint: ");
+ return sb.append(ssid)
+ .append(", ")
+ .append(bssid)
+ .append(", ")
+ .append(networkType)
+ .toString();
+ }
+ }
+
// Scan listener for scan requests.
private class NetworkFactoryScanListener implements WifiScanner.ScanListener {
@Override
@@ -152,11 +209,28 @@ public class WifiNetworkFactory extends NetworkFactory {
}
List<ScanResult> matchedScanResults =
getNetworksMatchingActiveNetworkRequest(scanResults);
- sendNetworkRequestMatchCallbacksForActiveRequest(matchedScanResults);
mActiveMatchedScanResults = matchedScanResults;
- // Didn't find a match, schedule the next scan.
- scheduleNextPeriodicScan();
+ ScanResult approvedScanResult = null;
+ if (isActiveRequestForSingleAccessPoint()) {
+ approvedScanResult =
+ findUserApprovedAccessPointForActiveRequestFromActiveMatchedScanResults();
+ }
+ if (approvedScanResult == null) {
+ 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.
+ scheduleNextPeriodicScan();
+ } else {
+ Log.v(TAG, "Approved access point found in matching scan results. "
+ + "Triggering connect " + approvedScanResult);
+ handleConnectToNetworkUserSelectionInternal(
+ ScanResultUtil.createNetworkFromScanResult(approvedScanResult));
+ // TODO (b/122658039): Post notification.
+ }
}
@Override
@@ -545,12 +619,7 @@ public class WifiNetworkFactory extends NetworkFactory {
scheduleConnectionTimeout();
}
- private void handleConnectToNetworkUserSelection(WifiConfiguration network) {
- Log.d(TAG, "User initiated connect to network: " + network.SSID);
-
- // Cancel the ongoing scans after user selection.
- cancelPeriodicScans();
-
+ private void handleConnectToNetworkUserSelectionInternal(WifiConfiguration network) {
// Disable Auto-join so that NetworkFactory can take control of the network connection.
mWifiConnectivityManager.setSpecificNetworkRequestInProgress(true);
@@ -563,6 +632,19 @@ public class WifiNetworkFactory extends NetworkFactory {
connectToNetwork(network);
}
+ private void handleConnectToNetworkUserSelection(WifiConfiguration network) {
+ Log.d(TAG, "User initiated connect to network: " + network.SSID);
+
+ // Cancel the ongoing scans after user selection.
+ cancelPeriodicScans();
+
+ // Trigger connection attempts.
+ handleConnectToNetworkUserSelectionInternal(network);
+
+ // Add the network to the approved access point map for the app.
+ addNetworkToUserApprovedAccessPointMap(network);
+ }
+
private void handleRejectUserSelection() {
Log.w(TAG, "User dismissed notification, cancelling " + mActiveSpecificNetworkRequest);
teardownForActiveRequest();
@@ -697,6 +779,7 @@ public class WifiNetworkFactory extends NetworkFactory {
mUserSelectedNetwork = null;
mUserSelectedNetworkConnectRetryCount = 0;
mIsPeriodicScanPaused = false;
+ mActiveMatchedScanResults = null;
// Cancel periodic scan, connection timeout alarm.
cancelPeriodicScans();
cancelConnectionTimeout();
@@ -915,5 +998,109 @@ public class WifiNetworkFactory extends NetworkFactory {
mContext.startActivityAsUser(intent,
UserHandle.getUserHandleForUid(requestorUid));
}
+
+ // Helper method to determine if the specifier does not contain any patterns and matches
+ // a single access point.
+ private boolean isActiveRequestForSingleAccessPoint() {
+ if (mActiveSpecificNetworkRequestSpecifier == null) return false;
+
+ if (mActiveSpecificNetworkRequestSpecifier.ssidPatternMatcher.getType()
+ != PatternMatcher.PATTERN_LITERAL) {
+ return false;
+ }
+ if (!Objects.equals(
+ mActiveSpecificNetworkRequestSpecifier.bssidPatternMatcher.second,
+ MacAddress.BROADCAST_ADDRESS)) {
+ return false;
+ }
+ return true;
+ }
+
+ private @Nullable ScanResult
+ findUserApprovedAccessPointForActiveRequestFromActiveMatchedScanResults() {
+ if (mActiveSpecificNetworkRequestSpecifier == null
+ || mActiveMatchedScanResults == null) return null;
+ String requestorPackageName = mContext.getPackageManager().getNameForUid(
+ mActiveSpecificNetworkRequestSpecifier.requestorUid);
+ Set<AccessPoint> approvedAccessPoints =
+ mUserApprovedAccessPointMap.get(requestorPackageName);
+ if (approvedAccessPoints == null) return null;
+ for (ScanResult scanResult : mActiveMatchedScanResults) {
+ ScanResultMatchInfo fromScanResult = ScanResultMatchInfo.fromScanResult(scanResult);
+ AccessPoint accessPoint =
+ new AccessPoint(scanResult.SSID,
+ MacAddress.fromString(scanResult.BSSID), fromScanResult.networkType);
+ if (approvedAccessPoints.contains(accessPoint)) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Found " + accessPoint
+ + " in user approved access point for " + requestorPackageName);
+ }
+ return scanResult;
+ }
+ }
+ return null;
+ }
+
+ // Helper method to store the all the BSSIDs matching the network from the matched scan results
+ private void addNetworkToUserApprovedAccessPointMap(@NonNull WifiConfiguration network) {
+ if (mActiveSpecificNetworkRequestSpecifier == null
+ || mActiveMatchedScanResults == null) return;
+ // Note: This hopefully is a list of size 1, because we want to store a 1:1 mapping
+ // from user selection and the AP that was approved. But, since we get a WifiConfiguration
+ // object representing an entire network from UI, we need to ensure that all the visible
+ // BSSIDs matching the original request and the selected network are stored.
+ Set<AccessPoint> newUserApprovedAccessPoints = new HashSet<>();
+ for (ScanResult scanResult : mActiveMatchedScanResults) {
+ ScanResultMatchInfo fromScanResult = ScanResultMatchInfo.fromScanResult(scanResult);
+ ScanResultMatchInfo fromWifiConfiguration =
+ ScanResultMatchInfo.fromWifiConfiguration(network);
+ if (fromScanResult.equals(fromWifiConfiguration)) {
+ AccessPoint approvedAccessPoint =
+ new AccessPoint(scanResult.SSID, MacAddress.fromString(scanResult.BSSID),
+ fromScanResult.networkType);
+ newUserApprovedAccessPoints.add(approvedAccessPoint);
+ }
+ }
+ String requestorPackageName = mContext.getPackageManager().getNameForUid(
+ mActiveSpecificNetworkRequestSpecifier.requestorUid);
+ Set<AccessPoint> approvedAccessPoints =
+ mUserApprovedAccessPointMap.get(requestorPackageName);
+ if (approvedAccessPoints == null) {
+ approvedAccessPoints = new HashSet<>();
+ mUserApprovedAccessPointMap.put(requestorPackageName, approvedAccessPoints);
+ }
+ approvedAccessPoints.addAll(newUserApprovedAccessPoints);
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Adding " + newUserApprovedAccessPoints
+ + " to user approved access point for " + requestorPackageName);
+ }
+ }
+
+ private String getSimplePackageName(@NonNull String origPackageName) {
+ // TODO (b/122658039): We could alternatively plumb the package name in the network
+ // specifier itself. getNameForUid is kind of messy for shared UIDs.
+ // getNameForUid (Stored in packageName) returns a concatenation of name
+ // and uid for shared UIDs ("name:uid").
+ if (!origPackageName.contains(":")) {
+ return origPackageName; // regular app not using shared UID.
+ }
+ // Separate the package name from the string for app using shared UID.
+ return origPackageName.substring(0, origPackageName.indexOf(":"));
+ }
+
+ /**
+ * Remove all user approved access points for the specified app.
+ */
+ public void removeUserApprovedAccessPointsForApp(@NonNull String packageName) {
+ Iterator<Map.Entry<String, Set<AccessPoint>>> iter =
+ mUserApprovedAccessPointMap.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry<String, Set<AccessPoint>> entry = iter.next();
+ if (packageName.equals(getSimplePackageName(entry.getKey()))) {
+ Log.i(TAG, "Removing all approved access points for " + packageName);
+ iter.remove();
+ }
+ }
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 9fe6b41f1..a92eff9f5 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -2628,6 +2628,7 @@ public class WifiServiceImpl extends BaseWifiService {
mScanRequestProxy.clearScanRequestTimestampsForApp(pkgName, uid);
// Remove all suggestions from the package.
mWifiNetworkSuggestionsManager.removeApp(pkgName);
+ mClientModeImpl.removeNetworkRequestUserApprovedAccessPointsForApp(pkgName);
});
}
}
diff --git a/service/java/com/android/server/wifi/WifiShellCommand.java b/service/java/com/android/server/wifi/WifiShellCommand.java
index 76682ff91..4e0f5b2d2 100644
--- a/service/java/com/android/server/wifi/WifiShellCommand.java
+++ b/service/java/com/android/server/wifi/WifiShellCommand.java
@@ -163,6 +163,11 @@ public class WifiShellCommand extends ShellCommand {
pw.println(hasUserApproved ? "yes" : "no");
return 0;
}
+ case "network-requests-remove-user-approved-access-points": {
+ String packageName = getNextArgRequired();
+ mClientModeImpl.removeNetworkRequestUserApprovedAccessPointsForApp(packageName);
+ return 0;
+ }
default:
return handleDefaultCommands(cmd);
}
@@ -204,6 +209,8 @@ public class WifiShellCommand extends ShellCommand {
pw.println(" Sets whether network suggestions from the app is approved or not.");
pw.println(" network-suggestions-has-user-approved <package name>");
pw.println(" Queries whether network suggestions from the app is approved or not.");
+ pw.println(" network-requests-remove-user-approved-access-points <package name>");
+ pw.println(" Removes all user approved network requests for the app.");
pw.println();
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
index 12c70533c..df0282c48 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
@@ -59,6 +59,7 @@ import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Pair;
+import com.android.server.wifi.util.ScanResultUtil;
import com.android.server.wifi.util.WifiPermissionsUtil;
import org.junit.After;
@@ -161,6 +162,7 @@ public class WifiNetworkFactoryTest {
// Setup with wifi on.
mWifiNetworkFactory.setWifiState(true);
+ mWifiNetworkFactory.enableVerboseLogging(1);
}
/**
@@ -1646,6 +1648,278 @@ public class WifiNetworkFactoryTest {
verify(mWifiScanner).startScan(any(), any(), any());
}
+ /**
+ * Verify the user approval bypass for a specific request for an access point that was already
+ * approved previously.
+ */
+ @Test
+ public void testNetworkSpecifierMatchSuccessUsingLiteralSsidAndBssidMatchPreviouslyApproved()
+ throws Exception {
+ setupScanData(SCAN_RESULT_TYPE_WPA_PSK,
+ TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4);
+
+ // 1. First request (no user approval bypass)
+ ScanResult matchingScanResult1 = mTestScanDatas[0].getResults()[0];
+ PatternMatcher ssidPatternMatch =
+ new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL);
+ Pair<MacAddress, MacAddress> bssidPatternMatch =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
+ ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+ mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback,
+ TEST_CALLBACK_IDENTIFIER);
+ verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration(
+ mNetworkRequestUserSelectionCallback.capture());
+ verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS);
+ ArgumentCaptor<List<ScanResult>> matchedScanResultsCaptor =
+ ArgumentCaptor.forClass(List.class);
+ verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture());
+ assertNotNull(matchedScanResultsCaptor.getValue());
+ validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult1);
+ // Now trigger user selection to the network.
+ mSelectedNetwork = ScanResultUtil.createNetworkFromScanResult(matchingScanResult1);
+ INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback =
+ mNetworkRequestUserSelectionCallback.getValue();
+ assertNotNull(networkRequestUserSelectionCallback);
+ networkRequestUserSelectionCallback.select(mSelectedNetwork);
+ mLooper.dispatchAll();
+
+ mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER);
+ reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager, mClientModeImpl);
+
+ // 2. Second request for the same access point (user approval bypass).
+ ScanResult matchingScanResult2 = matchingScanResult1;
+ ssidPatternMatch =
+ new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL);
+ bssidPatternMatch =
+ Pair.create(MacAddress.fromString(matchingScanResult2.BSSID),
+ MacAddress.BROADCAST_ADDRESS);
+ specifier = new WifiNetworkSpecifier(
+ ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+ mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback,
+ TEST_CALLBACK_IDENTIFIER);
+ // Trigger scan results & ensure we triggered a connect.
+ verify(mWifiScanner).startScan(any(), mScanListenerArgumentCaptor.capture(), any());
+ ScanListener scanListener = mScanListenerArgumentCaptor.getValue();
+ assertNotNull(scanListener);
+ scanListener.onResults(mTestScanDatas);
+
+ // Verify we did not trigger the match callback.
+ verify(mNetworkRequestMatchCallback, never()).onMatch(anyList());
+ // Verify that we sent a connection attempt to ClientModeImpl
+ verify(mClientModeImpl).sendMessage(any());
+ }
+
+ /**
+ * Verify that we don't bypass user approval for a specific request for an access point that was
+ * not approved previously.
+ */
+ @Test
+ public void testNetworkSpecifierMatchSuccessUsingLiteralSsidAndBssidMatchNotPreviouslyApproved()
+ throws Exception {
+ setupScanData(SCAN_RESULT_TYPE_WPA_PSK,
+ TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4);
+
+ // 1. First request (no user approval bypass)
+ ScanResult matchingScanResult1 = mTestScanDatas[0].getResults()[0];
+ PatternMatcher ssidPatternMatch =
+ new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL);
+ Pair<MacAddress, MacAddress> bssidPatternMatch =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
+ ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+ mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback,
+ TEST_CALLBACK_IDENTIFIER);
+ verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration(
+ mNetworkRequestUserSelectionCallback.capture());
+ verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS);
+ ArgumentCaptor<List<ScanResult>> matchedScanResultsCaptor =
+ ArgumentCaptor.forClass(List.class);
+ verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture());
+ assertNotNull(matchedScanResultsCaptor.getValue());
+ validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult1);
+ // Now trigger user selection to the network.
+ mSelectedNetwork = ScanResultUtil.createNetworkFromScanResult(matchingScanResult1);
+ INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback =
+ mNetworkRequestUserSelectionCallback.getValue();
+ assertNotNull(networkRequestUserSelectionCallback);
+ networkRequestUserSelectionCallback.select(mSelectedNetwork);
+ mLooper.dispatchAll();
+
+ mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER);
+ reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager, mClientModeImpl);
+
+ // 2. Second request for a different access point (but same network).
+ setupScanData(SCAN_RESULT_TYPE_WPA_PSK,
+ TEST_SSID_1, TEST_SSID_1, TEST_SSID_3, TEST_SSID_4);
+ ScanResult matchingScanResult2 = mTestScanDatas[0].getResults()[1];
+ ssidPatternMatch =
+ new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL);
+ bssidPatternMatch =
+ Pair.create(MacAddress.fromString(matchingScanResult2.BSSID),
+ MacAddress.BROADCAST_ADDRESS);
+ specifier = new WifiNetworkSpecifier(
+ ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+ mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback,
+ TEST_CALLBACK_IDENTIFIER);
+ verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS);
+ // Verify we triggered the match callback.
+ matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class);
+ verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture());
+ assertNotNull(matchedScanResultsCaptor.getValue());
+ validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult2);
+ // Verify that we did not send a connection attempt to ClientModeImpl.
+ verify(mClientModeImpl, never()).sendMessage(any());
+ }
+
+ /**
+ * Verify that we don't bypass user approval for a specific request for a network
+ * (not access point) that was approved previously.
+ */
+ @Test
+ public void testNetworkSpecifierMatchSuccessUsingLiteralSsidMatchPreviouslyApproved()
+ throws Exception {
+ setupScanData(SCAN_RESULT_TYPE_WPA_PSK,
+ TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4);
+
+ // 1. First request (no user approval bypass)
+ ScanResult matchingScanResult1 = mTestScanDatas[0].getResults()[0];
+ PatternMatcher ssidPatternMatch =
+ new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL);
+ Pair<MacAddress, MacAddress> bssidPatternMatch =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
+ ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+ mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback,
+ TEST_CALLBACK_IDENTIFIER);
+ verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration(
+ mNetworkRequestUserSelectionCallback.capture());
+ verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS);
+ ArgumentCaptor<List<ScanResult>> matchedScanResultsCaptor =
+ ArgumentCaptor.forClass(List.class);
+ verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture());
+ assertNotNull(matchedScanResultsCaptor.getValue());
+ validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult1);
+ // Now trigger user selection to the network.
+ mSelectedNetwork = ScanResultUtil.createNetworkFromScanResult(matchingScanResult1);
+ INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback =
+ mNetworkRequestUserSelectionCallback.getValue();
+ assertNotNull(networkRequestUserSelectionCallback);
+ networkRequestUserSelectionCallback.select(mSelectedNetwork);
+ mLooper.dispatchAll();
+
+ mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER);
+ reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager, mClientModeImpl);
+
+ // 2. Second request for the same network (but not specific access point)
+ ScanResult matchingScanResult2 = matchingScanResult1;
+ ssidPatternMatch =
+ new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL);
+ // match-all.
+ bssidPatternMatch =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ specifier = new WifiNetworkSpecifier(
+ ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+ mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback,
+ TEST_CALLBACK_IDENTIFIER);
+ verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS);
+ // Verify we triggered the match callback.
+ matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class);
+ verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture());
+ assertNotNull(matchedScanResultsCaptor.getValue());
+ validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult2);
+ // Verify that we did not send a connection attempt to ClientModeImpl.
+ verify(mClientModeImpl, never()).sendMessage(any());
+ }
+
+ /**
+ * Verify the we don't bypass user approval for a specific request for an access point that was
+ * already approved previously, but was then removed (app uninstalled, user deleted it from
+ * notification, from tests, etc).
+ */
+ @Test
+ public void testNetworkSpecifierMatchSuccessUsingLiteralSsidAndBssidMatchAfterApprovalsRemove()
+ throws Exception {
+ setupScanData(SCAN_RESULT_TYPE_WPA_PSK,
+ TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4);
+
+ // 1. First request (no user approval bypass)
+ ScanResult matchingScanResult1 = mTestScanDatas[0].getResults()[0];
+ PatternMatcher ssidPatternMatch =
+ new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL);
+ Pair<MacAddress, MacAddress> bssidPatternMatch =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier specifier = new WifiNetworkSpecifier(
+ ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+ mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback,
+ TEST_CALLBACK_IDENTIFIER);
+ verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration(
+ mNetworkRequestUserSelectionCallback.capture());
+ verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS);
+ ArgumentCaptor<List<ScanResult>> matchedScanResultsCaptor =
+ ArgumentCaptor.forClass(List.class);
+ verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture());
+ assertNotNull(matchedScanResultsCaptor.getValue());
+ validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult1);
+ // Now trigger user selection to the network.
+ mSelectedNetwork = ScanResultUtil.createNetworkFromScanResult(matchingScanResult1);
+ INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback =
+ mNetworkRequestUserSelectionCallback.getValue();
+ assertNotNull(networkRequestUserSelectionCallback);
+ networkRequestUserSelectionCallback.select(mSelectedNetwork);
+ mLooper.dispatchAll();
+
+ mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER);
+ reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager, mClientModeImpl);
+
+ // 2. Remove all approvals for the app.
+ mWifiNetworkFactory.removeUserApprovedAccessPointsForApp(TEST_PACKAGE_NAME_1);
+
+ // 3. Second request for the same access point
+ ScanResult matchingScanResult2 = matchingScanResult1;
+ ssidPatternMatch =
+ new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL);
+ bssidPatternMatch =
+ Pair.create(MacAddress.fromString(matchingScanResult2.BSSID),
+ MacAddress.ALL_ZEROS_ADDRESS);
+ specifier = new WifiNetworkSpecifier(
+ ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+ mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback,
+ TEST_CALLBACK_IDENTIFIER);
+ verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS);
+ // Verify we triggered the match callback.
+ matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class);
+ verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture());
+ assertNotNull(matchedScanResultsCaptor.getValue());
+ validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult2);
+ // Verify that we did not send a connection attempt to ClientModeImpl.
+ verify(mClientModeImpl, never()).sendMessage(any());
+ }
+
private Messenger sendNetworkRequestAndSetupForConnectionStatus() throws RemoteException {
return sendNetworkRequestAndSetupForConnectionStatus(TEST_SSID_1);
}
@@ -1756,7 +2030,7 @@ public class WifiNetworkFactoryTest {
assertNotNull(alarmListener);
}
- verifyNoMoreInteractions(mWifiScanner, mAlarmManager);
+ mInOrder.verifyNoMoreInteractions();
}
private WifiNetworkSpecifier createWifiNetworkSpecifier(int uid, boolean isHidden) {
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index 0a683fed2..e73d2219e 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -2734,6 +2734,7 @@ public class WifiServiceImplTest {
mLooper.dispatchAll();
verify(mScanRequestProxy).clearScanRequestTimestampsForApp(packageName, uid);
verify(mWifiNetworkSuggestionsManager).removeApp(packageName);
+ verify(mClientModeImpl).removeNetworkRequestUserApprovedAccessPointsForApp(packageName);
}
@Test
@@ -2755,6 +2756,8 @@ public class WifiServiceImplTest {
mLooper.dispatchAll();
verify(mScanRequestProxy, never()).clearScanRequestTimestampsForApp(anyString(), anyInt());
verify(mWifiNetworkSuggestionsManager, never()).removeApp(anyString());
+ verify(mClientModeImpl, never()).removeNetworkRequestUserApprovedAccessPointsForApp(
+ packageName);
}
@Test
@@ -2776,6 +2779,8 @@ public class WifiServiceImplTest {
mLooper.dispatchAll();
verify(mScanRequestProxy, never()).clearScanRequestTimestampsForApp(anyString(), anyInt());
verify(mWifiNetworkSuggestionsManager, never()).removeApp(anyString());
+ verify(mClientModeImpl, never()).removeNetworkRequestUserApprovedAccessPointsForApp(
+ anyString());
}
@Test