Add utility methods for creation of NetInfo, NetCaps, and LinkProps

This change adds basic utility methods to create network info, network
capabilities and link properties

Bug: 165827287
Test: atest FrameworksVcnTests
Change-Id: I915e0c4e9ca989344b9a4785e200381db0b94fb8
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index e88ce56..7024e67 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -16,30 +16,57 @@
 
 package com.android.server.vcn;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
 import static com.android.server.VcnManagementService.VDBG;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.ConnectivityManager;
 import android.net.InetAddresses;
+import android.net.IpPrefix;
 import android.net.IpSecManager;
 import android.net.IpSecManager.IpSecTunnelInterface;
 import android.net.IpSecManager.ResourceUnavailableException;
 import android.net.IpSecTransform;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkAgent;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.RouteInfo;
 import android.net.annotations.PolicyDirection;
+import android.net.ipsec.ike.ChildSessionCallback;
 import android.net.ipsec.ike.ChildSessionConfiguration;
+import android.net.ipsec.ike.ChildSessionParams;
 import android.net.ipsec.ike.IkeSession;
+import android.net.ipsec.ike.IkeSessionCallback;
+import android.net.ipsec.ike.IkeSessionConfiguration;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.exceptions.IkeException;
+import android.net.ipsec.ike.exceptions.IkeProtocolException;
 import android.net.vcn.VcnGatewayConnectionConfig;
+import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.Message;
 import android.os.ParcelUuid;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
 import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
 
 import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.util.Objects;
 import java.util.concurrent.TimeUnit;
@@ -628,12 +655,155 @@
         protected void processStateMsg(Message msg) {}
     }
 
-    private static class Dependencies {
+    // TODO: Remove this when migrating to new NetworkAgent API
+    private static NetworkInfo buildNetworkInfo(boolean isConnected) {
+        NetworkInfo info =
+                new NetworkInfo(
+                        ConnectivityManager.TYPE_MOBILE,
+                        TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                        "MOBILE",
+                        "VCN");
+        info.setDetailedState(
+                isConnected ? DetailedState.CONNECTED : DetailedState.DISCONNECTED, null, null);
+
+        return info;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static NetworkCapabilities buildNetworkCapabilities(
+            @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) {
+        final NetworkCapabilities caps = new NetworkCapabilities();
+
+        caps.addTransportType(TRANSPORT_CELLULAR);
+        caps.addCapability(NET_CAPABILITY_NOT_CONGESTED);
+        caps.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+
+        // Add exposed capabilities
+        for (int cap : gatewayConnectionConfig.getAllExposedCapabilities()) {
+            caps.addCapability(cap);
+        }
+
+        return caps;
+    }
+
+    private static LinkProperties buildConnectedLinkProperties(
+            @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
+            @NonNull IpSecTunnelInterface tunnelIface,
+            @NonNull ChildSessionConfiguration childConfig) {
+        final LinkProperties lp = new LinkProperties();
+
+        lp.setInterfaceName(tunnelIface.getInterfaceName());
+        for (LinkAddress addr : childConfig.getInternalAddresses()) {
+            lp.addLinkAddress(addr);
+        }
+        for (InetAddress addr : childConfig.getInternalDnsServers()) {
+            lp.addDnsServer(addr);
+        }
+
+        lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
+        lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
+
+        lp.setMtu(gatewayConnectionConfig.getMaxMtu());
+
+        return lp;
+    }
+
+    private class IkeSessionCallbackImpl implements IkeSessionCallback {
+        private final int mToken;
+
+        IkeSessionCallbackImpl(int token) {
+            mToken = token;
+        }
+
+        @Override
+        public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) {
+            Slog.v(TAG, "IkeOpened for token " + mToken);
+            // Nothing to do here.
+        }
+
+        @Override
+        public void onClosed() {
+            Slog.v(TAG, "IkeClosed for token " + mToken);
+            sessionClosed(mToken, null);
+        }
+
+        @Override
+        public void onClosedExceptionally(@NonNull IkeException exception) {
+            Slog.v(TAG, "IkeClosedExceptionally for token " + mToken, exception);
+            sessionClosed(mToken, exception);
+        }
+
+        @Override
+        public void onError(@NonNull IkeProtocolException exception) {
+            Slog.v(TAG, "IkeError for token " + mToken, exception);
+            // Non-fatal, log and continue.
+        }
+    }
+
+    private class ChildSessionCallbackImpl implements ChildSessionCallback {
+        private final int mToken;
+
+        ChildSessionCallbackImpl(int token) {
+            mToken = token;
+        }
+
+        @Override
+        public void onOpened(@NonNull ChildSessionConfiguration childConfig) {
+            Slog.v(TAG, "ChildOpened for token " + mToken);
+            childOpened(mToken, childConfig);
+        }
+
+        @Override
+        public void onClosed() {
+            Slog.v(TAG, "ChildClosed for token " + mToken);
+            sessionLost(mToken, null);
+        }
+
+        @Override
+        public void onClosedExceptionally(@NonNull IkeException exception) {
+            Slog.v(TAG, "ChildClosedExceptionally for token " + mToken, exception);
+            sessionLost(mToken, exception);
+        }
+
+        @Override
+        public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) {
+            Slog.v(TAG, "ChildTransformCreated; Direction: " + direction + "; token " + mToken);
+            childTransformCreated(mToken, transform, direction);
+        }
+
+        @Override
+        public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) {
+            // Nothing to be done; no references to the IpSecTransform are held, and this transform
+            // will be closed by the IKE library.
+            Slog.v(TAG, "ChildTransformDeleted; Direction: " + direction + "; for token " + mToken);
+        }
+    }
+
+    /** External dependencies used by VcnGatewayConnection, for injection in tests. */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public static class Dependencies {
+        /** Builds a new UnderlyingNetworkTracker. */
         public UnderlyingNetworkTracker newUnderlyingNetworkTracker(
                 VcnContext vcnContext,
                 ParcelUuid subscriptionGroup,
                 UnderlyingNetworkTrackerCallback callback) {
             return new UnderlyingNetworkTracker(vcnContext, subscriptionGroup, callback);
         }
+
+        /** Builds a new IkeSession. */
+        public IkeSession newIkeSession(
+                VcnContext vcnContext,
+                IkeSessionParams ikeSessionParams,
+                ChildSessionParams childSessionParams,
+                IkeSessionCallback ikeSessionCallback,
+                ChildSessionCallback childSessionCallback) {
+            return new IkeSession(
+                    vcnContext.getContext(),
+                    ikeSessionParams,
+                    childSessionParams,
+                    new HandlerExecutor(new Handler(vcnContext.getLooper())),
+                    ikeSessionCallback,
+                    childSessionCallback);
+        }
     }
 }
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
index f967bf0..3c08d34 100644
--- a/tests/vcn/Android.bp
+++ b/tests/vcn/Android.bp
@@ -20,6 +20,7 @@
         "services.core",
     ],
     libs: [
+        "android.net.ipsec.ike.stubs.module_lib",
         "android.test.runner",
         "android.test.base",
         "android.test.mock",
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index e98b6ef..dfd0c8a 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -33,12 +33,13 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class VcnGatewayConnectionConfigTest {
-    private static final int[] EXPOSED_CAPS =
+    // Public for use in VcnGatewayConnectionTest
+    public static final int[] EXPOSED_CAPS =
             new int[] {
                 NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS
             };
-    private static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN};
-    private static final long[] RETRY_INTERVALS_MS =
+    public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN};
+    public static final long[] RETRY_INTERVALS_MS =
             new long[] {
                 TimeUnit.SECONDS.toMillis(5),
                 TimeUnit.SECONDS.toMillis(30),
@@ -47,10 +48,10 @@
                 TimeUnit.MINUTES.toMillis(15),
                 TimeUnit.MINUTES.toMillis(30)
             };
