diff options
3 files changed, 114 insertions, 23 deletions
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 35fd64c5e..646b7a014 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.AppOpsManager; +import android.companion.CompanionDeviceManager; import android.content.Context; import android.net.IpMemoryStore; import android.net.NetworkCapabilities; @@ -624,6 +625,7 @@ public class WifiInjector { (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE), (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE), (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE), + mContext.getSystemService(CompanionDeviceManager.class), mClock, this, wifiConnectivityManager, mWifiConfigManager, mWifiConfigStore, mWifiPermissionsUtil, mWifiMetrics); } diff --git a/service/java/com/android/server/wifi/WifiNetworkFactory.java b/service/java/com/android/server/wifi/WifiNetworkFactory.java index 8d3072fe8..8bb87c65c 100644 --- a/service/java/com/android/server/wifi/WifiNetworkFactory.java +++ b/service/java/com/android/server/wifi/WifiNetworkFactory.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.AppOpsManager; +import android.companion.CompanionDeviceManager; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -55,6 +56,7 @@ import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.server.wifi.proto.nano.WifiMetricsProto; import com.android.server.wifi.util.ExternalCallbackTracker; import com.android.server.wifi.util.ScanResultUtil; @@ -107,6 +109,7 @@ public class WifiNetworkFactory extends NetworkFactory { private final ActivityManager mActivityManager; private final AlarmManager mAlarmManager; private final AppOpsManager mAppOpsManager; + private final CompanionDeviceManager mCompanionDeviceManager; private final Clock mClock; private final Handler mHandler; private final WifiInjector mWifiInjector; @@ -343,6 +346,7 @@ public class WifiNetworkFactory extends NetworkFactory { public WifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc, ActivityManager activityManager, AlarmManager alarmManager, AppOpsManager appOpsManager, + CompanionDeviceManager companionDeviceManager, Clock clock, WifiInjector wifiInjector, WifiConnectivityManager connectivityManager, WifiConfigManager configManager, @@ -354,6 +358,7 @@ public class WifiNetworkFactory extends NetworkFactory { mActivityManager = activityManager; mAlarmManager = alarmManager; mAppOpsManager = appOpsManager; + mCompanionDeviceManager = companionDeviceManager; mClock = clock; mHandler = new Handler(looper); mWifiInjector = wifiInjector; @@ -1245,30 +1250,61 @@ public class WifiNetworkFactory extends NetworkFactory { return selectedScanResult.BSSID; } + private boolean isAccessPointApprovedInInternalApprovalList( + @NonNull ScanResult scanResult, @NonNull String requestorPackageName) { + Set<AccessPoint> approvedAccessPoints = + mUserApprovedAccessPointMap.get(requestorPackageName); + if (approvedAccessPoints == null) return false; + ScanResultMatchInfo fromScanResult = ScanResultMatchInfo.fromScanResult(scanResult); + AccessPoint accessPoint = + new AccessPoint(scanResult.SSID, + MacAddress.fromString(scanResult.BSSID), fromScanResult.networkType); + if (!approvedAccessPoints.contains(accessPoint)) return false; + // keep the most recently used AP in the end + approvedAccessPoints.remove(accessPoint); + approvedAccessPoints.add(accessPoint); + if (mVerboseLoggingEnabled) { + Log.v(TAG, "Found " + scanResult + + " in internal user approved access point for " + requestorPackageName); + } + return true; + } + + private boolean isAccessPointApprovedInCompanionDeviceManager( + @NonNull ScanResult scanResult, @NonNull UserHandle requestorUserHandle, + @NonNull String requestorPackageName) { + boolean approved = mCompanionDeviceManager.isDeviceAssociated( + requestorPackageName, MacAddress.fromString(scanResult.BSSID), requestorUserHandle); + if (!approved) return false; + if (mVerboseLoggingEnabled) { + Log.v(TAG, "Found " + scanResult + + " in CDM user approved access point for " + requestorPackageName); + } + return true; + } + private @Nullable ScanResult findUserApprovedAccessPointForActiveRequestFromActiveMatchedScanResults() { if (mActiveSpecificNetworkRequestSpecifier == null - || mActiveMatchedScanResults == null) return null; - String requestorPackageName = mActiveSpecificNetworkRequestSpecifier.requestorPackageName; - 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)) { - // keep the most recently used AP in the end - approvedAccessPoints.remove(accessPoint); - approvedAccessPoints.add(accessPoint); - if (mVerboseLoggingEnabled) { - Log.v(TAG, "Found " + accessPoint - + " in user approved access point for " + requestorPackageName); - } - return scanResult; - } + || ArrayUtils.size(mActiveMatchedScanResults) != 1) { + return null; } + // There should only 1 matched scan result since the request contains a specific + // SSID + BSSID mentioned. + ScanResult scanResult = mActiveMatchedScanResults.get(0); + String requestorPackageName = mActiveSpecificNetworkRequestSpecifier.requestorPackageName; + UserHandle requestorUserHandle = + UserHandle.getUserHandleForUid(mActiveSpecificNetworkRequestSpecifier.requestorUid); + // Check if access point is approved via CDM first. + if (isAccessPointApprovedInCompanionDeviceManager( + scanResult, requestorUserHandle, requestorPackageName)) { + return scanResult; + } + // Check if access point is approved in internal approval list next. + if (isAccessPointApprovedInInternalApprovalList(scanResult, requestorPackageName)) { + return scanResult; + } + // no bypass approvals, show UI. return null; } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java index f7cd39c43..b2f74f68f 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java @@ -32,6 +32,7 @@ import android.app.ActivityManager; import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; import android.app.AppOpsManager; +import android.companion.CompanionDeviceManager; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -124,6 +125,7 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { @Mock ActivityManager mActivityManager; @Mock AlarmManager mAlarmManager; @Mock AppOpsManager mAppOpsManager; + @Mock CompanionDeviceManager mCompanionDeviceManager; @Mock Clock mClock; @Mock WifiInjector mWifiInjector; @Mock WifiConnectivityManager mWifiConnectivityManager; @@ -194,9 +196,9 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { when(mWifiScanner.getSingleScanResults()).thenReturn(Collections.emptyList()); mWifiNetworkFactory = new WifiNetworkFactory(mLooper.getLooper(), mContext, - mNetworkCapabilities, mActivityManager, mAlarmManager, mAppOpsManager, mClock, - mWifiInjector, mWifiConnectivityManager, mWifiConfigManager, mWifiConfigStore, - mWifiPermissionsUtil, mWifiMetrics); + mNetworkCapabilities, mActivityManager, mAlarmManager, mAppOpsManager, + mCompanionDeviceManager, mClock, mWifiInjector, mWifiConnectivityManager, + mWifiConfigManager, mWifiConfigStore, mWifiPermissionsUtil, mWifiMetrics); ArgumentCaptor<NetworkRequestStoreData.DataSource> dataSourceArgumentCaptor = ArgumentCaptor.forClass(NetworkRequestStoreData.DataSource.class); @@ -2470,6 +2472,57 @@ public class WifiNetworkFactoryTest extends WifiBaseTest { /** * Verify the user approval bypass for a specific request for an access point that was already + * approved previously via CDM and the scan result is present in the cached scan results. + */ + @Test + public void + testNetworkSpecifierMatchSuccessUsingLiteralSsidAndBssidMatchApprovedViaCDMWithCache() + throws Exception { + // Setup scan data for WPA-PSK networks. + setupScanData(SCAN_RESULT_TYPE_WPA_PSK, + TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4); + + // Choose the matching scan result. + ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; + + // Setup CDM approval for the scan result. + when(mCompanionDeviceManager.isDeviceAssociated( + TEST_PACKAGE_NAME_1, + MacAddress.fromString(matchingScanResult.BSSID), + UserHandle.getUserHandleForUid(TEST_UID_1))).thenReturn(true); + + // simulate no cache expiry + when(mClock.getElapsedSinceBootMillis()).thenReturn(0L); + // Simulate the cached results matching. + when(mWifiScanner.getSingleScanResults()) + .thenReturn(Arrays.asList(mTestScanDatas[0].getResults())); + + PatternMatcher ssidPatternMatch = + new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); + Pair<MacAddress, MacAddress> bssidPatternMatch = + Pair.create(MacAddress.fromString(matchingScanResult.BSSID), + MacAddress.BROADCAST_ADDRESS); + WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( + ssidPatternMatch, bssidPatternMatch, + WifiConfigurationTestUtil.createPskNetwork(), TEST_UID_1, TEST_PACKAGE_NAME_1); + mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); + mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); + + // Verify we did not trigger the UI for the second request. + verify(mContext, never()).startActivityAsUser(any(), any()); + // Verify we did not trigger a scan. + verify(mWifiScanner, never()).startScan(any(), any(), any()); + // Verify we did not trigger the match callback. + verify(mNetworkRequestMatchCallback, never()).onMatch(anyList()); + // Verify that we sent a connection attempt to ClientModeImpl + verify(mClientModeImpl).connect(eq(null), anyInt(), + any(Binder.class), mConnectListenerArgumentCaptor.capture(), anyInt(), anyInt()); + + verify(mWifiMetrics).incrementNetworkRequestApiNumUserApprovalBypass(); + } + + /** + * Verify the user approval bypass for a specific request for an access point that was already * approved previously and the scan result is present in the cached scan results, but the * results are stale. */ |