Merge "Match underlying networks based on interface name"

This commit is contained in:
Benedict Wong
2023-03-27 18:02:03 +00:00
committed by Gerrit Code Review
2 changed files with 80 additions and 20 deletions

View File

@@ -1104,7 +1104,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
final NetworkCapabilities result = ncBuilder.build(); final NetworkCapabilities result = ncBuilder.build();
final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy( final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy(
mTrackingNetworkCallback mTrackingNetworkCallback
.requiresRestartForImmutableCapabilityChanges(result), .requiresRestartForImmutableCapabilityChanges(result, linkProperties),
result); result);
logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities
@@ -1354,19 +1354,29 @@ public class VcnManagementService extends IVcnManagementService.Stub {
* without requiring a Network restart. * without requiring a Network restart.
*/ */
private class TrackingNetworkCallback extends ConnectivityManager.NetworkCallback { private class TrackingNetworkCallback extends ConnectivityManager.NetworkCallback {
private final Object mLockObject = new Object();
private final Map<Network, NetworkCapabilities> mCaps = new ArrayMap<>(); private final Map<Network, NetworkCapabilities> mCaps = new ArrayMap<>();
private final Map<Network, LinkProperties> mLinkProperties = new ArrayMap<>();
@Override @Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities caps) { public void onCapabilitiesChanged(Network network, NetworkCapabilities caps) {
synchronized (mCaps) { synchronized (mLockObject) {
mCaps.put(network, caps); mCaps.put(network, caps);
} }
} }
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
synchronized (mLockObject) {
mLinkProperties.put(network, lp);
}
}
@Override @Override
public void onLost(Network network) { public void onLost(Network network) {
synchronized (mCaps) { synchronized (mLockObject) {
mCaps.remove(network); mCaps.remove(network);
mLinkProperties.remove(network);
} }
} }
@@ -1393,22 +1403,28 @@ public class VcnManagementService extends IVcnManagementService.Stub {
return true; return true;
} }
private boolean requiresRestartForImmutableCapabilityChanges(NetworkCapabilities caps) { private boolean requiresRestartForImmutableCapabilityChanges(
NetworkCapabilities caps, LinkProperties lp) {
if (caps.getSubscriptionIds() == null) { if (caps.getSubscriptionIds() == null) {
return false; return false;
} }
synchronized (mCaps) { synchronized (mLockObject) {
for (NetworkCapabilities existing : mCaps.values()) { // Search for an existing network (using interfce names)
if (caps.getSubscriptionIds().equals(existing.getSubscriptionIds()) // TODO: Get network from NetworkFactory (if exists) for this match.
&& hasSameTransportsAndCapabilities(caps, existing)) { for (Entry<Network, LinkProperties> lpEntry : mLinkProperties.entrySet()) {
// Restart if any immutable capabilities have changed if (lp.getInterfaceName() != null
return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) && !lp.getInterfaceName().isEmpty()
&& Objects.equals(
lp.getInterfaceName(), lpEntry.getValue().getInterfaceName())) {
return mCaps.get(lpEntry.getKey())
.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
!= caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED); != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED);
} }
} }
} }
// If no network found, by definition does not need restart.
return false; return false;
} }

View File

