[VCN07] Bypass VCN for non-internet app accessible cellular services

Deduce the NET_CAPABILITY_NOT_VCN_MANAGED capability from other
capabilities and user intention, which includes:
   1. For the requests that don't have anything besides
      VCN_SUPPORTED_CAPABILITIES, add the NOT_VCN_MANAGED to
      allow the callers automatically utilize VCN networks
      if available.
   2. For the requests that explicitly add or remove
      NOT_VCN_MANAGED,  do not alter them to allow user fire
      request that suits their need.

Test: atest NetworkRequestTest#testBypassingVcnForNonInternetRequest
Bug: 175662146
Change-Id: I9936894b9530a22fb186cfd25cbee0fced65b72b
This commit is contained in:
junyulai
2021-01-13 18:13:11 +08:00
parent ab4b0cdccc
commit 2fc40da076
4 changed files with 84 additions and 9 deletions

View File

@@ -16,6 +16,22 @@
package android.net; package android.net;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
@@ -30,6 +46,8 @@ import android.os.Process;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@@ -156,8 +174,30 @@ public class NetworkRequest implements Parcelable {
* needed in terms of {@link NetworkCapabilities} features * needed in terms of {@link NetworkCapabilities} features
*/ */
public static class Builder { public static class Builder {
/**
* Capabilities that are currently compatible with VCN networks.
*/
private static final List<Integer> VCN_SUPPORTED_CAPABILITIES = Arrays.asList(
NET_CAPABILITY_CAPTIVE_PORTAL,
NET_CAPABILITY_DUN,
NET_CAPABILITY_FOREGROUND,
NET_CAPABILITY_INTERNET,
NET_CAPABILITY_NOT_CONGESTED,
NET_CAPABILITY_NOT_METERED,
NET_CAPABILITY_NOT_RESTRICTED,
NET_CAPABILITY_NOT_ROAMING,
NET_CAPABILITY_NOT_SUSPENDED,
NET_CAPABILITY_NOT_VPN,
NET_CAPABILITY_PARTIAL_CONNECTIVITY,
NET_CAPABILITY_TEMPORARILY_NOT_METERED,
NET_CAPABILITY_TRUSTED,
NET_CAPABILITY_VALIDATED);
private final NetworkCapabilities mNetworkCapabilities; private final NetworkCapabilities mNetworkCapabilities;
// A boolean that represents the user modified NOT_VCN_MANAGED capability.
private boolean mModifiedNotVcnManaged = false;
/** /**
* Default constructor for Builder. * Default constructor for Builder.
*/ */
@@ -179,6 +219,7 @@ public class NetworkRequest implements Parcelable {
// maybeMarkCapabilitiesRestricted() doesn't add back. // maybeMarkCapabilitiesRestricted() doesn't add back.
final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities); final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
nc.maybeMarkCapabilitiesRestricted(); nc.maybeMarkCapabilitiesRestricted();
deduceNotVcnManagedCapability(nc);
return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE, return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
ConnectivityManager.REQUEST_ID_UNSET, Type.NONE); ConnectivityManager.REQUEST_ID_UNSET, Type.NONE);
} }
@@ -195,6 +236,9 @@ public class NetworkRequest implements Parcelable {
*/ */
public Builder addCapability(@NetworkCapabilities.NetCapability int capability) { public Builder addCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addCapability(capability); mNetworkCapabilities.addCapability(capability);
if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
mModifiedNotVcnManaged = true;
}
return this; return this;
} }
@@ -206,6 +250,9 @@ public class NetworkRequest implements Parcelable {
*/ */
public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) { public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.removeCapability(capability); mNetworkCapabilities.removeCapability(capability);
if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
mModifiedNotVcnManaged = true;
}
return this; return this;
} }
@@ -263,6 +310,9 @@ public class NetworkRequest implements Parcelable {
@NonNull @NonNull
public Builder clearCapabilities() { public Builder clearCapabilities() {
mNetworkCapabilities.clearAll(); mNetworkCapabilities.clearAll();
// If the caller explicitly clear all capabilities, the NOT_VCN_MANAGED capabilities
// should not be add back later.
mModifiedNotVcnManaged = true;
return this; return this;
} }
@@ -382,6 +432,25 @@ public class NetworkRequest implements Parcelable {
mNetworkCapabilities.setSignalStrength(signalStrength); mNetworkCapabilities.setSignalStrength(signalStrength);
return this; return this;
} }
/**
* Deduce the NET_CAPABILITY_NOT_VCN_MANAGED capability from other capabilities
* and user intention, which includes:
* 1. For the requests that don't have anything besides
* {@link #VCN_SUPPORTED_CAPABILITIES}, add the NET_CAPABILITY_NOT_VCN_MANAGED to
* allow the callers automatically utilize VCN networks if available.
* 2. For the requests that explicitly add or remove NET_CAPABILITY_NOT_VCN_MANAGED,
* do not alter them to allow user fire request that suits their need.
*
* @hide
*/
private void deduceNotVcnManagedCapability(final NetworkCapabilities nc) {
if (mModifiedNotVcnManaged) return;
for (final int cap : nc.getCapabilities()) {
if (!VCN_SUPPORTED_CAPABILITIES.contains(cap)) return;
}
nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
}
} }
// implement the Parcelable interface // implement the Parcelable interface

