Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 923011ed authored by Yan Yan's avatar Yan Yan
Browse files

Add VCN gateway option to enable data stall handling

This commit allows caller to enable VCN's ability of handling data
stall by setting a VCN gateway option.

Bug: 261499808
Test: atest FrameworksVcnTests (new tests), CtsVcnTestCases
Change-Id: If37b26faf851153d64face66d10201d7eecad685
parent 99f5d0a0
Loading
Loading
Loading
Loading
+113 −4
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -130,6 +131,33 @@ public final class VcnGatewayConnectionConfig {
            })
    public @interface VcnSupportedCapability {}

    /**
     * Perform mobility update to attempt recovery from suspected data stalls.
     *
     * <p>If set, the gatway connection will monitor the data stall detection of the VCN network.
     * When there is a suspected data stall, the gateway connection will attempt recovery by
     * performing a mobility update on the underlying IKE session.
     *
     * @hide
     */
    public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(
            prefix = {"VCN_GATEWAY_OPTION_"},
            value = {
                // TODO: b/261499808 Add VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY
                // when it is exposed
            })
    public @interface VcnGatewayOption {}

    private static final Set<Integer> ALLOWED_GATEWAY_OPTIONS = new ArraySet<>();

    static {
        ALLOWED_GATEWAY_OPTIONS.add(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY);
    }

    private static final int DEFAULT_MAX_MTU = 1500;

    /**
@@ -201,6 +229,9 @@ public final class VcnGatewayConnectionConfig {
    private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs";
    @NonNull private final long[] mRetryIntervalsMs;

    private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions";
    @NonNull private final Set<Integer> mGatewayOptions;

    /** Builds a VcnGatewayConnectionConfig with the specified parameters. */
    private VcnGatewayConnectionConfig(
            @NonNull String gatewayConnectionName,
@@ -208,12 +239,14 @@ public final class VcnGatewayConnectionConfig {
            @NonNull Set<Integer> exposedCapabilities,
            @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
            @NonNull long[] retryIntervalsMs,
            @IntRange(from = MIN_MTU_V6) int maxMtu) {
            @IntRange(from = MIN_MTU_V6) int maxMtu,
            @NonNull Set<Integer> gatewayOptions) {
        mGatewayConnectionName = gatewayConnectionName;
        mTunnelConnectionParams = tunnelConnectionParams;
        mExposedCapabilities = new TreeSet(exposedCapabilities);
        mRetryIntervalsMs = retryIntervalsMs;
        mMaxMtu = maxMtu;
        mGatewayOptions = Collections.unmodifiableSet(new HashSet(gatewayOptions));

        mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates);
        if (mUnderlyingNetworkTemplates.isEmpty()) {
@@ -256,6 +289,20 @@ public final class VcnGatewayConnectionConfig {
                            VcnUnderlyingNetworkTemplate::fromPersistableBundle);
        }

        final PersistableBundle gatewayOptionsBundle = in.getPersistableBundle(GATEWAY_OPTIONS_KEY);

        if (gatewayOptionsBundle == null) {
            // GATEWAY_OPTIONS_KEY was added in Android U. Thus VcnGatewayConnectionConfig created
            // on old platforms will not have this data and will be assigned with the default value
            mGatewayOptions = Collections.emptySet();
        } else {
            mGatewayOptions =
                    new HashSet<>(
                            PersistableBundleUtils.toList(
                                    gatewayOptionsBundle,
                                    PersistableBundleUtils.INTEGER_DESERIALIZER));
        }

        mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY);
        mMaxMtu = in.getInt(MAX_MTU_KEY);