-    private static final int MAX_MTU = 1360;
+    public static final int MAX_MTU = 1360;
 
-    // Package protected for use in VcnConfigTest
-    static VcnGatewayConnectionConfig buildTestConfig() {
+    // Public for use in VcnGatewayConnectionTest
+    public static VcnGatewayConnectionConfig buildTestConfig() {
         final VcnGatewayConnectionConfig.Builder builder =
                 new VcnGatewayConnectionConfig.Builder()
                         .setRetryInterval(RETRY_INTERVALS_MS)
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
new file mode 100644
index 0000000..d741e5c
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.NetworkCapabilities;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+import android.telephony.SubscriptionInfo;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/** Tests for TelephonySubscriptionTracker */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionTest {
+    private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID());
+    private static final int TEST_SIM_SLOT_INDEX = 1;
+    private static final int TEST_SUBSCRIPTION_ID_1 = 2;
+    private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class);
+    private static final int TEST_SUBSCRIPTION_ID_2 = 3;
+    private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
+    private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP;
+
+    static {
+        final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>();
+        subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID);
+        subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_PARCEL_UUID);
+        TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap);
+    }
+
+    @NonNull private final Context mContext;
+    @NonNull private final TestLooper mTestLooper;
+    @NonNull private final VcnNetworkProvider mVcnNetworkProvider;
+    @NonNull private final VcnGatewayConnection.Dependencies mDeps;
+
+    public VcnGatewayConnectionTest() {
+        mContext = mock(Context.class);
+        mTestLooper = new TestLooper();
+        mVcnNetworkProvider = mock(VcnNetworkProvider.class);
+        mDeps = mock(VcnGatewayConnection.Dependencies.class);
+    }
+
+    @Test
+    public void testBuildNetworkCapabilities() throws Exception {
+        final NetworkCapabilities caps =
+                VcnGatewayConnection.buildNetworkCapabilities(
+                        VcnGatewayConnectionConfigTest.buildTestConfig());
+
+        for (int exposedCapability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
+            assertTrue(caps.hasCapability(exposedCapability));
+        }
+    }
+}