Merge "Change IaPrefixOption prefix length type to byte."
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index b1c653d..ff65228 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -36,7 +36,6 @@
srcs: [
"device/com/android/net/module/util/DeviceConfigUtils.java",
"device/com/android/net/module/util/FdEventsReader.java",
- "device/com/android/net/module/util/HexDump.java",
"device/com/android/net/module/util/NetworkMonitorUtils.java",
"device/com/android/net/module/util/PacketReader.java",
"device/com/android/net/module/util/SharedLog.java",
@@ -121,11 +120,11 @@
"device/com/android/net/module/util/BpfDump.java",
"device/com/android/net/module/util/BpfMap.java",
"device/com/android/net/module/util/BpfUtils.java",
- "device/com/android/net/module/util/HexDump.java",
"device/com/android/net/module/util/IBpfMap.java",
"device/com/android/net/module/util/JniUtil.java",
"device/com/android/net/module/util/Struct.java",
"device/com/android/net/module/util/TcUtils.java",
+ "framework/com/android/net/module/util/HexDump.java",
],
sdk_version: "module_current",
min_sdk_version: "29",
@@ -149,7 +148,6 @@
java_library {
name: "net-utils-device-common-struct",
srcs: [
- "device/com/android/net/module/util/HexDump.java",
"device/com/android/net/module/util/Ipv6Utils.java",
"device/com/android/net/module/util/PacketBuilder.java",
"device/com/android/net/module/util/Struct.java",
@@ -267,6 +265,14 @@
"//packages/apps/Settings",
],
lint: { strict_updatability_linting: true },
+ errorprone: {
+ enabled: true,
+ // Error-prone checking only warns of problems when building. To make the build fail with
+ // these errors, list the specific error-prone problems below.
+ javacflags: [
+ "-Xep:NullablePrimitive:ERROR",
+ ],
+ },
}
java_library {
@@ -371,10 +377,10 @@
sdk_version: "core_platform",
srcs: [
"device/com/android/net/module/util/FdEventsReader.java",
- "device/com/android/net/module/util/HexDump.java",
"device/com/android/net/module/util/SharedLog.java",
"framework/com/android/net/module/util/ByteUtils.java",
"framework/com/android/net/module/util/CollectionUtils.java",
+ "framework/com/android/net/module/util/HexDump.java",
"framework/com/android/net/module/util/LinkPropertiesUtils.java",
],
libs: [
diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java
index 9042085..9df2b03 100644
--- a/staticlibs/device/com/android/net/module/util/BpfMap.java
+++ b/staticlibs/device/com/android/net/module/util/BpfMap.java
@@ -70,8 +70,11 @@
private static ParcelFileDescriptor cachedBpfFdGet(String path, int mode,
int keySize, int valueSize)
throws ErrnoException, NullPointerException {
- // TODO: key should include keySize & valueSize, but really we should match specific types
- Pair<String, Integer> key = Pair.create(path, mode);
+ // Supports up to 1023 byte key and 65535 byte values
+ // Creating a BpfMap with larger keys/values seems like a bad idea any way...
+ keySize &= 1023; // 10-bits
+ valueSize &= 65535; // 16-bits
+ var key = Pair.create(path, (mode << 26) ^ (keySize << 16) ^ valueSize);
// unlocked fetch is safe: map is concurrent read capable, and only inserted into
ParcelFileDescriptor fd = sFdCache.get(key);
if (fd != null) return fd;
diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
index f8f250d..dae4eb9 100644
--- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
+++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java
@@ -16,9 +16,12 @@
package com.android.net.module.util;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+
import android.content.Context;
-import android.content.pm.ModuleInfo;
+import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.provider.DeviceConfig;
import android.util.Log;
@@ -28,6 +31,9 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Utilities for modules to query {@link DeviceConfig} and flags.
*/
@@ -43,6 +49,11 @@
public static final String TETHERING_MODULE_NAME = "com.android.tethering";
@VisibleForTesting
+ public static final String RESOURCES_APK_INTENT =
+ "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK";
+ private static final String CONNECTIVITY_RES_PKG_DIR = "/apex/" + TETHERING_MODULE_NAME + "/";
+
+ @VisibleForTesting
public static void resetPackageVersionCacheForTest() {
sPackageVersion = -1;
sModuleVersion = -1;
@@ -189,8 +200,13 @@
*/
public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace,
@NonNull String name, @NonNull String moduleName, boolean defaultEnabled) {
+ // TODO: migrate callers to a non-generic isTetheringFeatureEnabled method.
+ if (!TETHERING_MODULE_NAME.equals(moduleName)) {
+ throw new IllegalArgumentException(
+ "This method is only usable by the tethering module");
+ }
try {
- final long packageVersion = getModuleVersion(context, moduleName);
+ final long packageVersion = getTetheringModuleVersion(context);
return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Could not find the module name", e);
@@ -198,14 +214,6 @@
}
}
- private static boolean maybeUseFixedPackageVersion(@NonNull Context context) {
- final String packageName = context.getPackageName();
- if (packageName == null) return false;
-
- return packageName.equals("com.android.networkstack.tethering")
- || packageName.equals("com.android.networkstack.tethering.inprocess");
- }
-
private static boolean isFeatureEnabled(@NonNull Context context, long packageVersion,
@NonNull String namespace, String name, boolean defaultEnabled)
throws PackageManager.NameNotFoundException {
@@ -215,36 +223,40 @@
|| (propertyVersion != 0 && packageVersion >= (long) propertyVersion);
}
+ // 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".
+ // Then resolve that package version number with packageManager.
+ // If that fails retry by appending "go.tethering" instead
+ private static long resolveTetheringModuleVersion(@NonNull Context context)
+ throws PackageManager.NameNotFoundException {
+ final String connResourcesPackage = getConnectivityResourcesPackageName(context);
+ final int pkgPrefixLen = connResourcesPackage.indexOf("connectivity");
+ if (pkgPrefixLen < 0) {
+ throw new IllegalStateException(
+ "Invalid connectivity resources package: " + connResourcesPackage);
+ }
+
+ final String pkgPrefix = connResourcesPackage.substring(0, pkgPrefixLen);
+ final PackageManager packageManager = context.getPackageManager();
+ try {
+ return packageManager.getPackageInfo(pkgPrefix + "tethering",
+ PackageManager.MATCH_APEX).getLongVersionCode();
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "Device is using go modules");
+ // fall through
+ }
+
+ return packageManager.getPackageInfo(pkgPrefix + "go.tethering",
+ PackageManager.MATCH_APEX).getLongVersionCode();
+ }
+
private static volatile long sModuleVersion = -1;
- @VisibleForTesting public static long FIXED_PACKAGE_VERSION = 10;
- private static long getModuleVersion(@NonNull Context context, @NonNull String moduleName)
+ private static long getTetheringModuleVersion(@NonNull Context context)
throws PackageManager.NameNotFoundException {
if (sModuleVersion >= 0) return sModuleVersion;
- final PackageManager packageManager = context.getPackageManager();
- ModuleInfo module;
- try {
- module = packageManager.getModuleInfo(
- moduleName, PackageManager.MODULE_APEX_NAME);
- } catch (PackageManager.NameNotFoundException e) {
- // The error may happen if mainline module meta data is not installed e.g. there are
- // no meta data configuration in AOSP build. To be able to enable a feature in AOSP
- // by setting a flag via ADB for example. set a small non-zero fixed number for
- // comparing.
- if (maybeUseFixedPackageVersion(context)) {
- sModuleVersion = FIXED_PACKAGE_VERSION;
- return FIXED_PACKAGE_VERSION;
- } else {
- throw e;
- }
- }
- String modulePackageName = module.getPackageName();
- if (modulePackageName == null) throw new PackageManager.NameNotFoundException(moduleName);
- final long version = packageManager.getPackageInfo(modulePackageName,
- PackageManager.MATCH_APEX).getLongVersionCode();
- sModuleVersion = version;
-
- return version;
+ sModuleVersion = resolveTetheringModuleVersion(context);
+ return sModuleVersion;
}
/**
@@ -272,4 +284,24 @@
return defaultValue;
}
}
+
+ /**
+ * Get the package name of the ServiceConnectivityResources package, used to provide resources
+ * for service-connectivity.
+ */
+ @NonNull
+ public static String getConnectivityResourcesPackageName(@NonNull Context context) {
+ final List<ResolveInfo> pkgs = new ArrayList<>(context.getPackageManager()
+ .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY));
+ pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith(
+ CONNECTIVITY_RES_PKG_DIR));
+ if (pkgs.size() > 1) {
+ Log.wtf(TAG, "More than one connectivity resources package found: " + pkgs);
+ }
+ if (pkgs.isEmpty()) {
+ throw new IllegalStateException("No connectivity resource package found");
+ }
+
+ return pkgs.get(0).activityInfo.applicationInfo.packageName;
+ }
}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
index d462c53..e69a844 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
@@ -468,6 +468,23 @@
&& !isAdbSocket(diagMsg));
}
+ /**
+ * Close tcp sockets that match the following condition
+ * 1. TCP status is one of TCP_ESTABLISHED, TCP_SYN_SENT, and TCP_SYN_RECV
+ * 2. Owner uid of socket is in the targetUids
+ * 3. Socket is not loopback
+ * 4. Socket is not adb socket
+ *
+ * @param ownerUids target uids to close sockets
+ */
+ public static void destroyLiveTcpSocketsByOwnerUids(Set<Integer> ownerUids)
+ throws SocketException, InterruptedIOException, ErrnoException {
+ destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER,
+ (diagMsg) -> ownerUids.contains(diagMsg.inetDiagMsg.idiag_uid)
+ && !isLoopback(diagMsg)
+ && !isAdbSocket(diagMsg));
+ }
+
@Override
public String toString() {
return "InetDiagMessage{ "
diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
index f08880c..39e7ce9 100644
--- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
@@ -101,7 +101,6 @@
/**
* @return The index of the first element that matches the predicate, or -1 if none.
*/
- @Nullable
public static <T> int indexOf(@NonNull final Collection<T> elem,
@NonNull final Predicate<? super T> predicate) {
int idx = 0;
diff --git a/staticlibs/device/com/android/net/module/util/HexDump.java b/staticlibs/framework/com/android/net/module/util/HexDump.java
similarity index 99%
rename from staticlibs/device/com/android/net/module/util/HexDump.java
rename to staticlibs/framework/com/android/net/module/util/HexDump.java
index a27c0a3..a22c258 100644
--- a/staticlibs/device/com/android/net/module/util/HexDump.java
+++ b/staticlibs/framework/com/android/net/module/util/HexDump.java
@@ -20,6 +20,8 @@
/**
* Hex utility functions.
+ *
+ * @hide
*/
public class HexDump {
private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
diff --git a/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java b/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java
index 31d0729..40fc59f 100644
--- a/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java
@@ -16,7 +16,10 @@
package com.android.net.module.util;
+import android.annotation.NonNull;
import android.os.Parcel;
+import android.util.Log;
+
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -28,6 +31,7 @@
*/
public class InetAddressUtils {
+ private static final String TAG = InetAddressUtils.class.getSimpleName();
private static final int INET6_ADDR_LENGTH = 16;
/**
@@ -71,5 +75,23 @@
}
}
+ /**
+ * Create a Inet6Address with scope id if it is a link local address. Otherwise, returns the
+ * original address.
+ */
+ public static Inet6Address withScopeId(@NonNull final Inet6Address addr, int scopeid) {
+ if (!addr.isLinkLocalAddress()) {
+ return addr;
+ }
+ try {
+ return Inet6Address.getByAddress(null /* host */, addr.getAddress(),
+ scopeid);
+ } catch (UnknownHostException impossible) {
+ Log.wtf(TAG, "Cannot construct scoped Inet6Address with Inet6Address.getAddress("
+ + addr.getHostAddress() + "): ", impossible);
+ return null;
+ }
+ }
+
private InetAddressUtils() {}
}
diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
index aa2dd4c..6a6f5e1 100644
--- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
+++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
@@ -135,7 +135,7 @@
* - https://tools.ietf.org/html/rfc792
*/
public static final int ICMP_CHECKSUM_OFFSET = 2;
-
+ public static final int ICMP_HEADER_LEN = 8;
/**
* ICMPv6 constants.
*
@@ -197,6 +197,8 @@
* - https://tools.ietf.org/html/rfc768
*/
public static final int UDP_HEADER_LEN = 8;
+ public static final int UDP_SRCPORT_OFFSET = 0;
+ public static final int UDP_DSTPORT_OFFSET = 2;
public static final int UDP_LENGTH_OFFSET = 4;
public static final int UDP_CHECKSUM_OFFSET = 6;
@@ -227,6 +229,14 @@
public static final int DHCP6_OPTION_IAPREFIX = 26;
/**
+ * DNS constants.
+ *
+ * See also:
+ * - https://datatracker.ietf.org/doc/html/rfc7858#section-3.1
+ */
+ public static final short DNS_OVER_TLS_PORT = 853;
+
+ /**
* IEEE802.11 standard constants.
*
* See also:
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
index 4939483..70c0f89 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
@@ -27,13 +27,6 @@
// Android S / 12 (api level 31) - added 'tethering' mainline eBPF support
#define BPFLOADER_S_VERSION 2u
-// Android T / 13 Beta 3 (api level 33) - added support for 'netd_shared'
-#define BPFLOADER_T_BETA3_VERSION 13u
-
-// v0.18 added support for shared and pindir, but still ignores selinux_content
-// v0.19 added support for selinux_content along with the required selinux changes
-// and should be available starting with Android T Beta 4
-//
// Android T / 13 (api level 33) - support for shared/selinux_context/pindir
#define BPFLOADER_T_VERSION 19u
@@ -43,6 +36,9 @@
// Bpfloader v0.33+ supports {map,prog}.ignore_on_{eng,user,userdebug}
#define BPFLOADER_IGNORED_ON_VERSION 33u
+// Android U / 14 (api level 34) - various new program types added
+#define BPFLOADER_U_VERSION 37u
+
/* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER
* before #include "bpf_helpers.h" to change which bpfloaders will
* process the resulting .o file.
@@ -225,7 +221,7 @@
#ifdef THIS_BPF_PROGRAM_IS_FOR_TEST_PURPOSES_ONLY
#define BPF_MAP_ASSERT_OK(type, entries, mode)
-#elif BPFLOADER_MIN_VER >= BPFLOADER_T_BETA3_VERSION
+#elif BPFLOADER_MIN_VER >= BPFLOADER_T_VERSION
#define BPF_MAP_ASSERT_OK(type, entries, mode)
#else
#define BPF_MAP_ASSERT_OK(type, entries, mode) \
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
index d286eba..65540e0 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
@@ -48,9 +48,8 @@
#define DEFAULT_SIZEOF_BPF_MAP_DEF 32 // v0.0 struct: enum (uint sized) + 7 uint
#define DEFAULT_SIZEOF_BPF_PROG_DEF 20 // v0.0 struct: 4 uint + bool + 3 byte alignment pad
-// By default, unless otherwise specified, allow the use of features only supported by v0.28,
-// which first added working support for map uid != root
-#define COMPILE_FOR_BPFLOADER_VERSION 28u
+// By default, unless otherwise specified, allow the use of features only supported by v0.37.
+#define COMPILE_FOR_BPFLOADER_VERSION 37u
/*
* The bpf_{map,prog}_def structures are compiled for different architectures.
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 a8e7993..b75939b 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
@@ -16,25 +16,30 @@
package com.android.net.module.util;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+
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.DeviceConfigUtils.FIXED_PACKAGE_VERSION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
-import android.content.pm.ModuleInfo;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.provider.DeviceConfig;
@@ -49,6 +54,8 @@
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
+import java.util.Arrays;
+
/**
* Tests for DeviceConfigUtils.
@@ -66,14 +73,23 @@
private static final int TEST_MIN_FLAG_VALUE = 100;
private static final long TEST_PACKAGE_VERSION = 290000000;
private static final String TEST_PACKAGE_NAME = "test.package.name";
- private static final String TETHERING_AOSP_PACKAGE_NAME = "com.android.networkstack.tethering";
- private static final String TEST_APEX_NAME = "test.apex.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
+ // file extension, so they have an AndroidManifest: the APEX package name is the package name in
+ // 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_NAME = "com.android.tethering";
+ 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_CONNRES_PACKAGE_NAME =
+ "com.prefix.android.connectivity.resources";
+ private final PackageInfo mPackageInfo = new PackageInfo();
+ private final PackageInfo mApexPackageInfo = new PackageInfo();
private MockitoSession mSession;
@Mock private Context mContext;
@Mock private PackageManager mPm;
- @Mock private ModuleInfo mMi;
- @Mock private PackageInfo mPi;
@Mock private Resources mResources;
@Before
@@ -81,15 +97,26 @@
MockitoAnnotations.initMocks(this);
mSession = mockitoSession().spyStatic(DeviceConfig.class).startMocking();
- final PackageInfo pi = new PackageInfo();
- pi.setLongVersionCode(TEST_PACKAGE_VERSION);
+ mPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION);
+ mApexPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION);
doReturn(mPm).when(mContext).getPackageManager();
doReturn(TEST_PACKAGE_NAME).when(mContext).getPackageName();
- doReturn(mMi).when(mPm).getModuleInfo(eq(TEST_APEX_NAME), anyInt());
- doReturn(TEST_PACKAGE_NAME).when(mMi).getPackageName();
- doReturn(pi).when(mPm).getPackageInfo(anyString(), anyInt());
+ 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(mResources).when(mContext).getResources();
+
+ final ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = new ActivityInfo();
+ ri.activityInfo.applicationInfo = new ApplicationInfo();
+ ri.activityInfo.applicationInfo.packageName = TEST_CONNRES_PACKAGE_NAME;
+ ri.activityInfo.applicationInfo.sourceDir =
+ "/apex/com.android.tethering/priv-app/ServiceConnectivityResources@version";
+ doReturn(Arrays.asList(ri)).when(mPm).queryIntentActivities(argThat(
+ intent -> intent.getAction().equals(DeviceConfigUtils.RESOURCES_APK_INTENT)),
+ eq(MATCH_SYSTEM_ONLY));
}
@After
@@ -223,35 +250,32 @@
TEST_EXPERIMENT_FLAG));
assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */));
- doThrow(NameNotFoundException.class).when(mPm).getModuleInfo(anyString(), anyInt());
- assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
- TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */));
}
-
@Test
- public void testFeatureIsEnabledUsingFixedVersion() throws Exception {
- doReturn(TETHERING_AOSP_PACKAGE_NAME).when(mContext).getPackageName();
- doThrow(NameNotFoundException.class).when(mPm).getModuleInfo(anyString(), anyInt());
-
- doReturn(Long.toString(FIXED_PACKAGE_VERSION)).when(() -> DeviceConfig.getProperty(
+ 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());
+ doReturn("0").when(() -> DeviceConfig.getProperty(
eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG)));
- assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
- TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */));
- doReturn(Long.toString(FIXED_PACKAGE_VERSION + 1)).when(() -> DeviceConfig.getProperty(
- eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG)));
+ assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
+ TEST_EXPERIMENT_FLAG));
assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */));
+ assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
+ TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */));
- doReturn(Long.toString(FIXED_PACKAGE_VERSION - 1)).when(() -> DeviceConfig.getProperty(
- eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG)));
+ doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
+ eq(TEST_EXPERIMENT_FLAG)));
assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */));
}
@Test
- public void testFeatureIsEnabledCaching() throws Exception {
+ public void testFeatureIsEnabledCaching_APK() throws Exception {
doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
eq(TEST_EXPERIMENT_FLAG)));
assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
@@ -263,14 +287,20 @@
verify(mContext, times(1)).getPackageManager();
verify(mContext, times(1)).getPackageName();
verify(mPm, times(1)).getPackageInfo(anyString(), anyInt());
+ }
+ @Test
+ public void testFeatureIsEnabledCaching_APEX() throws Exception {
+ doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
+ eq(TEST_EXPERIMENT_FLAG)));
assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */));
assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */));
- // Module info is only queried once
- verify(mPm, times(1)).getModuleInfo(anyString(), anyInt());
+ // Package info is only queried once
+ verify(mPm, times(1)).getPackageInfo(anyString(), anyInt());
+ verify(mContext, never()).getPackageName();
}
@Test
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java
index 2736c53..bb2b933 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java
@@ -18,6 +18,10 @@
import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.InetAddresses;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
@@ -67,4 +71,25 @@
assertEquals(ipv6, out);
assertEquals(42, out.getScopeId());
}
+
+ @Test
+ public void testWithScopeId() {
+ final int scopeId = 999;
+
+ final String globalAddrStr = "2401:fa00:49c:484:dc41:e6ff:fefd:f180";
+ final Inet6Address globalAddr = (Inet6Address) InetAddresses
+ .parseNumericAddress(globalAddrStr);
+ final Inet6Address updatedGlobalAddr = InetAddressUtils.withScopeId(globalAddr, scopeId);
+ assertFalse(updatedGlobalAddr.isLinkLocalAddress());
+ assertEquals(globalAddrStr, updatedGlobalAddr.getHostAddress());
+ assertEquals(0, updatedGlobalAddr.getScopeId());
+
+ final String localAddrStr = "fe80::4735:9628:d038:2087";
+ final Inet6Address localAddr = (Inet6Address) InetAddresses
+ .parseNumericAddress(localAddrStr);
+ final Inet6Address updatedLocalAddr = InetAddressUtils.withScopeId(localAddr, scopeId);
+ assertTrue(updatedLocalAddr.isLinkLocalAddress());
+ assertEquals(localAddrStr + "%" + scopeId, updatedLocalAddr.getHostAddress());
+ assertEquals(scopeId, updatedLocalAddr.getScopeId());
+ }
}
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt b/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt
index 86631c3..cf0490c 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt
@@ -17,10 +17,14 @@
package com.android.testutils
import android.net.MacAddress
+import com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN
import java.net.Inet4Address
import java.net.InetAddress
import java.nio.ByteBuffer
+private const val ARP_SENDER_MAC_OFFSET = ETHER_HEADER_LEN + 8
+private const val ARP_TARGET_IPADDR_OFFSET = ETHER_HEADER_LEN + 24
+
private val TYPE_ARP = byteArrayOf(0x08, 0x06)
// Arp reply header for IPv4 over ethernet
private val ARP_REPLY_IPV4 = byteArrayOf(0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02)
diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/PacketFilter.kt b/staticlibs/testutils/hostdevice/com/android/testutils/PacketFilter.kt
index 7c615d0..1bb6d68 100644
--- a/staticlibs/testutils/hostdevice/com/android/testutils/PacketFilter.kt
+++ b/staticlibs/testutils/hostdevice/com/android/testutils/PacketFilter.kt
@@ -19,24 +19,25 @@
import java.net.Inet4Address
import java.util.function.Predicate
-const val ETHER_TYPE_OFFSET = 12
-const val ETHER_HEADER_LENGTH = 14
-const val IPV4_PROTOCOL_OFFSET = ETHER_HEADER_LENGTH + 9
-const val IPV4_CHECKSUM_OFFSET = ETHER_HEADER_LENGTH + 10
-const val IPV4_DST_OFFSET = ETHER_HEADER_LENGTH + 16
-const val IPV4_HEADER_LENGTH = 20
-const val IPV4_UDP_OFFSET = ETHER_HEADER_LENGTH + IPV4_HEADER_LENGTH
-const val IPV4_UDP_SRCPORT_OFFSET = IPV4_UDP_OFFSET
-const val IPV4_UDP_DSTPORT_OFFSET = IPV4_UDP_OFFSET + 2
-const val UDP_HEADER_LENGTH = 8
-const val BOOTP_OFFSET = IPV4_UDP_OFFSET + UDP_HEADER_LENGTH
-const val BOOTP_TID_OFFSET = BOOTP_OFFSET + 4
-const val BOOTP_CLIENT_MAC_OFFSET = BOOTP_OFFSET + 28
-const val DHCP_OPTIONS_OFFSET = BOOTP_OFFSET + 240
-
-const val ARP_OPCODE_OFFSET = ETHER_HEADER_LENGTH + 6
-const val ARP_SENDER_MAC_OFFSET = ETHER_HEADER_LENGTH + 8
-const val ARP_TARGET_IPADDR_OFFSET = ETHER_HEADER_LENGTH + 24
+// Some of the below constants are duplicated with NetworkStackConstants, but this is a hostdevice
+// library usable for host-side tests, so device-side utils are not usable, and there is no
+// host-side non-test library to host common constants.
+private const val ETHER_TYPE_OFFSET = 12
+private const val ETHER_HEADER_LENGTH = 14
+private const val IPV4_PROTOCOL_OFFSET = ETHER_HEADER_LENGTH + 9
+private const val IPV6_PROTOCOL_OFFSET = ETHER_HEADER_LENGTH + 6
+private const val IPV4_CHECKSUM_OFFSET = ETHER_HEADER_LENGTH + 10
+private const val IPV4_DST_OFFSET = ETHER_HEADER_LENGTH + 16
+private const val IPV4_HEADER_LENGTH = 20
+private const val IPV6_HEADER_LENGTH = 40
+private const val IPV4_PAYLOAD_OFFSET = ETHER_HEADER_LENGTH + IPV4_HEADER_LENGTH
+private const val IPV6_PAYLOAD_OFFSET = ETHER_HEADER_LENGTH + IPV6_HEADER_LENGTH
+private const val UDP_HEADER_LENGTH = 8
+private const val BOOTP_OFFSET = IPV4_PAYLOAD_OFFSET + UDP_HEADER_LENGTH
+private const val BOOTP_TID_OFFSET = BOOTP_OFFSET + 4
+private const val BOOTP_CLIENT_MAC_OFFSET = BOOTP_OFFSET + 28
+private const val DHCP_OPTIONS_OFFSET = BOOTP_OFFSET + 240
+private const val ARP_OPCODE_OFFSET = ETHER_HEADER_LENGTH + 6
/**
* A [Predicate] that matches a [ByteArray] if it contains the specified [bytes] at the specified
@@ -47,12 +48,48 @@
bytes.withIndex().all { it.value == packet[offset + it.index] }
}
+private class UdpPortFilter(
+ private val udpOffset: Int,
+ private val src: Short?,
+ private val dst: Short?
+) : Predicate<ByteArray> {
+ override fun test(t: ByteArray): Boolean {
+ if (src != null && !OffsetFilter(udpOffset,
+ src.toInt().ushr(8).toByte(), src.toByte()).test(t)) {
+ return false
+ }
+
+ if (dst != null && !OffsetFilter(udpOffset + 2,
+ dst.toInt().ushr(8).toByte(), dst.toByte()).test(t)) {
+ return false
+ }
+ return true
+ }
+}
+
/**
* A [Predicate] that matches ethernet-encapped packets that contain an UDP over IPv4 datagram.
*/
-class IPv4UdpFilter : Predicate<ByteArray> {
+class IPv4UdpFilter @JvmOverloads constructor(
+ srcPort: Short? = null,
+ dstPort: Short? = null
+) : Predicate<ByteArray> {
private val impl = OffsetFilter(ETHER_TYPE_OFFSET, 0x08, 0x00 /* IPv4 */).and(
- OffsetFilter(IPV4_PROTOCOL_OFFSET, 17 /* UDP */))
+ OffsetFilter(IPV4_PROTOCOL_OFFSET, 17 /* UDP */)).and(
+ UdpPortFilter(IPV4_PAYLOAD_OFFSET, srcPort, dstPort))
+ override fun test(t: ByteArray) = impl.test(t)
+}
+
+/**
+ * A [Predicate] that matches ethernet-encapped packets that contain an UDP over IPv6 datagram.
+ */
+class IPv6UdpFilter @JvmOverloads constructor(
+ srcPort: Short? = null,
+ dstPort: Short? = null
+) : Predicate<ByteArray> {
+ private val impl = OffsetFilter(ETHER_TYPE_OFFSET, 0x86.toByte(), 0xdd.toByte() /* IPv6 */).and(
+ OffsetFilter(IPV6_PROTOCOL_OFFSET, 17 /* UDP */)).and(
+ UdpPortFilter(IPV6_PAYLOAD_OFFSET, srcPort, dstPort))
override fun test(t: ByteArray) = impl.test(t)
}
@@ -77,9 +114,7 @@
* A [Predicate] that matches ethernet-encapped DHCP packets sent from a DHCP client.
*/
class DhcpClientPacketFilter : Predicate<ByteArray> {
- private val impl = IPv4UdpFilter()
- .and(OffsetFilter(IPV4_UDP_SRCPORT_OFFSET, 0x00, 0x44 /* 68 */))
- .and(OffsetFilter(IPV4_UDP_DSTPORT_OFFSET, 0x00, 0x43 /* 67 */))
+ private val impl = IPv4UdpFilter(srcPort = 68, dstPort = 67)
override fun test(t: ByteArray) = impl.test(t)
}