@@ -279,6 +326,10 @@ public final class VcnGatewayConnectionConfig {

        Preconditions.checkArgument(
                mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)");

        for (int option : mGatewayOptions) {
            validateGatewayOption(option);
        }
    }

    private static void checkValidCapability(int capability) {
@@ -315,6 +366,12 @@ public final class VcnGatewayConnectionConfig {
        }
    }

    private static void validateGatewayOption(int option) {
        if (!ALLOWED_GATEWAY_OPTIONS.contains(option)) {
            throw new IllegalArgumentException("Invalid vcn gateway option: " + option);
        }
    }

    /**
     * Returns the configured Gateway Connection name.
     *
@@ -398,6 +455,18 @@ public final class VcnGatewayConnectionConfig {
        return mMaxMtu;
    }

    /**
     * Checks if the given VCN gateway option is enabled.
     *
     * @param option the option to check.
     * @throws IllegalArgumentException if the provided option is invalid.
     * @hide
     */
    public boolean hasGatewayOption(@VcnGatewayOption int option) {
        validateGatewayOption(option);
        return mGatewayOptions.contains(option);
    }

    /**
     * Converts this config to a PersistableBundle.
     *
@@ -418,11 +487,16 @@ public final class VcnGatewayConnectionConfig {
                PersistableBundleUtils.fromList(
                        mUnderlyingNetworkTemplates,
                        VcnUnderlyingNetworkTemplate::toPersistableBundle);
        final PersistableBundle gatewayOptionsBundle =
                PersistableBundleUtils.fromList(
                        new ArrayList<>(mGatewayOptions),
                        PersistableBundleUtils.INTEGER_SERIALIZER);

        result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName);
        result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle);
        result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
        result.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, networkTemplatesBundle);
        result.putPersistableBundle(GATEWAY_OPTIONS_KEY, gatewayOptionsBundle);
        result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
        result.putInt(MAX_MTU_KEY, mMaxMtu);

@@ -437,7 +511,8 @@ public final class VcnGatewayConnectionConfig {
                mExposedCapabilities,
                mUnderlyingNetworkTemplates,
                Arrays.hashCode(mRetryIntervalsMs),
                mMaxMtu);
                mMaxMtu,
                mGatewayOptions);
    }

    @Override
@@ -452,7 +527,8 @@ public final class VcnGatewayConnectionConfig {
                && mExposedCapabilities.equals(rhs.mExposedCapabilities)
                && mUnderlyingNetworkTemplates.equals(rhs.mUnderlyingNetworkTemplates)
                && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
                && mMaxMtu == rhs.mMaxMtu;
                && mMaxMtu == rhs.mMaxMtu
                && mGatewayOptions.equals(rhs.mGatewayOptions);
    }

    /**
@@ -470,6 +546,8 @@ public final class VcnGatewayConnectionConfig {
        @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
        private int mMaxMtu = DEFAULT_MAX_MTU;

        @NonNull private final Set<Integer> mGatewayOptions = new ArraySet<>();

        // TODO: (b/175829816) Consider VCN-exposed capabilities that may be transport dependent.
        //       Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS
        //       when on Cell.
@@ -627,6 +705,36 @@ public final class VcnGatewayConnectionConfig {
            return this;
        }

        /**
         * Enables the specified VCN gateway option.
         *
         * @param option the option to be enabled
         * @return this {@link Builder} instance, for chaining
         * @throws IllegalArgumentException if the provided option is invalid
         * @hide
         */
        @NonNull
        public Builder addGatewayOption(@VcnGatewayOption int option) {
            validateGatewayOption(option);
            mGatewayOptions.add(option);
            return this;
        }

        /**
         * Resets (disables) the specified VCN gateway option.
         *
         * @param option the option to be disabled
         * @return this {@link Builder} instance, for chaining
         * @throws IllegalArgumentException if the provided option is invalid
         * @hide
         */
        @NonNull
        public Builder removeGatewayOption(@VcnGatewayOption int option) {
            validateGatewayOption(option);
            mGatewayOptions.remove(option);
            return this;
        }

        /**
         * Builds and validates the VcnGatewayConnectionConfig.
         *
@@ -640,7 +748,8 @@ public final class VcnGatewayConnectionConfig {
                    mExposedCapabilities,
                    mUnderlyingNetworkTemplates,
                    mRetryIntervalsMs,
                    mMaxMtu);
                    mMaxMtu,
                    mGatewayOptions);
        }
    }
}
+85 −2
Original line number Diff line number Diff line
@@ -19,9 +19,11 @@ package android.net.vcn;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
import static android.net.vcn.VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES;
import static android.net.vcn.VcnGatewayConnectionConfig.UNDERLYING_NETWORK_TEMPLATES_KEY;
import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
@@ -42,7 +44,9 @@ import org.junit.runner.RunWith;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@RunWith(AndroidJUnit4.class)
@@ -79,6 +83,9 @@ public class VcnGatewayConnectionConfigTest {
            };
    public static final int MAX_MTU = 1360;

    private static final Set<Integer> GATEWAY_OPTIONS =
            Collections.singleton(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY);

    public static final IkeTunnelConnectionParams TUNNEL_CONNECTION_PARAMS =
            TunnelConnectionParamsUtilsTest.buildTestParams();

@@ -109,10 +116,16 @@ public class VcnGatewayConnectionConfigTest {
                TUNNEL_CONNECTION_PARAMS);
    }

    private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(
            VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) {
    private static VcnGatewayConnectionConfig buildTestConfigWithExposedCapsAndOptions(
            VcnGatewayConnectionConfig.Builder builder,
            Set<Integer> gatewayOptions,
            int... exposedCaps) {
        builder.setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU);

        for (int option : gatewayOptions) {
            builder.addGatewayOption(option);
        }

        for (int caps : exposedCaps) {
            builder.addExposedCapability(caps);
        }
@@ -120,11 +133,27 @@ public class VcnGatewayConnectionConfigTest {
        return builder.build();
    }

    private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(
            VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) {
        return buildTestConfigWithExposedCapsAndOptions(
                builder, Collections.emptySet(), exposedCaps);
    }

    // Public for use in VcnGatewayConnectionTest
    public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) {
        return buildTestConfigWithExposedCaps(newBuilder(), exposedCaps);
    }

    private static VcnGatewayConnectionConfig buildTestConfigWithGatewayOptions(
            VcnGatewayConnectionConfig.Builder builder, Set<Integer> gatewayOptions) {
        return buildTestConfigWithExposedCapsAndOptions(builder, gatewayOptions, EXPOSED_CAPS);
    }

    private static VcnGatewayConnectionConfig buildTestConfigWithGatewayOptions(
            Set<Integer> gatewayOptions) {
        return buildTestConfigWithExposedCapsAndOptions(newBuilder(), gatewayOptions, EXPOSED_CAPS);
    }

    @Test
    public void testBuilderRequiresNonNullGatewayConnectionName() {
        try {
@@ -210,6 +239,15 @@ public class VcnGatewayConnectionConfigTest {
        }
    }

    @Test
    public void testBuilderRequiresValidOption() {
        try {
            newBuilder().addGatewayOption(-1);
            fail("Expected exception due to the invalid VCN gateway option");
        } catch (IllegalArgumentException e) {
        }
    }

    @Test
    public void testBuilderAndGetters() {
        final VcnGatewayConnectionConfig config = buildTestConfig();
@@ -225,6 +263,20 @@ public class VcnGatewayConnectionConfigTest {

        assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis());
        assertEquals(MAX_MTU, config.getMaxMtu());

        assertFalse(
                config.hasGatewayOption(
                        VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY));
    }

    @Test
    public void testBuilderAndGettersWithOptions() {
        final VcnGatewayConnectionConfig config =
                buildTestConfigWithGatewayOptions(GATEWAY_OPTIONS);

        for (int option : GATEWAY_OPTIONS) {
            assertTrue(config.hasGatewayOption(option));
        }
    }

    @Test
@@ -234,6 +286,14 @@ public class VcnGatewayConnectionConfigTest {
        assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
    }

    @Test
    public void testPersistableBundleWithOptions() {
        final VcnGatewayConnectionConfig config =
                buildTestConfigWithGatewayOptions(GATEWAY_OPTIONS);

        assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
    }

    @Test
    public void testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates() {
        PersistableBundle configBundle = buildTestConfig().toPersistableBundle();
@@ -318,4 +378,27 @@ public class VcnGatewayConnectionConfigTest {
        assertNotEquals(UNDERLYING_NETWORK_TEMPLATES, networkTemplatesNotEqual);
        assertNotEquals(config, configNotEqual);
    }

    private static VcnGatewayConnectionConfig buildConfigWithGatewayOptionsForEqualityTest(
            Set<Integer> gatewayOptions) {
        return buildTestConfigWithGatewayOptions(
                new VcnGatewayConnectionConfig.Builder(
                        "buildConfigWithGatewayOptionsForEqualityTest", TUNNEL_CONNECTION_PARAMS),
                gatewayOptions);
    }

    @Test
    public void testVcnGatewayOptionsEquality() throws Exception {
        final VcnGatewayConnectionConfig config =
                buildConfigWithGatewayOptionsForEqualityTest(GATEWAY_OPTIONS);

        final VcnGatewayConnectionConfig configEqual =
                buildConfigWithGatewayOptionsForEqualityTest(GATEWAY_OPTIONS);

        final VcnGatewayConnectionConfig configNotEqual =
                buildConfigWithGatewayOptionsForEqualityTest(Collections.emptySet());

        assertEquals(config, configEqual);
        assertNotEquals(config, configNotEqual);
    }
}