From 46adcf3089bd54334d94c12c5564f47cf00e22e2 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 18 Apr 2018 20:18:38 +0900 Subject: [PATCH] Make sure getActiveNetwork is consistent with default callbacks Bug: 77737389 Test: runtest framework-net new test don't pass without the main code change, but they do with it Change-Id: I0cd83a935ab0b349aa47e065b830e5a43ab9a091 --- .../android/server/ConnectivityService.java | 30 +++++++++--- .../server/ConnectivityServiceTest.java | 49 +++++++++++++++++++ 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 569324a84f..9994462531 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -930,6 +930,15 @@ public class ConnectivityService extends IConnectivityManager.Stub deps); } + private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) { + final NetworkCapabilities netCap = new NetworkCapabilities(); + netCap.addCapability(NET_CAPABILITY_INTERNET); + netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED); + netCap.removeCapability(NET_CAPABILITY_NOT_VPN); + netCap.setSingleUid(uid); + return netCap; + } + private NetworkRequest createDefaultInternetRequestForTransport( int transportType, NetworkRequest.Type type) { NetworkCapabilities netCap = new NetworkCapabilities(); @@ -1182,12 +1191,20 @@ public class ConnectivityService extends IConnectivityManager.Stub int vpnNetId = NETID_UNSET; synchronized (mVpns) { final Vpn vpn = mVpns.get(user); + // TODO : now that capabilities contain the UID, the appliesToUid test should + // be removed as the satisfying test below should be enough. if (vpn != null && vpn.appliesToUid(uid)) vpnNetId = vpn.getNetId(); } NetworkAgentInfo nai; if (vpnNetId != NETID_UNSET) { nai = getNetworkAgentInfoForNetId(vpnNetId); - if (nai != null) return nai.network; + if (nai != null) { + final NetworkCapabilities requiredCaps = + createDefaultNetworkCapabilitiesForUid(uid); + if (requiredCaps.satisfiedByNetworkCapabilities(nai.networkCapabilities)) { + return nai.network; + } + } } nai = getDefaultNetwork(); if (nai != null @@ -1402,8 +1419,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions( NetworkCapabilities nc, int callerPid, int callerUid) { final NetworkCapabilities newNc = new NetworkCapabilities(nc); - if (!checkSettingsPermission(callerPid, callerUid)) newNc.setUids(null); - if (!checkSettingsPermission(callerPid, callerUid)) newNc.setSSID(null); + if (!checkSettingsPermission(callerPid, callerUid)) { + newNc.setUids(null); + newNc.setSSID(null); + } return newNc; } @@ -4305,8 +4324,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // the default network request. This allows callers to keep track of // the system default network. if (type == NetworkRequest.Type.TRACK_DEFAULT) { - networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities); - networkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN); + networkCapabilities = createDefaultNetworkCapabilitiesForUid(Binder.getCallingUid()); enforceAccessPermission(); } else { networkCapabilities = new NetworkCapabilities(networkCapabilities); @@ -4563,7 +4581,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated. private final NetworkRequest mDefaultRequest; - + // Request used to optionally keep mobile data active even when higher // priority networks like Wi-Fi are active. private final NetworkRequest mDefaultMobileDataRequest; diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index e722b2c4c9..5b73bbaa1c 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -4173,4 +4173,53 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(vpnNetworkCallback); mCm.unregisterNetworkCallback(defaultCallback); } + + @Test + public void testVpnWithAndWithoutInternet() { + final int uid = Process.myUid(); + + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultCallback); + defaultCallback.assertNoCallback(); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + + defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId); + vpnNetworkAgent.setUids(ranges); + vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */); + + defaultCallback.assertNoCallback(); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + vpnNetworkAgent.disconnect(); + defaultCallback.assertNoCallback(); + + vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId); + vpnNetworkAgent.setUids(ranges); + vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */); + defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + vpnNetworkAgent.disconnect(); + defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); + + vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId); + ranges.clear(); + vpnNetworkAgent.setUids(ranges); + + vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */); + defaultCallback.assertNoCallback(); + + mCm.unregisterNetworkCallback(defaultCallback); + } }