Add version control for packet address translation design
This commit adds the version control for keepalive packet address
translation design to prevent device crash if the network stack
is not updated to a newer version. This commit also adds a
DeviceConfig to control the design in newer module version.
Bug: 291870956
Test: atest FrameworksNetTests CtsNetTestCases
Change-Id: Id4efbf51dae9154d2bc3a1ee405e2139d5c91e36
diff --git a/service/src/com/android/server/connectivity/KeepaliveTracker.java b/service/src/com/android/server/connectivity/KeepaliveTracker.java
index 2ce186f..ae70767 100644
--- a/service/src/com/android/server/connectivity/KeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/KeepaliveTracker.java
@@ -34,6 +34,8 @@
import static android.net.SocketKeepalive.SUCCESS;
import static android.net.SocketKeepalive.SUCCESS_PAUSED;
+import static com.android.net.module.util.FeatureVersions.FEATURE_CLAT_ADDRESS_TRANSLATE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -59,6 +61,7 @@
import com.android.connectivity.resources.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.DeviceConfigUtils;
import com.android.net.module.util.HexDump;
import com.android.net.module.util.IpUtils;
@@ -86,6 +89,9 @@
public static final String PERMISSION = android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
+ private static final String CONFIG_DISABLE_CLAT_ADDRESS_TRANSLATE =
+ "disable_clat_address_translate";
+
/** Keeps track of keepalive requests. */
private final HashMap <NetworkAgentInfo, HashMap<Integer, KeepaliveInfo>> mKeepalives =
new HashMap<> ();
@@ -113,7 +119,7 @@
}
@VisibleForTesting
- KeepaliveTracker(Context context, Handler handler, TcpKeepaliveController tcpController,
+ public KeepaliveTracker(Context context, Handler handler, TcpKeepaliveController tcpController,
Dependencies deps) {
mTcpController = tcpController;
mContext = context;
@@ -553,6 +559,8 @@
private KeepaliveInfo handleUpdateKeepaliveForClat(KeepaliveInfo ki)
throws InvalidSocketException, InvalidPacketException {
+ if (!mDependencies.isAddressTranslationEnabled(mContext)) return ki;
+
// Translation applies to only NAT-T keepalive
if (ki.mType != KeepaliveInfo.TYPE_NATT) return ki;
// Only try to translate address if the packet source address is the clat's source address.
@@ -973,5 +981,20 @@
public ConnectivityResources createConnectivityResources(@NonNull Context context) {
return new ConnectivityResources(context);
}
+
+ /**
+ * Return if keepalive address translation with clat feature is supported or not.
+ *
+ * This is controlled by both isFeatureSupported() and isFeatureEnabled(). The
+ * isFeatureSupported() checks whether device contains the minimal required module
+ * version for FEATURE_CLAT_ADDRESS_TRANSLATE. The isTetheringFeatureForceDisabled()
+ * checks the DeviceConfig flag that can be updated via DeviceConfig push to control
+ * the overall feature.
+ */
+ public boolean isAddressTranslationEnabled(@NonNull Context context) {
+ return DeviceConfigUtils.isFeatureSupported(context, FEATURE_CLAT_ADDRESS_TRANSLATE)
+ && !DeviceConfigUtils.isTetheringFeatureForceDisabled(
+ CONFIG_DISABLE_CLAT_ADDRESS_TRANSLATE);
+ }
}
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 5dd4048..931670a 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -402,6 +402,7 @@
import com.android.server.connectivity.ClatCoordinator;
import com.android.server.connectivity.ConnectivityFlags;
import com.android.server.connectivity.ConnectivityResources;
+import com.android.server.connectivity.KeepaliveTracker;
import com.android.server.connectivity.MultinetworkPolicyTracker;
import com.android.server.connectivity.MultinetworkPolicyTrackerTestDependencies;
import com.android.server.connectivity.Nat464Xlat;
@@ -410,6 +411,7 @@
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.QosCallbackTracker;
+import com.android.server.connectivity.TcpKeepaliveController;
import com.android.server.connectivity.UidRangeUtils;
import com.android.server.connectivity.Vpn;
import com.android.server.connectivity.VpnProfileStore;
@@ -627,6 +629,7 @@
@Mock ActivityManager mActivityManager;
@Mock DestroySocketsWrapper mDestroySocketsWrapper;
@Mock SubscriptionManager mSubscriptionManager;
+ @Mock KeepaliveTracker.Dependencies mMockKeepaliveTrackerDependencies;
// BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
// underlying binder calls.
@@ -1898,6 +1901,12 @@
doReturn(mResources).when(mockResContext).getResources();
ConnectivityResources.setResourcesContextForTest(mockResContext);
mDeps = new ConnectivityServiceDependencies(mockResContext);
+ doReturn(true).when(mMockKeepaliveTrackerDependencies)
+ .isAddressTranslationEnabled(mServiceContext);
+ doReturn(new ConnectivityResources(mockResContext)).when(mMockKeepaliveTrackerDependencies)
+ .createConnectivityResources(mServiceContext);
+ doReturn(new int[] {1, 3, 0, 0}).when(mMockKeepaliveTrackerDependencies)
+ .getSupportedKeepalives(mServiceContext);
mAutoOnOffKeepaliveDependencies =
new AutomaticOnOffKeepaliveTrackerDependencies(mServiceContext);
mService = new ConnectivityService(mServiceContext,
@@ -2297,6 +2306,12 @@
// Assuming enabled here to focus on ConnectivityService tests.
return true;
}
+ public KeepaliveTracker newKeepaliveTracker(@NonNull Context context,
+ @NonNull Handler connectivityserviceHander) {
+ return new KeepaliveTracker(context, connectivityserviceHander,
+ new TcpKeepaliveController(connectivityserviceHander),
+ mMockKeepaliveTrackerDependencies);
+ }
}
private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) {
diff --git a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
index f4d3915..b69b042 100644
--- a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
@@ -78,7 +78,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.connectivity.resources.R;
import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker.AutomaticOnOffKeepalive;
import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
import com.android.testutils.DevSdkIgnoreRule;
@@ -96,6 +95,7 @@
import org.mockito.MockitoAnnotations;
import java.io.FileDescriptor;
+import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
@@ -128,7 +128,7 @@
@Mock AlarmManager mAlarmManager;
@Mock NetworkAgentInfo mNai;
@Mock SubscriptionManager mSubscriptionManager;
-
+ @Mock KeepaliveTracker.Dependencies mKeepaliveTrackerDeps;
KeepaliveStatsTracker mKeepaliveStatsTracker;
TestKeepaliveTracker mKeepaliveTracker;
AOOTestHandler mTestHandler;
@@ -267,7 +267,7 @@
TestKeepaliveTracker(@NonNull final Context context, @NonNull final Handler handler,
@NonNull final TcpKeepaliveController tcpController) {
- super(context, handler, tcpController, new Dependencies());
+ super(context, handler, tcpController, mKeepaliveTrackerDeps);
}
public void setReturnedKeepaliveInfo(@NonNull final KeepaliveInfo ki) {
@@ -336,8 +336,6 @@
anyInt() /* pid */, anyInt() /* uid */);
ConnectivityResources.setResourcesContextForTest(mCtx);
final Resources mockResources = mock(Resources.class);
- doReturn(new String[] { "0,3", "3,3" }).when(mockResources)
- .getStringArray(R.array.config_networkSupportedKeepaliveCount);
doReturn(mockResources).when(mCtx).getResources();
doReturn(mNetd).when(mDependencies).getNetd();
doReturn(mAlarmManager).when(mDependencies).getAlarmManager(any());
@@ -345,6 +343,10 @@
.getFwmarkForNetwork(TEST_NETID);
doNothing().when(mDependencies).sendRequest(any(), any());
+ doReturn(true).when(mKeepaliveTrackerDeps).isAddressTranslationEnabled(mCtx);
+ doReturn(new ConnectivityResources(mCtx)).when(mKeepaliveTrackerDeps)
+ .createConnectivityResources(mCtx);
+ doReturn(new int[] {3, 0, 0, 3}).when(mKeepaliveTrackerDeps).getSupportedKeepalives(mCtx);
mHandlerThread = new HandlerThread("KeepaliveTrackerTest");
mHandlerThread.start();
@@ -659,6 +661,25 @@
}
@Test
+ public void testStartNattKeepalive_addressTranslationOnClatNotSupported() throws Exception {
+ // Disable address translation feature and verify the behavior
+ doReturn(false).when(mKeepaliveTrackerDeps).isAddressTranslationEnabled(mCtx);
+
+ setupTestNaiForClat(InetAddresses.parseNumericAddress("2001:db8::1"),
+ InetAddresses.parseNumericAddress("2001:db8::2"));
+
+ doStartNattKeepalive();
+ final ArgumentCaptor<NattKeepalivePacketData> kpdCaptor =
+ ArgumentCaptor.forClass(NattKeepalivePacketData.class);
+ verify(mNai).onStartNattSocketKeepalive(
+ eq(TEST_SLOT), eq(TEST_KEEPALIVE_INTERVAL_SEC), kpdCaptor.capture());
+ // Verify that address translation is not triggered so the addresses are still v4.
+ final NattKeepalivePacketData kpd = kpdCaptor.getValue();
+ assertTrue(kpd.getSrcAddress() instanceof Inet4Address);
+ assertTrue(kpd.getDstAddress() instanceof Inet4Address);
+ }
+
+ @Test
public void testStartNattKeepalive_addressTranslationOnClat() throws Exception {
final InetAddress v6AddrSrc = InetAddresses.parseNumericAddress("2001:db8::1");
final InetAddress v6AddrDst = InetAddresses.parseNumericAddress("2001:db8::2");