diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 0426acef07..04ce2fab50 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -22,6 +22,7 @@ import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.provider.DeviceConfig.NAMESPACE_TETHERING; import static com.android.net.module.util.FeatureVersions.CONNECTIVITY_MODULE_ID; +import static com.android.net.module.util.FeatureVersions.DNS_RESOLVER_MODULE_ID; import static com.android.net.module.util.FeatureVersions.MODULE_MASK; import static com.android.net.module.util.FeatureVersions.NETWORK_STACK_MODULE_ID; import static com.android.net.module.util.FeatureVersions.VERSION_MASK; @@ -68,7 +69,8 @@ public final class DeviceConfigUtils { @VisibleForTesting public static void resetPackageVersionCacheForTest() { sPackageVersion = -1; - sModuleVersion = -1; + sTetheringModuleVersion = -1; + sResolvModuleVersion = -1; sNetworkStackModuleVersion = -1; } @@ -243,23 +245,23 @@ public final class DeviceConfigUtils { } } - // Guess the tethering module name based on the package prefix of the connectivity resources - // Take the resource package name, cut it before "connectivity" and append "tethering". + // Guess an APEX module name based on the package prefix of the connectivity resources + // Take the resource package name, cut it before "connectivity" and append the module name. // Then resolve that package version number with packageManager. - // If that fails retry by appending "go.tethering" instead - private static long resolveTetheringModuleVersion(@NonNull Context context) + // If that fails retry by appending "go." instead. + private static long resolveApexModuleVersion(@NonNull Context context, String moduleName) throws PackageManager.NameNotFoundException { final String pkgPrefix = resolvePkgPrefix(context); final PackageManager packageManager = context.getPackageManager(); try { - return packageManager.getPackageInfo(pkgPrefix + "tethering", + return packageManager.getPackageInfo(pkgPrefix + moduleName, PackageManager.MATCH_APEX).getLongVersionCode(); } catch (PackageManager.NameNotFoundException e) { Log.d(TAG, "Device is using go modules"); // fall through } - return packageManager.getPackageInfo(pkgPrefix + "go.tethering", + return packageManager.getPackageInfo(pkgPrefix + "go." + moduleName, PackageManager.MATCH_APEX).getLongVersionCode(); } @@ -274,19 +276,35 @@ public final class DeviceConfigUtils { return connResourcesPackage.substring(0, pkgPrefixLen); } - private static volatile long sModuleVersion = -1; + private static volatile long sTetheringModuleVersion = -1; + private static long getTetheringModuleVersion(@NonNull Context context) { - if (sModuleVersion >= 0) return sModuleVersion; + if (sTetheringModuleVersion >= 0) return sTetheringModuleVersion; try { - sModuleVersion = resolveTetheringModuleVersion(context); + sTetheringModuleVersion = resolveApexModuleVersion(context, "tethering"); } catch (PackageManager.NameNotFoundException e) { // It's expected to fail tethering module version resolution on the devices with // flattened apex Log.e(TAG, "Failed to resolve tethering module version: " + e); return DEFAULT_PACKAGE_VERSION; } - return sModuleVersion; + return sTetheringModuleVersion; + } + + private static volatile long sResolvModuleVersion = -1; + private static long getResolvModuleVersion(@NonNull Context context) { + if (sResolvModuleVersion >= 0) return sResolvModuleVersion; + + try { + sResolvModuleVersion = resolveApexModuleVersion(context, "resolv"); + } catch (PackageManager.NameNotFoundException e) { + // It's expected to fail resolv module version resolution on the devices with + // flattened apex + Log.e(TAG, "Failed to resolve resolv module version: " + e); + return DEFAULT_PACKAGE_VERSION; + } + return sResolvModuleVersion; } private static volatile long sNetworkStackModuleVersion = -1; @@ -342,6 +360,8 @@ public final class DeviceConfigUtils { moduleVersion = getTetheringModuleVersion(context); } else if (moduleId == NETWORK_STACK_MODULE_ID) { moduleVersion = getNetworkStackModuleVersion(context); + } else if (moduleId == DNS_RESOLVER_MODULE_ID) { + moduleVersion = getResolvModuleVersion(context); } else { throw new IllegalArgumentException("Unknown module " + moduleId); } diff --git a/staticlibs/device/com/android/net/module/util/FeatureVersions.java b/staticlibs/device/com/android/net/module/util/FeatureVersions.java index d5f8124d67..d0cf3fd2ca 100644 --- a/staticlibs/device/com/android/net/module/util/FeatureVersions.java +++ b/staticlibs/device/com/android/net/module/util/FeatureVersions.java @@ -37,6 +37,7 @@ public class FeatureVersions { public static final long VERSION_MASK = 0x00F_FFFF_FFFFL; public static final long CONNECTIVITY_MODULE_ID = 0x01L << MODULE_SHIFT; public static final long NETWORK_STACK_MODULE_ID = 0x02L << MODULE_SHIFT; + public static final long DNS_RESOLVER_MODULE_ID = 0x03L << MODULE_SHIFT; // CLAT_ADDRESS_TRANSLATE is a feature of the network stack, which doesn't throw when system // try to add a NAT-T keepalive packet filter with v6 address, introduced in version // M-2023-Sept on July 3rd, 2023. @@ -48,4 +49,11 @@ public class FeatureVersions { // by BPF for the given uid and conditions, introduced in version M-2024-Feb on Nov 6, 2023. public static final long FEATURE_IS_UID_NETWORKING_BLOCKED = CONNECTIVITY_MODULE_ID + 34_14_00_000L; + + // DDR is a feature implemented across NetworkStack, ConnectivityService and DnsResolver. + // The flag that enables this feature is in NetworkStack. + public static final long FEATURE_DDR_IN_CONNECTIVITY = + CONNECTIVITY_MODULE_ID + 35_11_00_000L; + public static final long FEATURE_DDR_IN_DNSRESOLVER = + DNS_RESOLVER_MODULE_ID + 35_11_00_000L; } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index 9fb61d9b43..a5af09b3d7 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -24,6 +24,7 @@ import static android.provider.DeviceConfig.NAMESPACE_TETHERING; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.net.module.util.FeatureVersions.CONNECTIVITY_MODULE_ID; +import static com.android.net.module.util.FeatureVersions.DNS_RESOLVER_MODULE_ID; import static com.android.net.module.util.FeatureVersions.NETWORK_STACK_MODULE_ID; import static org.junit.Assert.assertEquals; @@ -77,7 +78,9 @@ public class DeviceConfigUtilsTest { private static final int TEST_DEFAULT_FLAG_VALUE = 0; private static final int TEST_MAX_FLAG_VALUE = 1000; private static final int TEST_MIN_FLAG_VALUE = 100; - private static final long TEST_PACKAGE_VERSION = 290000000; + private static final long TEST_PACKAGE_VERSION = 290500000; + private static final long TEST_GO_PACKAGE_VERSION = 290000000; // Not updated + private static final long TEST_RESOLV_PACKAGE_VERSION = 290300000; // Updated, but older. private static final String TEST_PACKAGE_NAME = "test.package.name"; // The APEX name is the name of the APEX module, as in android.content.pm.ModuleInfo, and is // used for its mount point in /apex. APEX packages are actually APKs with a different @@ -85,14 +88,18 @@ public class DeviceConfigUtilsTest { // that manifest, and is reflected in android.content.pm.ApplicationInfo. Contrary to the APEX // (module) name, different package names are typically used to identify the organization that // built and signed the APEX modules. - private static final String TEST_APEX_PACKAGE_NAME = "com.prefix.android.tethering"; - private static final String TEST_GO_APEX_PACKAGE_NAME = "com.prefix.android.go.tethering"; + private static final String TEST_TETHERING_PACKAGE_NAME = "com.prefix.android.tethering"; + private static final String TEST_GO_TETHERING_PACKAGE_NAME = "com.prefix.android.go.tethering"; + private static final String TEST_RESOLV_PACKAGE_NAME = "com.prefix.android.resolv"; + private static final String TEST_GO_RESOLV_PACKAGE_NAME = "com.prefix.android.go.resolv"; private static final String TEST_CONNRES_PACKAGE_NAME = "com.prefix.android.connectivity.resources"; private static final String TEST_NETWORKSTACK_NAME = "com.prefix.android.networkstack"; private static final String TEST_GO_NETWORKSTACK_NAME = "com.prefix.android.go.networkstack"; private final PackageInfo mPackageInfo = new PackageInfo(); - private final PackageInfo mApexPackageInfo = new PackageInfo(); + private final PackageInfo mGoApexPackageInfo = new PackageInfo(); + private final PackageInfo mTetheringApexPackageInfo = new PackageInfo(); + private final PackageInfo mResolvApexPackageInfo = new PackageInfo(); private MockitoSession mSession; @Mock private Context mContext; @@ -105,13 +112,22 @@ public class DeviceConfigUtilsTest { mSession = mockitoSession().spyStatic(DeviceConfig.class).startMocking(); mPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION); - mApexPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION); + mTetheringApexPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION); + mGoApexPackageInfo.setLongVersionCode(TEST_GO_PACKAGE_VERSION); + mResolvApexPackageInfo.setLongVersionCode(TEST_RESOLV_PACKAGE_VERSION); doReturn(mPm).when(mContext).getPackageManager(); doReturn(TEST_PACKAGE_NAME).when(mContext).getPackageName(); doThrow(NameNotFoundException.class).when(mPm).getPackageInfo(anyString(), anyInt()); doReturn(mPackageInfo).when(mPm).getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt()); - doReturn(mApexPackageInfo).when(mPm).getPackageInfo(eq(TEST_APEX_PACKAGE_NAME), anyInt()); + doReturn(mTetheringApexPackageInfo).when(mPm).getPackageInfo( + eq(TEST_TETHERING_PACKAGE_NAME), anyInt()); + doReturn(mResolvApexPackageInfo).when(mPm).getPackageInfo(eq(TEST_RESOLV_PACKAGE_NAME), + anyInt()); + doReturn(mGoApexPackageInfo).when(mPm).getPackageInfo(eq(TEST_GO_TETHERING_PACKAGE_NAME), + anyInt()); + doReturn(mGoApexPackageInfo).when(mPm).getPackageInfo(eq(TEST_GO_RESOLV_PACKAGE_NAME), + anyInt()); doReturn(mResources).when(mContext).getResources(); @@ -342,9 +358,9 @@ public class DeviceConfigUtilsTest { @Test public void testFeatureIsEnabledOnGo() throws Exception { doThrow(NameNotFoundException.class).when(mPm).getPackageInfo( - eq(TEST_APEX_PACKAGE_NAME), anyInt()); - doReturn(mApexPackageInfo).when(mPm).getPackageInfo( - eq(TEST_GO_APEX_PACKAGE_NAME), anyInt()); + eq(TEST_TETHERING_PACKAGE_NAME), anyInt()); + doReturn(mTetheringApexPackageInfo).when(mPm).getPackageInfo( + eq(TEST_GO_TETHERING_PACKAGE_NAME), anyInt()); doReturn("0").when(() -> DeviceConfig.getProperty( NAMESPACE_CONNECTIVITY, TEST_EXPERIMENT_FLAG)); doReturn("0").when(() -> DeviceConfig.getProperty( @@ -483,6 +499,31 @@ public class DeviceConfigUtilsTest { mContext, 889900000L + CONNECTIVITY_MODULE_ID)); } + + @Test + public void testIsFeatureSupported_resolvFeature() throws Exception { + assertTrue(DeviceConfigUtils.isFeatureSupported( + mContext, TEST_RESOLV_PACKAGE_VERSION + DNS_RESOLVER_MODULE_ID)); + // Return false because feature requires a future version. + assertFalse(DeviceConfigUtils.isFeatureSupported( + mContext, 889900000L + DNS_RESOLVER_MODULE_ID)); + } + + @Test + public void testIsFeatureSupported_goResolvFeature() throws Exception { + doThrow(NameNotFoundException.class).when(mPm).getPackageInfo(eq(TEST_RESOLV_PACKAGE_NAME), + anyInt()); + doReturn(mGoApexPackageInfo).when(mPm).getPackageInfo(eq(TEST_GO_RESOLV_PACKAGE_NAME), + anyInt()); + assertFalse(DeviceConfigUtils.isFeatureSupported( + mContext, TEST_RESOLV_PACKAGE_VERSION + DNS_RESOLVER_MODULE_ID)); + assertTrue(DeviceConfigUtils.isFeatureSupported( + mContext, TEST_GO_PACKAGE_VERSION + DNS_RESOLVER_MODULE_ID)); + // Return false because feature requires a future version. + assertFalse(DeviceConfigUtils.isFeatureSupported( + mContext, 889900000L + DNS_RESOLVER_MODULE_ID)); + } + @Test public void testIsFeatureSupported_illegalModule() throws Exception { assertThrows(IllegalArgumentException.class,