Merge "Support adjustable VCN safe mode timeout" into main
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 70cf973..c727a60 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -115,6 +115,20 @@
"vcn_restricted_transports";
/**
+ * Key for number of seconds to wait before entering safe mode
+ *
+ * <p>A VcnGatewayConnection will enter safe mode when it takes over the configured timeout to
+ * enter {@link ConnectedState}.
+ *
+ * <p>Defaults to 30, unless overridden by carrier config
+ *
+ * @hide
+ */
+ @NonNull
+ public static final String VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY =
+ "vcn_safe_mode_timeout_seconds_key";
+
+ /**
* Key for maximum number of parallel SAs for tunnel aggregation
*
* <p>If set to a value > 1, multiple tunnels will be set up, and inbound traffic will be
@@ -135,6 +149,7 @@
VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+ VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY,
VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY,
};
diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig
index 6956916..67a1906 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -5,4 +5,11 @@
namespace: "vcn"
description: "Feature flag for safe mode configurability"
bug: "276358140"
+}
+
+flag {
+ name: "safe_mode_timeout_config"
+ namespace: "vcn"
+ description: "Feature flag for adjustable safe mode timeout"
+ bug: "317406085"
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java
index 9213d96..6ce8685 100644
--- a/services/core/java/com/android/server/vcn/VcnContext.java
+++ b/services/core/java/com/android/server/vcn/VcnContext.java
@@ -74,6 +74,10 @@
return mFeatureFlags;
}
+ public boolean isFlagSafeModeTimeoutConfigEnabled() {
+ return mFeatureFlags.safeModeTimeoutConfig();
+ }
+
/**
* Verifies that the caller is running on the VcnContext Thread.
*
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 54c97dd..68132dc 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -1242,9 +1242,28 @@
createScheduledAlarm(
SAFEMODE_TIMEOUT_ALARM,
delayedMessage,
- mVcnContext.isInTestMode()
- ? TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS_TEST_MODE)
- : TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
+ getSafeModeTimeoutMs(mVcnContext, mLastSnapshot, mSubscriptionGroup));
+ }
+
+ /** Gets the safe mode timeout */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static long getSafeModeTimeoutMs(
+ VcnContext vcnContext, TelephonySubscriptionSnapshot snapshot, ParcelUuid subGrp) {
+ final int defaultSeconds =
+ vcnContext.isInTestMode()
+ ? SAFEMODE_TIMEOUT_SECONDS_TEST_MODE
+ : SAFEMODE_TIMEOUT_SECONDS;
+
+ final PersistableBundleWrapper carrierConfig = snapshot.getCarrierConfigForSubGrp(subGrp);
+ int resultSeconds = defaultSeconds;
+
+ if (vcnContext.isFlagSafeModeTimeoutConfigEnabled() && carrierConfig != null) {
+ resultSeconds =
+ carrierConfig.getInt(
+ VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, defaultSeconds);
+ }
+
+ return TimeUnit.SECONDS.toMillis(resultSeconds);
}
private void cancelSafeModeAlarm() {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index 692c8a8..49665f7 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -27,15 +27,18 @@
import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY;
import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR;
+import static com.android.server.vcn.VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS;
import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
+import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
@@ -55,6 +58,7 @@
import android.net.TelephonyNetworkSpecifier;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.net.vcn.VcnManager;
import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
import android.os.ParcelUuid;
@@ -81,6 +85,7 @@
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
/** Tests for TelephonySubscriptionTracker */
@RunWith(AndroidJUnit4.class)
@@ -352,4 +357,71 @@
any(Executor.class),
any(ConnectivityDiagnosticsCallback.class));
}
+
+ private void verifyGetSafeModeTimeoutMs(
+ boolean isInTestMode,
+ boolean isConfigTimeoutSupported,
+ PersistableBundleWrapper carrierConfig,
+ long expectedTimeoutMs)
+ throws Exception {
+ doReturn(isInTestMode).when(mVcnContext).isInTestMode();
+ doReturn(isConfigTimeoutSupported).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled();
+
+ final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class);
+ doReturn(carrierConfig).when(snapshot).getCarrierConfigForSubGrp(TEST_SUB_GRP);
+
+ final long result =
+ VcnGatewayConnection.getSafeModeTimeoutMs(mVcnContext, snapshot, TEST_SUB_GRP);
+
+ assertEquals(expectedTimeoutMs, result);
+ }
+
+ @Test
+ public void testGetSafeModeTimeoutMs_configTimeoutUnsupported() throws Exception {
+ verifyGetSafeModeTimeoutMs(
+ false /* isInTestMode */,
+ false /* isConfigTimeoutSupported */,
+ null /* carrierConfig */,
+ TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
+ }
+
+ @Test
+ public void testGetSafeModeTimeoutMs_configTimeoutSupported() throws Exception {
+ final int carrierConfigTimeoutSeconds = 20;
+ final PersistableBundleWrapper carrierConfig = mock(PersistableBundleWrapper.class);
+ doReturn(carrierConfigTimeoutSeconds)
+ .when(carrierConfig)
+ .getInt(eq(VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY), anyInt());
+
+ verifyGetSafeModeTimeoutMs(
+ false /* isInTestMode */,
+ true /* isConfigTimeoutSupported */,
+ carrierConfig,
+ TimeUnit.SECONDS.toMillis(carrierConfigTimeoutSeconds));
+ }
+
+ @Test
+ public void testGetSafeModeTimeoutMs_configTimeoutSupported_carrierConfigNull()
+ throws Exception {
+ verifyGetSafeModeTimeoutMs(
+ false /* isInTestMode */,
+ true /* isConfigTimeoutSupported */,
+ null /* carrierConfig */,
+ TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
+ }
+
+ @Test
+ public void testGetSafeModeTimeoutMs_configTimeoutOverrideTestModeDefault() throws Exception {
+ final int carrierConfigTimeoutSeconds = 20;
+ final PersistableBundleWrapper carrierConfig = mock(PersistableBundleWrapper.class);
+ doReturn(carrierConfigTimeoutSeconds)
+ .when(carrierConfig)
+ .getInt(eq(VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY), anyInt());
+
+ verifyGetSafeModeTimeoutMs(
+ true /* isInTestMode */,
+ true /* isConfigTimeoutSupported */,
+ carrierConfig,
+ TimeUnit.SECONDS.toMillis(carrierConfigTimeoutSeconds));
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index edced87..342056a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -226,6 +226,7 @@
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags();
+ doReturn(true).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled();
doReturn(mUnderlyingNetworkController)
.when(mDeps)