View File

@@ -45,6 +45,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
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_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
@@ -1222,6 +1223,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) { private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
final NetworkCapabilities netCap = new NetworkCapabilities(); final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN); netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
netCap.setSingleUid(uid); netCap.setSingleUid(uid);
return netCap; return netCap;
@@ -1231,6 +1233,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
int transportType, NetworkRequest.Type type) { int transportType, NetworkRequest.Type type) {
final NetworkCapabilities netCap = new NetworkCapabilities(); final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName()); netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
if (transportType > -1) { if (transportType > -1) {
netCap.addTransportType(transportType); netCap.addTransportType(transportType);

View File

@@ -17,6 +17,7 @@
package com.android.server; package com.android.server;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -84,6 +85,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
final String typeName = ConnectivityManager.getNetworkTypeName(type); final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities(); mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED); mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
mNetworkCapabilities.addTransportType(transport); mNetworkCapabilities.addTransportType(transport);
switch (transport) { switch (transport) {
case TRANSPORT_ETHERNET: case TRANSPORT_ETHERNET:

View File

@@ -2590,6 +2590,10 @@ public class ConnectivityServiceTest {
NetworkCapabilities filter = new NetworkCapabilities(); NetworkCapabilities filter = new NetworkCapabilities();
filter.addCapability(capability); filter.addCapability(capability);
// Add NOT_VCN_MANAGED capability into filter unconditionally since some request will add
// NOT_VCN_MANAGED automatically but not for NetworkCapabilities,
// see {@code NetworkCapabilities#deduceNotVcnManagedCapability} for more details.
filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests"); final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
handlerThread.start(); handlerThread.start();
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
@@ -3841,6 +3845,7 @@ public class ConnectivityServiceTest {
handlerThread.start(); handlerThread.start();
NetworkCapabilities filter = new NetworkCapabilities() NetworkCapabilities filter = new NetworkCapabilities()
.addTransportType(TRANSPORT_CELLULAR) .addTransportType(TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.addCapability(NET_CAPABILITY_INTERNET); .addCapability(NET_CAPABILITY_INTERNET);
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
mServiceContext, "testFactory", filter); mServiceContext, "testFactory", filter);
@@ -5743,6 +5748,7 @@ public class ConnectivityServiceTest {
.addTransportType(TRANSPORT_CELLULAR) .addTransportType(TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_INTERNET) .addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_NOT_CONGESTED) .addCapability(NET_CAPABILITY_NOT_CONGESTED)
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkDownstreamBandwidthKbps(10); .setLinkDownstreamBandwidthKbps(10);
final NetworkCapabilities wifiNc = new NetworkCapabilities() final NetworkCapabilities wifiNc = new NetworkCapabilities()
.addTransportType(TRANSPORT_WIFI) .addTransportType(TRANSPORT_WIFI)
@@ -5751,6 +5757,7 @@ public class ConnectivityServiceTest {
.addCapability(NET_CAPABILITY_NOT_ROAMING) .addCapability(NET_CAPABILITY_NOT_ROAMING)
.addCapability(NET_CAPABILITY_NOT_CONGESTED) .addCapability(NET_CAPABILITY_NOT_CONGESTED)
.addCapability(NET_CAPABILITY_NOT_SUSPENDED) .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkUpstreamBandwidthKbps(20); .setLinkUpstreamBandwidthKbps(20);
mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */); mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */); mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
@@ -7382,19 +7389,13 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.removeCapability(testCap); mWiFiNetworkAgent.removeCapability(testCap);
callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent); callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent); callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
// TODO: Test default network changes for NOT_VCN_MANAGED once the default request has
// it.
if (testCap == NET_CAPABILITY_TRUSTED) {
verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId)); verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
reset(mMockNetd); reset(mMockNetd);
}
mCellNetworkAgent.removeCapability(testCap); mCellNetworkAgent.removeCapability(testCap);
callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
callbackWithoutCap.assertNoCallback(); callbackWithoutCap.assertNoCallback();
if (testCap == NET_CAPABILITY_TRUSTED) {
verify(mMockNetd).networkClearDefault(); verify(mMockNetd).networkClearDefault();
}
mCm.unregisterNetworkCallback(callbackWithCap); mCm.unregisterNetworkCallback(callbackWithCap);
mCm.unregisterNetworkCallback(callbackWithoutCap); mCm.unregisterNetworkCallback(callbackWithoutCap);