@@ -17,7 +17,9 @@
package com.android.server; package com.android.server;
import static android.net.ConnectivityManager.NetworkCallback; import static android.net.ConnectivityManager.NetworkCallback;
import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -67,7 +69,6 @@ import android.net.LinkProperties;
import android.net.Network; import android.net.Network;
import android.net.NetworkCapabilities; import android.net.NetworkCapabilities;
import android.net.NetworkRequest; import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
import android.net.Uri; import android.net.Uri;
import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
@@ -128,6 +129,15 @@ public class VcnManagementServiceTest {
private static final VcnConfig TEST_VCN_CONFIG; private static final VcnConfig TEST_VCN_CONFIG;
private static final VcnConfig TEST_VCN_CONFIG_PKG_2; private static final VcnConfig TEST_VCN_CONFIG_PKG_2;
private static final int TEST_UID = Process.FIRST_APPLICATION_UID; private static final int TEST_UID = Process.FIRST_APPLICATION_UID;
private static final String TEST_IFACE_NAME = "TEST_IFACE";
private static final String TEST_IFACE_NAME_2 = "TEST_IFACE2";
private static final LinkProperties TEST_LP_1 = new LinkProperties();
private static final LinkProperties TEST_LP_2 = new LinkProperties();
static {
TEST_LP_1.setInterfaceName(TEST_IFACE_NAME);
TEST_LP_2.setInterfaceName(TEST_IFACE_NAME_2);
}
static { static {
final Context mockConfigContext = mock(Context.class); final Context mockConfigContext = mock(Context.class);
@@ -1034,8 +1044,7 @@ public class VcnManagementServiceTest {
setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive); setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
return mVcnMgmtSvc.getUnderlyingNetworkPolicy( return mVcnMgmtSvc.getUnderlyingNetworkPolicy(
getNetworkCapabilitiesBuilderForTransport(subId, transport).build(), getNetworkCapabilitiesBuilderForTransport(subId, transport).build(), TEST_LP_1);
new LinkProperties());
} }
private void checkGetRestrictedTransportsFromCarrierConfig( private void checkGetRestrictedTransportsFromCarrierConfig(
@@ -1260,7 +1269,7 @@ public class VcnManagementServiceTest {
false /* expectRestricted */); false /* expectRestricted */);
} }
private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) { private void setupTrackedNetwork(NetworkCapabilities caps, LinkProperties lp) {
mVcnMgmtSvc.systemReady(); mVcnMgmtSvc.systemReady();
final ArgumentCaptor<NetworkCallback> captor = final ArgumentCaptor<NetworkCallback> captor =
@@ -1269,7 +1278,10 @@ public class VcnManagementServiceTest {
.registerNetworkCallback( .registerNetworkCallback(
eq(new NetworkRequest.Builder().clearCapabilities().build()), eq(new NetworkRequest.Builder().clearCapabilities().build()),
captor.capture()); captor.capture());
captor.getValue().onCapabilitiesChanged(mock(Network.class, CALLS_REAL_METHODS), caps);
Network mockNetwork = mock(Network.class, CALLS_REAL_METHODS);
captor.getValue().onCapabilitiesChanged(mockNetwork, caps);
captor.getValue().onLinkPropertiesChanged(mockNetwork, lp);
} }
@Test @Test
@@ -1279,7 +1291,7 @@ public class VcnManagementServiceTest {
getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
.removeCapability(NET_CAPABILITY_NOT_RESTRICTED) .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
.build(); .build();
setupTrackedCarrierWifiNetwork(existingNetworkCaps); setupTrackedNetwork(existingNetworkCaps, TEST_LP_1);
// Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED
// immutable capability // immutable capability
@@ -1288,7 +1300,7 @@ public class VcnManagementServiceTest {
getNetworkCapabilitiesBuilderForTransport( getNetworkCapabilitiesBuilderForTransport(
TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
.build(), .build(),
new LinkProperties()); TEST_LP_1);
assertTrue(policy.isTeardownRequested()); assertTrue(policy.isTeardownRequested());
} }
@@ -1298,7 +1310,7 @@ public class VcnManagementServiceTest {
final NetworkCapabilities existingNetworkCaps = final NetworkCapabilities existingNetworkCaps =
getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI) getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
.build(); .build();
setupTrackedCarrierWifiNetwork(existingNetworkCaps); setupTrackedNetwork(existingNetworkCaps, TEST_LP_1);
final VcnUnderlyingNetworkPolicy policy = final VcnUnderlyingNetworkPolicy policy =
startVcnAndGetPolicyForTransport( startVcnAndGetPolicyForTransport(
@@ -1315,7 +1327,7 @@ public class VcnManagementServiceTest {
.addCapability(NET_CAPABILITY_NOT_RESTRICTED) .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
.removeCapability(NET_CAPABILITY_IMS) .removeCapability(NET_CAPABILITY_IMS)
.build(); .build();
setupTrackedCarrierWifiNetwork(existingNetworkCaps); setupTrackedNetwork(existingNetworkCaps, TEST_LP_1);
final VcnUnderlyingNetworkPolicy policy = final VcnUnderlyingNetworkPolicy policy =
mVcnMgmtSvc.getUnderlyingNetworkPolicy( mVcnMgmtSvc.getUnderlyingNetworkPolicy(
@@ -1336,7 +1348,7 @@ public class VcnManagementServiceTest {
new NetworkCapabilities.Builder() new NetworkCapabilities.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_2)) .setSubscriptionIds(Collections.singleton(TEST_SUBSCRIPTION_ID_2))
.build(); .build();
VcnUnderlyingNetworkPolicy policy = VcnUnderlyingNetworkPolicy policy =
@@ -1346,6 +1358,38 @@ public class VcnManagementServiceTest {
assertEquals(nc, policy.getMergedNetworkCapabilities()); assertEquals(nc, policy.getMergedNetworkCapabilities());
} }
/**
* Checks that networks with similar capabilities do not clobber each other.
*
* <p>In previous iterations, the VcnMgmtSvc used capability-matching to check if a network
* undergoing policy checks were the same as an existing networks. However, this meant that if
* there were newly added capabilities that the VCN did not check, two networks differing only
* by that capability would restart each other constantly.
*/
@Test
public void testGetUnderlyingNetworkPolicySimilarNetworks() throws Exception {
NetworkCapabilities nc1 =
new NetworkCapabilities.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.addCapability(NET_CAPABILITY_INTERNET)
.setSubscriptionIds(Collections.singleton(TEST_SUBSCRIPTION_ID_2))
.build();
NetworkCapabilities nc2 =
new NetworkCapabilities.Builder(nc1)
.addCapability(NET_CAPABILITY_ENTERPRISE)
.removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
.build();
setupTrackedNetwork(nc1, TEST_LP_1);
VcnUnderlyingNetworkPolicy policy = mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc2, TEST_LP_2);
assertFalse(policy.isTeardownRequested());
assertEquals(nc2, policy.getMergedNetworkCapabilities());
}
@Test(expected = SecurityException.class) @Test(expected = SecurityException.class)
public void testGetUnderlyingNetworkPolicyInvalidPermission() { public void testGetUnderlyingNetworkPolicyInvalidPermission() {
doReturn(PackageManager.PERMISSION_DENIED) doReturn(PackageManager.PERMISSION_DENIED)