Convert VcnNetworkProvider to use NetworkOffers
This change brings VcnNetworkProvider to full functionality in the new
NetworkProvider paradigm, where NetworkProviders offer networks, and are
notified based on NetworkOfferCallbacks.
Bug: 185204197
Test: atest FrameworksVcnTests
Change-Id: I88c69c0be9f6fd81839fb1595ed00341001694a5
Merged-In: I88c69c0be9f6fd81839fb1595ed00341001694a5
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index d59ad6f..86cd23d 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -83,7 +83,12 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
static final int MIN_MTU_V6 = 1280;
- private static final Set<Integer> ALLOWED_CAPABILITIES;
+ /**
+ * The set of allowed capabilities for exposed capabilities.
+ *
+ * @hide
+ */
+ public static final Set<Integer> ALLOWED_CAPABILITIES;
static {
Set<Integer> allowedCaps = new ArraySet<>();
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 1718052..70b0fc1 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -372,8 +372,7 @@
/** Notifies the VcnManagementService that external dependencies can be set up. */
public void systemReady() {
- mContext.getSystemService(ConnectivityManager.class)
- .registerNetworkProvider(mNetworkProvider);
+ mNetworkProvider.register();
mContext.getSystemService(ConnectivityManager.class)
.registerNetworkCallback(
new NetworkRequest.Builder().clearCapabilities().build(),
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index ebabe2a..31ee247 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -16,12 +16,24 @@
package com.android.server.vcn;
+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_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.util.ArraySet;
import android.util.Slog;
@@ -30,7 +42,9 @@
import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
+import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
/**
* VCN Network Provider routes NetworkRequests to listeners to bring up tunnels as needed.
@@ -45,6 +59,10 @@
private final Set<NetworkRequestListener> mListeners = new ArraySet<>();
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Dependencies mDeps;
+
/**
* Cache of NetworkRequest(s).
*
@@ -52,8 +70,59 @@
*/
private final Set<NetworkRequest> mRequests = new ArraySet<>();
- public VcnNetworkProvider(Context context, Looper looper) {
- super(context, looper, VcnNetworkProvider.class.getSimpleName());
+ public VcnNetworkProvider(@NonNull Context context, @NonNull Looper looper) {
+ this(context, looper, new Dependencies());
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public VcnNetworkProvider(
+ @NonNull Context context, @NonNull Looper looper, @NonNull Dependencies dependencies) {
+ super(
+ Objects.requireNonNull(context, "Missing context"),
+ Objects.requireNonNull(looper, "Missing looper"),
+ TAG);
+
+ mContext = context;
+ mHandler = new Handler(looper);
+ mDeps = Objects.requireNonNull(dependencies, "Missing dependencies");
+ }
+
+ /** Registers this VcnNetworkProvider and a generic network offer with ConnectivityService. */
+ public void register() {
+ mContext.getSystemService(ConnectivityManager.class).registerNetworkProvider(this);
+ mDeps.registerNetworkOffer(
+ this,
+ Vcn.getNetworkScore(), // score filter
+ buildCapabilityFilter(),
+ new HandlerExecutor(mHandler),
+ new NetworkOfferCallback() {
+ @Override
+ public void onNetworkNeeded(@NonNull NetworkRequest request) {
+ handleNetworkRequested(request);
+ }
+
+ @Override
+ public void onNetworkUnneeded(@NonNull NetworkRequest request) {
+ handleNetworkRequestWithdrawn(request);
+ }
+ });
+ }
+
+ /** Builds the filter for NetworkRequests that can be served by the VcnNetworkProvider. */
+ private NetworkCapabilities buildCapabilityFilter() {
+ final NetworkCapabilities.Builder builder =
+ new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_TRUSTED)
+ .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NET_CAPABILITY_NOT_VPN)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+
+ for (int cap : VcnGatewayConnectionConfig.ALLOWED_CAPABILITIES) {
+ builder.addCapability(cap);
+ }
+
+ return builder.build();
}
/**
@@ -88,8 +157,7 @@
listener.onNetworkRequested(request);
}
- @Override
- public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
+ private void handleNetworkRequested(@NonNull NetworkRequest request) {
if (VDBG) {
Slog.v(TAG, "Network requested: Request = " + request);
}
@@ -103,8 +171,7 @@
}
}
- @Override
- public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
+ private void handleNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
if (VDBG) {
Slog.v(TAG, "Network request withdrawn: Request = " + request);
}
@@ -144,4 +211,18 @@
pw.decreaseIndent();
}
+
+ /** Proxy class for dependencies used for testing. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class Dependencies {
+ /** Registers a given network offer for the given provider. */
+ public void registerNetworkOffer(
+ @NonNull VcnNetworkProvider provider,
+ @NonNull NetworkScore score,
+ @NonNull NetworkCapabilities capabilitiesFilter,
+ @NonNull Executor executor,
+ @NonNull NetworkOfferCallback callback) {
+ provider.registerNetworkOffer(score, capabilitiesFilter, executor, callback);
+ }
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
index 79cf746..72db55b 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
@@ -16,12 +16,18 @@
package com.android.server.vcn;
+import static android.net.NetworkProvider.NetworkOfferCallback;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.NetworkRequest;
import android.os.test.TestLooper;
@@ -33,6 +39,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
import java.util.List;
@@ -47,6 +54,8 @@
@NonNull private final Context mContext;
@NonNull private final TestLooper mTestLooper;
+ @NonNull private VcnNetworkProvider.Dependencies mDeps;
+ @NonNull private ConnectivityManager mConnMgr;
@NonNull private VcnNetworkProvider mVcnNetworkProvider;
@NonNull private NetworkRequestListener mListener;
@@ -57,16 +66,47 @@
@Before
public void setUp() throws Exception {
- mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper());
+ mDeps = mock(VcnNetworkProvider.Dependencies.class);
+ mConnMgr = mock(ConnectivityManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
+ mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper(), mDeps);
mListener = mock(NetworkRequestListener.class);
}
+ private NetworkOfferCallback verifyRegisterAndGetOfferCallback() throws Exception {
+ mVcnNetworkProvider.register();
+
+ final ArgumentCaptor<NetworkOfferCallback> cbCaptor =
+ ArgumentCaptor.forClass(NetworkOfferCallback.class);
+
+ verify(mConnMgr).registerNetworkProvider(eq(mVcnNetworkProvider));
+ verify(mDeps)
+ .registerNetworkOffer(
+ eq(mVcnNetworkProvider),
+ argThat(
+ score ->
+ score.getLegacyInt()
+ == Vcn.getNetworkScore().getLegacyInt()),
+ any(),
+ any(),
+ cbCaptor.capture());
+
+ return cbCaptor.getValue();
+ }
+
+ @Test
+ public void testRegister() throws Exception {
+ verifyRegisterAndGetOfferCallback();
+ }
+
@Test
public void testRequestsPassedToRegisteredListeners() throws Exception {
mVcnNetworkProvider.registerListener(mListener);
final NetworkRequest request = mock(NetworkRequest.class);
- mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
+ verifyRegisterAndGetOfferCallback().onNetworkNeeded(request);
verify(mListener).onNetworkRequested(request);
}
@@ -76,13 +116,14 @@
mVcnNetworkProvider.unregisterListener(mListener);
final NetworkRequest request = mock(NetworkRequest.class);
- mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
+ verifyRegisterAndGetOfferCallback().onNetworkNeeded(request);
verifyNoMoreInteractions(mListener);
}
@Test
public void testCachedRequestsPassedOnRegister() throws Exception {
final List<NetworkRequest> requests = new ArrayList<>();
+ final NetworkOfferCallback offerCb = verifyRegisterAndGetOfferCallback();
for (int i = 0; i < 10; i++) {
// Build unique network requests; in this case, iterate down the capabilities as a way
@@ -91,12 +132,12 @@
new NetworkRequest.Builder().clearCapabilities().addCapability(i).build();
requests.add(request);
- mVcnNetworkProvider.onNetworkRequested(request, i, i + 1);
+ offerCb.onNetworkNeeded(request);
}
// Remove one, and verify that it is never sent to the listeners.
final NetworkRequest removed = requests.remove(0);
- mVcnNetworkProvider.onNetworkRequestWithdrawn(removed);
+ offerCb.onNetworkUnneeded(removed);
mVcnNetworkProvider.registerListener(mListener);
for (NetworkRequest request : requests) {