Merge "Remove ambiguity when using error().code()."
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index 4c58228..50cfb02 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -334,31 +334,3 @@
         "//packages/modules/Wifi/service",
     ],
 }
-
-// This file group is deprecated; new users should use net-utils-annotations
-filegroup {
-    name: "net-utils-annotations-srcs",
-    srcs: [
-        "annotations/android/net/annotations/PolicyDirection.java",
-    ],
-    visibility: [
-        "//frameworks/base",
-    ],
-}
-
-
-java_library {
-    name: "net-utils-annotations",
-    srcs: [":net-utils-annotations-srcs"],
-    libs: [
-        "framework-annotations-lib",
-    ],
-    sdk_version: "system_current",
-    min_sdk_version: "30",
-    visibility: ["//visibility:public"],
-    apex_available: [
-        "//apex_available:anyapex",
-        "//apex_available:platform",
-    ],
-    lint: { strict_updatability_linting: true },
-}
diff --git a/staticlibs/annotations/android/net/annotations/PolicyDirection.java b/staticlibs/annotations/android/net/annotations/PolicyDirection.java
deleted file mode 100644
index febd9b4..0000000
--- a/staticlibs/annotations/android/net/annotations/PolicyDirection.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.annotations;
-
-import android.annotation.IntDef;
-import android.net.IpSecManager;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * IPsec traffic direction.
- *
- * <p>Mainline modules cannot reference hidden @IntDef. Moving this annotation to a separate class
- * to allow others to statically include it.
- *
- * @hide
- */
-@IntDef(value = {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT})
-@Retention(RetentionPolicy.SOURCE)
-public @interface PolicyDirection {}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java
index c5efcb2..1705f1c 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java
@@ -22,6 +22,7 @@
 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY;
 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY;
 
+import android.annotation.SuppressLint;
 import android.net.IpPrefix;
 import android.system.OsConstants;
 
@@ -107,6 +108,7 @@
      * @param header netlink message header.
      * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes.
      */
+    @SuppressLint("NewApi")
     @Nullable
     public static RtNetlinkRouteMessage parse(@NonNull final StructNlMsgHdr header,
             @NonNull final ByteBuffer byteBuffer) {
diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java
index f6b2e0e..8226346 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java
@@ -16,6 +16,7 @@
 
 package com.android.net.module.util.netlink;
 
+import android.annotation.SuppressLint;
 import android.net.IpPrefix;
 import android.util.Log;
 
@@ -107,6 +108,7 @@
         this.lifetime = lifetime & 0xfff8;
     }
 
+    @SuppressLint("NewApi")
     private StructNdOptPref64(@NonNull ByteBuffer buf) {
         super(buf.get(), Byte.toUnsignedInt(buf.get()));
         if (type != TYPE) throw new IllegalArgumentException("Invalid type " + type);
diff --git a/staticlibs/framework/com/android/net/module/util/BestClock.java b/staticlibs/framework/com/android/net/module/util/BestClock.java
new file mode 100644
index 0000000..35391ad
--- /dev/null
+++ b/staticlibs/framework/com/android/net/module/util/BestClock.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.net.module.util;
+
+import android.util.Log;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.util.Arrays;
+
+/**
+ * Single {@link Clock} that will return the best available time from a set of
+ * prioritized {@link Clock} instances.
+ * <p>
+ * For example, when {@link SystemClock#currentNetworkTimeClock()} isn't able to
+ * provide the time, this class could use {@link Clock#systemUTC()} instead.
+ *
+ * Note that this is re-implemented based on {@code android.os.BestClock} to be used inside
+ * the mainline module. And the class does NOT support serialization.
+ *
+ * @hide
+ */
+final public class BestClock extends Clock {
+    private static final String TAG = "BestClock";
+    private final ZoneId mZone;
+    private final Clock[] mClocks;
+
+    public BestClock(ZoneId zone, Clock... clocks) {
+        super();
+        this.mZone = zone;
+        this.mClocks = clocks;
+    }
+
+    @Override
+    public long millis() {
+        for (Clock clock : mClocks) {
+            try {
+                return clock.millis();
+            } catch (DateTimeException e) {
+                // Ignore and attempt the next clock
+                Log.w(TAG, e.toString());
+            }
+        }
+        throw new DateTimeException(
+                "No clocks in " + Arrays.toString(mClocks) + " were able to provide time");
+    }
+
+    @Override
+    public ZoneId getZone() {
+        return mZone;
+    }
+
+    @Override
+    public Clock withZone(ZoneId zone) {
+        return new BestClock(zone, mClocks);
+    }
+
+    @Override
+    public Instant instant() {
+        return Instant.ofEpochMilli(millis());
+    }
+}
diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
index 6e1af55..312ca48 100644
--- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
@@ -180,4 +180,17 @@
         }
         return matches;
     }
+
+    /**
+     * Return sum of the given long array.
+     */
+    public static long total(@Nullable long[] array) {
+        long total = 0;
+        if (array != null) {
+            for (long value : array) {
+                total += value;
+            }
+        }
+        return total;
+    }
 }
diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
index 903214e..d6222a7 100644
--- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
@@ -16,9 +16,11 @@
 
 package com.android.net.module.util;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
@@ -26,8 +28,11 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_MCX;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
@@ -74,43 +79,6 @@
     };
 
     /**
-     * See android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE
-     * TODO: Use API constant when all downstream branches are S-based
-     */
-    public static final int NET_CAPABILITY_OEM_PRIVATE = 26;
-
-    /**
-     * See android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL
-     * TODO: Use API constant when all downstream branches are S-based
-     */
-    public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27;
-
-    /**
-     * See android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
-     * TODO: Use API constant when all downstream branches are S-based
-     */
-    public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28;
-
-    /**
-     * See android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE
-     * TODO: Use API constant when all downstream branches are S-based
-     */
-    public static final int NET_CAPABILITY_ENTERPRISE = 29;
-
-    /**
-     * See android.net.NetworkCapabilities.NET_CAPABILITY_VSIM
-     * TODO: Use API constant when all downstream branches are S-based
-     */
-    public static final int NET_CAPABILITY_VSIM = 30;
-
-    /**
-     * See android.net.NetworkCapabilities.NET_CAPABILITY_BIP
-     * TODO: Use API constant when all downstream branches are S-based
-     */
-    public static final int NET_CAPABILITY_BIP = 31;
-
-
-    /**
      * Capabilities that suggest that a network is restricted.
      * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted},
       * and {@code FORCE_RESTRICTED_CAPABILITIES}.
diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java
new file mode 100644
index 0000000..d4ad1f2
--- /dev/null
+++ b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.net.module.util;
+
+/**
+ * Various utilities used for NetworkStats related code.
+ *
+ * @hide
+ */
+public class NetworkStatsUtils {
+    /**
+     * Safely multiple a value by a rational.
+     * <p>
+     * Internally it uses integer-based math whenever possible, but switches
+     * over to double-based math if values would overflow.
+     * @hide
+     */
+    public static long multiplySafeByRational(long value, long num, long den) {
+        if (den == 0) {
+            throw new ArithmeticException("Invalid Denominator");
+        }
+        long x = value;
+        long y = num;
+
+        // Logic shamelessly borrowed from Math.multiplyExact()
+        long r = x * y;
+        long ax = Math.abs(x);
+        long ay = Math.abs(y);
+        if (((ax | ay) >>> 31 != 0)) {
+            // Some bits greater than 2^31 that might cause overflow
+            // Check the result using the divide operator
+            // and check for the special case of Long.MIN_VALUE * -1
+            if (((y != 0) && (r / y != x))
+                    || (x == Long.MIN_VALUE && y == -1)) {
+                // Use double math to avoid overflowing
+                return (long) (((double) num / den) * value);
+            }
+        }
+        return r / den;
+    }
+
+    /**
+     * Value of the match rule of the subscriberId to match networks with specific subscriberId.
+     *
+     * @hide
+     */
+    public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0;
+    /**
+     * Value of the match rule of the subscriberId to match networks with any subscriberId which
+     * includes null and non-null.
+     *
+     * @hide
+     */
+    public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1;
+
+    /**
+     * Return the constrained value by given the lower and upper bounds.
+     */
+    public static int constrain(int amount, int low, int high) {
+        if (low > high) throw new IllegalArgumentException("low(" + low + ") > high(" + high + ")");
+        return amount < low ? low : (amount > high ? high : amount);
+    }
+
+    /**
+     * Return the constrained value by given the lower and upper bounds.
+     */
+    public static long constrain(long amount, long low, long high) {
+        if (low > high) throw new IllegalArgumentException("low(" + low + ") > high(" + high + ")");
+        return amount < low ? low : (amount > high ? high : amount);
+    }
+}
diff --git a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java
index 10eda57..0f3dc15 100644
--- a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java
@@ -16,13 +16,18 @@
 
 package com.android.net.module.util;
 
+import static android.Manifest.permission.ACCESS_NETWORK_STATE;
+import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
 import static android.Manifest.permission.NETWORK_STACK;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
+import android.os.Binder;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 
@@ -80,4 +85,63 @@
         permissions.add(PERMISSION_MAINLINE_NETWORK_STACK);
         enforceAnyPermissionOf(context, permissions.toArray(new String[0]));
     }
+
+    /**
+     * If the CONNECTIVITY_USE_RESTRICTED_NETWORKS is not allowed for a particular process, throw a
+     * {@link SecurityException}.
+     *
+     * @param context {@link android.content.Context} for the process.
+     * @param message A message to include in the exception if it is thrown.
+     */
+    public static void enforceRestrictedNetworkPermission(
+            final @NonNull Context context, final @Nullable String message) {
+        context.enforceCallingOrSelfPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, message);
+    }
+
+    /**
+     * If the ACCESS_NETWORK_STATE is not allowed for a particular process, throw a
+     * {@link SecurityException}.
+     *
+     * @param context {@link android.content.Context} for the process.
+     * @param message A message to include in the exception if it is thrown.
+     */
+    public static void enforceAccessNetworkStatePermission(
+            final @NonNull Context context, final @Nullable String message) {
+        context.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, message);
+    }
+
+    /**
+     * Return true if the context has DUMP permission.
+     */
+    public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+        if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump " + tag + " from from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " due to missing android.permission.DUMP permission");
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Enforce that a given feature is available and if not, throw an
+     * {@link UnsupportedOperationException}.
+     *
+     * @param context {@link android.content.Context} for the process.
+     * @param feature the feature name to enforce.
+     * @param errorMessage an optional error message to include.
+     */
+    public static void enforceSystemFeature(final @NonNull Context context,
+            final @NonNull String feature, final @Nullable String errorMessage) {
+        final boolean hasSystemFeature =
+                context.getPackageManager().hasSystemFeature(feature);
+        if (!hasSystemFeature) {
+            if (null == errorMessage) {
+                throw new UnsupportedOperationException();
+            }
+            throw new UnsupportedOperationException(errorMessage);
+        }
+    }
 }
diff --git a/staticlibs/native/bpf_map_utils/Android.bp b/staticlibs/native/bpf_headers/Android.bp
similarity index 90%
rename from staticlibs/native/bpf_map_utils/Android.bp
rename to staticlibs/native/bpf_headers/Android.bp
index e14c259..06ba1b0 100644
--- a/staticlibs/native/bpf_map_utils/Android.bp
+++ b/staticlibs/native/bpf_headers/Android.bp
@@ -17,15 +17,18 @@
 }
 
 cc_library_headers {
-    name: "bpf_map_utils",
-    vendor_available: true,
+    name: "bpf_headers",
+    vendor_available: false,
     host_supported: true,
     native_bridge_supported: true,
+    header_libs: ["bpf_syscall_wrappers"],
+    export_header_lib_headers: ["bpf_syscall_wrappers"],
     export_include_dirs: ["include"],
     cflags: [
         "-Wall",
         "-Werror",
     ],
+    sdk_version: "30",
     min_sdk_version: "30",
     apex_available: [
         "//apex_available:platform",
@@ -40,6 +43,7 @@
         "//frameworks/native/services/gpuservice/gpumem",
         "//frameworks/native/services/gpuservice/tests/unittests",
         "//frameworks/native/services/gpuservice/tracing",
+        "//packages/modules/Connectivity/bpf_progs",
         "//packages/modules/Connectivity/netd",
         "//packages/modules/Connectivity/tests/unit/jni",
         "//packages/modules/DnsResolver/tests",
diff --git a/staticlibs/native/bpf_map_utils/BpfMapTest.cpp b/staticlibs/native/bpf_headers/BpfMapTest.cpp
similarity index 100%
rename from staticlibs/native/bpf_map_utils/BpfMapTest.cpp
rename to staticlibs/native/bpf_headers/BpfMapTest.cpp
diff --git a/staticlibs/native/bpf_map_utils/TEST_MAPPING b/staticlibs/native/bpf_headers/TEST_MAPPING
similarity index 100%
rename from staticlibs/native/bpf_map_utils/TEST_MAPPING
rename to staticlibs/native/bpf_headers/TEST_MAPPING
diff --git a/staticlibs/native/bpf_map_utils/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h
similarity index 100%
rename from staticlibs/native/bpf_map_utils/include/bpf/BpfMap.h
rename to staticlibs/native/bpf_headers/include/bpf/BpfMap.h
diff --git a/staticlibs/native/bpf_map_utils/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h
similarity index 100%
rename from staticlibs/native/bpf_map_utils/include/bpf/BpfUtils.h
rename to staticlibs/native/bpf_headers/include/bpf/BpfUtils.h
diff --git a/staticlibs/native/bpf_map_utils/include/bpf/WaitForProgsLoaded.h b/staticlibs/native/bpf_headers/include/bpf/WaitForProgsLoaded.h
similarity index 100%
rename from staticlibs/native/bpf_map_utils/include/bpf/WaitForProgsLoaded.h
rename to staticlibs/native/bpf_headers/include/bpf/WaitForProgsLoaded.h
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
new file mode 100644
index 0000000..878bb10
--- /dev/null
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
@@ -0,0 +1,216 @@
+/* Common BPF helpers to be used by all BPF programs loaded by Android */
+
+#include <linux/bpf.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "bpf_map_def.h"
+
+/******************************************************************************
+ * WARNING: CHANGES TO THIS FILE OUTSIDE OF AOSP/MASTER ARE LIKELY TO BREAK   *
+ * DEVICE COMPATIBILITY WITH MAINLINE MODULES SHIPPING EBPF CODE.             *
+ *                                                                            *
+ * THIS WILL LIKELY RESULT IN BRICKED DEVICES AT SOME ARBITRARY FUTURE TIME   *
+ *                                                                            *
+ * THAT GOES ESPECIALLY FOR THE 'SECTION' 'LICENSE' AND 'CRITICAL' MACROS     *
+ *                                                                            *
+ * We strongly suggest that if you need changes to bpfloader functionality    *
+ * you get your changes reviewed and accepted into aosp/master.               *
+ *                                                                            *
+ ******************************************************************************/
+
+/* 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.
+ *
+ * While this will work outside of mainline too, there just is no point to
+ * using it when the .o and the bpfloader ship in sync with each other.
+ */
+#ifndef BPFLOADER_MIN_VER
+#define BPFLOADER_MIN_VER DEFAULT_BPFLOADER_MIN_VER
+#endif
+
+#ifndef BPFLOADER_MAX_VER
+#define BPFLOADER_MAX_VER DEFAULT_BPFLOADER_MAX_VER
+#endif
+
+/* place things in different elf sections */
+#define SECTION(NAME) __attribute__((section(NAME), used))
+
+/* Must be present in every program, example usage:
+ *   LICENSE("GPL"); or LICENSE("Apache 2.0");
+ *
+ * We also take this opportunity to embed a bunch of other useful values in
+ * the resulting .o (This is to enable some limited forward compatibility
+ * with mainline module shipped ebpf programs)
+ *
+ * The bpfloader_{min/max}_ver defines the [min, max) range of bpfloader
+ * versions that should load this .o file (bpfloaders outside of this range
+ * will simply ignore/skip this *entire* .o)
+ * The [inclusive,exclusive) matches what we do for kernel ver dependencies.
+ *
+ * The size_of_bpf_{map,prog}_def allow the bpfloader to load programs where
+ * these structures have been extended with additional fields (they will of
+ * course simply be ignored then).
+ *
+ * If missing, bpfloader_{min/max}_ver default to 0/0x10000 ie. [v0.0, v1.0),
+ * while size_of_bpf_{map/prog}_def default to 32/20 which are the v0.0 sizes.
+ */
+#define LICENSE(NAME)                                                                           \
+    unsigned int _bpfloader_min_ver SECTION("bpfloader_min_ver") = BPFLOADER_MIN_VER;           \
+    unsigned int _bpfloader_max_ver SECTION("bpfloader_max_ver") = BPFLOADER_MAX_VER;           \
+    size_t _size_of_bpf_map_def SECTION("size_of_bpf_map_def") = sizeof(struct bpf_map_def);    \
+    size_t _size_of_bpf_prog_def SECTION("size_of_bpf_prog_def") = sizeof(struct bpf_prog_def); \
+    char _license[] SECTION("license") = (NAME)
+
+/* flag the resulting bpf .o file as critical to system functionality,
+ * loading all kernel version appropriate programs in it must succeed
+ * for bpfloader success
+ */
+#define CRITICAL(REASON) char _critical[] SECTION("critical") = (REASON)
+
+/*
+ * Helper functions called from eBPF programs written in C. These are
+ * implemented in the kernel sources.
+ */
+
+#define KVER_NONE 0
+#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
+#define KVER_INF 0xFFFFFFFFu
+
+/* generic functions */
+
+/*
+ * Type-unsafe bpf map functions - avoid if possible.
+ *
+ * Using these it is possible to pass in keys/values of the wrong type/size,
+ * or, for 'bpf_map_lookup_elem_unsafe' receive into a pointer to the wrong type.
+ * You will not get a compile time failure, and for certain types of errors you
+ * might not even get a failure from the kernel's ebpf verifier during program load,
+ * instead stuff might just not work right at runtime.
+ *
+ * Instead please use:
+ *   DEFINE_BPF_MAP(foo_map, TYPE, KeyType, ValueType, num_entries)
+ * where TYPE can be something like HASH or ARRAY, and num_entries is an integer.
+ *
+ * This defines the map (hence this should not be used in a header file included
+ * from multiple locations) and provides type safe accessors:
+ *   ValueType * bpf_foo_map_lookup_elem(const KeyType *)
+ *   int bpf_foo_map_update_elem(const KeyType *, const ValueType *, flags)
+ *   int bpf_foo_map_delete_elem(const KeyType *)
+ *
+ * This will make sure that if you change the type of a map you'll get compile
+ * errors at any spots you forget to update with the new type.
+ *
+ * Note: these all take pointers to const map because from the C/eBPF point of view
+ * the map struct is really just a readonly map definition of the in kernel object.
+ * Runtime modification of the map defining struct is meaningless, since
+ * the contents is only ever used during bpf program loading & map creation
+ * by the bpf loader, and not by the eBPF program itself.
+ */
+static void* (*bpf_map_lookup_elem_unsafe)(const struct bpf_map_def* map,
+                                           const void* key) = (void*)BPF_FUNC_map_lookup_elem;
+static int (*bpf_map_update_elem_unsafe)(const struct bpf_map_def* map, const void* key,
+                                         const void* value, unsigned long long flags) = (void*)
+        BPF_FUNC_map_update_elem;
+static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map,
+                                         const void* key) = (void*)BPF_FUNC_map_delete_elem;
+
+/* type safe macro to declare a map and related accessor functions */
+#define DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, usr, grp, md)     \
+    const struct bpf_map_def SECTION("maps") the_map = {                                         \
+            .type = BPF_MAP_TYPE_##TYPE,                                                         \
+            .key_size = sizeof(TypeOfKey),                                                       \
+            .value_size = sizeof(TypeOfValue),                                                   \
+            .max_entries = (num_entries),                                                        \
+            .map_flags = 0,                                                                      \
+            .uid = (usr),                                                                        \
+            .gid = (grp),                                                                        \
+            .mode = (md),                                                                        \
+            .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER,                                      \
+            .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER,                                      \
+            .min_kver = KVER_NONE,                                                               \
+            .max_kver = KVER_INF,                                                                \
+    };                                                                                           \
+                                                                                                 \
+    static inline __always_inline __unused TypeOfValue* bpf_##the_map##_lookup_elem(             \
+            const TypeOfKey* k) {                                                                \
+        return bpf_map_lookup_elem_unsafe(&the_map, k);                                          \
+    };                                                                                           \
+                                                                                                 \
+    static inline __always_inline __unused int bpf_##the_map##_update_elem(                      \
+            const TypeOfKey* k, const TypeOfValue* v, unsigned long long flags) {                \
+        return bpf_map_update_elem_unsafe(&the_map, k, v, flags);                                \
+    };                                                                                           \
+                                                                                                 \
+    static inline __always_inline __unused int bpf_##the_map##_delete_elem(const TypeOfKey* k) { \
+        return bpf_map_delete_elem_unsafe(&the_map, k);                                          \
+    };
+
+#define DEFINE_BPF_MAP(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
+    DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, AID_ROOT, 0600)
+
+#define DEFINE_BPF_MAP_GWO(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \
+    DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0620)
+
+#define DEFINE_BPF_MAP_GRO(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \
+    DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0640)
+
+#define DEFINE_BPF_MAP_GRW(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \
+    DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0660)
+
+static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read;
+static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str;
+static unsigned long long (*bpf_ktime_get_ns)(void) = (void*) BPF_FUNC_ktime_get_ns;
+static unsigned long long (*bpf_ktime_get_boot_ns)(void) = (void*)BPF_FUNC_ktime_get_boot_ns;
+static int (*bpf_trace_printk)(const char* fmt, int fmt_size, ...) = (void*) BPF_FUNC_trace_printk;
+static unsigned long long (*bpf_get_current_pid_tgid)(void) = (void*) BPF_FUNC_get_current_pid_tgid;
+static unsigned long long (*bpf_get_current_uid_gid)(void) = (void*) BPF_FUNC_get_current_uid_gid;
+static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_get_smp_processor_id;
+
+#define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
+                                       opt)                                                        \
+    const struct bpf_prog_def SECTION("progs") the_prog##_def = {                                  \
+            .uid = (prog_uid),                                                                     \
+            .gid = (prog_gid),                                                                     \
+            .min_kver = (min_kv),                                                                  \
+            .max_kver = (max_kv),                                                                  \
+            .optional = (opt),                                                                     \
+            .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER,                                        \
+            .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER,                                        \
+    };                                                                                             \
+    SECTION(SECTION_NAME)                                                                          \
+    int the_prog
+
+// Programs (here used in the sense of functions/sections) marked optional are allowed to fail
+// to load (for example due to missing kernel patches).
+// The bpfloader will just ignore these failures and continue processing the next section.
+//
+// A non-optional program (function/section) failing to load causes a failure and aborts
+// processing of the entire .o, if the .o is additionally marked critical, this will result
+// in the entire bpfloader process terminating with a failure and not setting the bpf.progs_loaded
+// system property.  This in turn results in waitForProgsLoaded() never finishing.
+//
+// ie. a non-optional program in a critical .o is mandatory for kernels matching the min/max kver.
+
+// programs requiring a kernel version >= min_kv && < max_kv
+#define DEFINE_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv) \
+    DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
+                                   false)
+#define DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, \
+                                            max_kv)                                             \
+    DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, true)
+
+// programs requiring a kernel version >= min_kv
+#define DEFINE_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv)                 \
+    DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF, \
+                                   false)
+#define DEFINE_OPTIONAL_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv)        \
+    DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF, \
+                                   true)
+
+// programs with no kernel version requirements
+#define DEFINE_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
+    DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF, false)
+#define DEFINE_OPTIONAL_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
+    DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF, true)
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
new file mode 100644
index 0000000..02b2096
--- /dev/null
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/* This file is separate because it's included both by eBPF programs (via include
+ * in bpf_helpers.h) and directly by the boot time bpfloader (Loader.cpp).
+ */
+
+#include <linux/bpf.h>
+
+// Pull in AID_* constants from //system/core/libcutils/include/private/android_filesystem_config.h
+#include <private/android_filesystem_config.h>
+
+/******************************************************************************
+ *                                                                            *
+ *                          ! ! ! W A R N I N G ! ! !                         *
+ *                                                                            *
+ * CHANGES TO THESE STRUCTURE DEFINITIONS OUTSIDE OF AOSP/MASTER *WILL* BREAK *
+ * MAINLINE MODULE COMPATIBILITY                                              *
+ *                                                                            *
+ * AND THUS MAY RESULT IN YOUR DEVICE BRICKING AT SOME ARBITRARY POINT IN     *
+ * THE FUTURE                                                                 *
+ *                                                                            *
+ * (and even in aosp/master you may only append new fields at the very end,   *
+ *  you may *never* delete fields, change their types, ordering, insert in    *
+ *  the middle, etc.  If a mainline module using the old definition has       *
+ *  already shipped (which happens roughly monthly), then it's set in stone)  *
+ *                                                                            *
+ ******************************************************************************/
+
+// These are the values used if these fields are missing
+#define DEFAULT_BPFLOADER_MIN_VER 0u        // v0.0 (this is inclusive ie. >= v0.0)
+#define DEFAULT_BPFLOADER_MAX_VER 0x10000u  // v1.0 (this is exclusive ie. < v1.0)
+#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
+
+/*
+ * The bpf_{map,prog}_def structures are compiled for different architectures.
+ * Once by the BPF compiler for the BPF architecture, and once by a C++
+ * compiler for the native Android architecture for the bpfloader.
+ *
+ * For things to work, their layout must be the same between the two.
+ * The BPF architecture is platform independent ('64-bit LSB bpf').
+ * So this effectively means these structures must be the same layout
+ * on 5 architectures, all of them little endian:
+ *   64-bit BPF, x86_64, arm  and  32-bit x86 and arm
+ *
+ * As such for any types we use inside of these structs we must make sure that
+ * the size and alignment are the same, so the same amount of padding is used.
+ *
+ * Currently we only use: bool, enum bpf_map_type and unsigned int.
+ * Additionally we use char for padding.
+ *
+ * !!! WARNING: HERE BE DRAGONS !!!
+ *
+ * Be particularly careful with 64-bit integers.
+ * You will need to manually override their alignment to 8 bytes.
+ *
+ * To quote some parts of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69560
+ *
+ * Some types have weaker alignment requirements when they are structure members.
+ *
+ * unsigned long long on x86 is such a type.
+ *
+ * C distinguishes C11 _Alignof (the minimum alignment the type is guaranteed
+ * to have in all contexts, so 4, see min_align_of_type) from GNU C __alignof
+ * (the normal alignment of the type, so 8).
+ *
+ * alignof / _Alignof == minimum alignment required by target ABI
+ * __alignof / __alignof__ == preferred alignment
+ *
+ * When in a struct, apparently the minimum alignment is used.
+ */
+
+_Static_assert(sizeof(bool) == 1, "sizeof bool != 1");
+_Static_assert(__alignof__(bool) == 1, "__alignof__ bool != 1");
+_Static_assert(_Alignof(bool) == 1, "_Alignof bool != 1");
+
+_Static_assert(sizeof(char) == 1, "sizeof char != 1");
+_Static_assert(__alignof__(char) == 1, "__alignof__ char != 1");
+_Static_assert(_Alignof(char) == 1, "_Alignof char != 1");
+
+// This basically verifies that an enum is 'just' a 32-bit int
+_Static_assert(sizeof(enum bpf_map_type) == 4, "sizeof enum bpf_map_type != 4");
+_Static_assert(__alignof__(enum bpf_map_type) == 4, "__alignof__ enum bpf_map_type != 4");
+_Static_assert(_Alignof(enum bpf_map_type) == 4, "_Alignof enum bpf_map_type != 4");
+
+// Linux kernel requires sizeof(int) == 4, sizeof(void*) == sizeof(long), sizeof(long long) == 8
+_Static_assert(sizeof(unsigned int) == 4, "sizeof unsigned int != 4");
+_Static_assert(__alignof__(unsigned int) == 4, "__alignof__ unsigned int != 4");
+_Static_assert(_Alignof(unsigned int) == 4, "_Alignof unsigned int != 4");
+
+// We don't currently use any 64-bit types in these structs, so this is purely to document issue.
+// Here sizeof & __alignof__ are consistent, but _Alignof is not: compile for 'aosp_cf_x86_phone'
+_Static_assert(sizeof(unsigned long long) == 8, "sizeof unsigned long long != 8");
+_Static_assert(__alignof__(unsigned long long) == 8, "__alignof__ unsigned long long != 8");
+// BPF wants 8, but 32-bit x86 wants 4
+//_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8");
+
+/*
+ * Map structure to be used by Android eBPF C programs. The Android eBPF loader
+ * uses this structure from eBPF object to create maps at boot time.
+ *
+ * The eBPF C program should define structure in the maps section using
+ * SECTION("maps") otherwise it will be ignored by the eBPF loader.
+ *
+ * For example:
+ *   const struct bpf_map_def SECTION("maps") mymap { .type=... , .key_size=... }
+ *
+ * See 'bpf_helpers.h' for helpful macros for eBPF program use.
+ */
+struct bpf_map_def {
+    enum bpf_map_type type;
+    unsigned int key_size;
+    unsigned int value_size;
+    unsigned int max_entries;
+    unsigned int map_flags;
+
+    // The following are not supported by the Android bpfloader:
+    //   unsigned int inner_map_idx;
+    //   unsigned int numa_node;
+
+    unsigned int uid;   // uid_t
+    unsigned int gid;   // gid_t
+    unsigned int mode;  // mode_t
+
+    // The following fields were added in version 0.1
+    unsigned int bpfloader_min_ver;  // if missing, defaults to 0, ie. v0.0
+    unsigned int bpfloader_max_ver;  // if missing, defaults to 0x10000, ie. v1.0
+
+    // The following fields were added in version 0.2
+    // kernelVersion() must be >= min_kver and < max_kver
+    unsigned int min_kver;
+    unsigned int max_kver;
+};
+
+// This needs to be updated whenever the above structure definition is expanded.
+_Static_assert(sizeof(struct bpf_map_def) == 48, "sizeof struct bpf_map_def != 48");
+_Static_assert(__alignof__(struct bpf_map_def) == 4, "__alignof__ struct bpf_map_def != 4");
+_Static_assert(_Alignof(struct bpf_map_def) == 4, "_Alignof struct bpf_map_def != 4");
+
+struct bpf_prog_def {
+    unsigned int uid;
+    unsigned int gid;
+
+    // kernelVersion() must be >= min_kver and < max_kver
+    unsigned int min_kver;
+    unsigned int max_kver;
+
+    bool optional;  // program section (ie. function) may fail to load, continue onto next func.
+    char pad0[3];
+
+    // The following fields were added in version 0.1
+    unsigned int bpfloader_min_ver;  // if missing, defaults to 0, ie. v0.0
+    unsigned int bpfloader_max_ver;  // if missing, defaults to 0x10000, ie. v1.0
+
+    // No new fields in version 0.2
+};
+
+// This needs to be updated whenever the above structure definition is expanded.
+_Static_assert(sizeof(struct bpf_prog_def) == 28, "sizeof struct bpf_prog_def != 28");
+_Static_assert(__alignof__(struct bpf_prog_def) == 4, "__alignof__ struct bpf_prog_def != 4");
+_Static_assert(_Alignof(struct bpf_prog_def) == 4, "_Alignof struct bpf_prog_def != 4");
diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp
index 037e10d..1a1b53c 100644
--- a/staticlibs/native/bpf_syscall_wrappers/Android.bp
+++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp
@@ -19,7 +19,7 @@
 cc_library_headers {
     name: "bpf_syscall_wrappers",
     vendor_available: false,
-    host_supported: false,
+    host_supported: true,
     native_bridge_supported: true,
     export_include_dirs: ["include"],
     cflags: [
@@ -34,6 +34,7 @@
         "com.android.tethering",
     ],
     visibility: [
+        "//frameworks/libs/net/common/native/bpf_headers",
         "//frameworks/libs/net/common/native/bpfmapjni",
         "//packages/modules/Connectivity/netd",
         "//packages/modules/Connectivity/service",
diff --git a/staticlibs/native/ip_checksum/Android.bp b/staticlibs/native/ip_checksum/Android.bp
index d7e195d..9878d73 100644
--- a/staticlibs/native/ip_checksum/Android.bp
+++ b/staticlibs/native/ip_checksum/Android.bp
@@ -37,4 +37,10 @@
     //
     // TODO: delete libnetutils from the VNDK in T, and remove this.
     vendor_available: true,
+
+    min_sdk_version: "30",
+    apex_available: [
+        "com.android.tethering",
+        "//apex_available:platform",
+    ],
 }
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
index 96648a5..911483a 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
@@ -77,4 +77,13 @@
         assertFalse(CollectionUtils.contains(arrayOf("A", "B", "C"), "D"))
         assertFalse(CollectionUtils.contains(null, "A"))
     }
+
+    @Test
+    fun testTotal() {
+        assertEquals(10, CollectionUtils.total(longArrayOf(3, 6, 1)))
+        assertEquals(10, CollectionUtils.total(longArrayOf(6, 1, 3)))
+        assertEquals(10, CollectionUtils.total(longArrayOf(1, 3, 6)))
+        assertEquals(3, CollectionUtils.total(longArrayOf(1, 1, 1)))
+        assertEquals(0, CollectionUtils.total(null))
+    }
 }
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java
index f44b17d..20bbd4a 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.annotation.SuppressLint;
 import android.net.InetAddresses;
 import android.net.IpPrefix;
 
@@ -92,6 +93,7 @@
         }
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testConstructor() {
         IpRange r = new IpRange(new IpPrefix(IPV4_ADDR, 32));
@@ -119,6 +121,7 @@
         assertEquals(IPV6_RANGE_END, r.getEndAddr());
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testContainsRangeEqualRanges() {
         final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35));
@@ -129,6 +132,7 @@
         assertEquals(r1, r2);
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testContainsRangeSubset() {
         final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 64));
@@ -139,6 +143,7 @@
         assertNotEquals(r1, r2);
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testContainsRangeTruncatesLowerOrderBits() {
         final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 100));
@@ -149,6 +154,7 @@
         assertEquals(r1, r2);
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testContainsRangeSubsetSameStartAddr() {
         final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35));
@@ -159,6 +165,7 @@
         assertNotEquals(r1, r2);
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testContainsRangeOverlapping() {
         final IpRange r1 = new IpRange(new IpPrefix(address("2001:db9::"), 32));
@@ -169,6 +176,7 @@
         assertNotEquals(r1, r2);
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testOverlapsRangeEqualRanges() {
         final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35));
@@ -179,6 +187,7 @@
         assertEquals(r1, r2);
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testOverlapsRangeSubset() {
         final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35));
@@ -189,6 +198,7 @@
         assertNotEquals(r1, r2);
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testOverlapsRangeDisjoint() {
         final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 32));
@@ -199,6 +209,7 @@
         assertNotEquals(r1, r2);
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testOverlapsRangePartialOverlapLow() {
         final IpRange r1 = new IpRange(new IpPrefix(address("2001:db9::"), 32));
@@ -209,6 +220,7 @@
         assertNotEquals(r1, r2);
     }
 
+    @SuppressLint("NewApi")
     @Test
     public void testOverlapsRangePartialOverlapHigh() {
         final IpRange r1 = new IpRange(new IpPrefix(address("2001:db7::"), 32));
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java
index 3d2d6eb..09f0490 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.annotation.SuppressLint;
 import android.net.InetAddresses;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
@@ -46,6 +47,7 @@
 
 @RunWith(AndroidJUnit4.class)
 public final class LinkPropertiesUtilsTest {
+    @SuppressLint("NewApi")
     private static final IpPrefix PREFIX = new IpPrefix(toInetAddress("75.208.6.0"), 24);
     private static final InetAddress V4_ADDR = toInetAddress("75.208.6.1");
     private static final InetAddress V6_ADDR  = toInetAddress(
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt
new file mode 100644
index 0000000..ff839fe
--- /dev/null
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.net.module.util
+
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class NetworkStatsUtilsTest {
+    @Test
+    fun testMultiplySafeByRational() {
+        // Verify basic cases that the method equals to a * b / c.
+        assertEquals(3 * 5 / 2, NetworkStatsUtils.multiplySafeByRational(3, 5, 2))
+
+        // Verify input with zeros.
+        assertEquals(0 * 7 / 3, NetworkStatsUtils.multiplySafeByRational(0, 7, 3))
+        assertEquals(7 * 0 / 3, NetworkStatsUtils.multiplySafeByRational(7, 0, 3))
+        assertEquals(0 * 0 / 1, NetworkStatsUtils.multiplySafeByRational(0, 0, 1))
+        assertEquals(0, NetworkStatsUtils.multiplySafeByRational(0, Long.MAX_VALUE, Long.MAX_VALUE))
+        assertEquals(0, NetworkStatsUtils.multiplySafeByRational(Long.MAX_VALUE, 0, Long.MAX_VALUE))
+        assertFailsWith<ArithmeticException> {
+            NetworkStatsUtils.multiplySafeByRational(7, 3, 0)
+        }
+        assertFailsWith<ArithmeticException> {
+            NetworkStatsUtils.multiplySafeByRational(0, 0, 0)
+        }
+
+        // Verify cases where a * b overflows.
+        assertEquals(101, NetworkStatsUtils.multiplySafeByRational(
+                101, Long.MAX_VALUE, Long.MAX_VALUE))
+        assertEquals(721, NetworkStatsUtils.multiplySafeByRational(
+                Long.MAX_VALUE, 721, Long.MAX_VALUE))
+        assertEquals(Long.MAX_VALUE, NetworkStatsUtils.multiplySafeByRational(
+                Long.MAX_VALUE, Long.MAX_VALUE, Long.MAX_VALUE))
+        assertFailsWith<ArithmeticException> {
+            NetworkStatsUtils.multiplySafeByRational(Long.MAX_VALUE, Long.MAX_VALUE, 0)
+        }
+    }
+
+    @Test
+    fun testConstrain() {
+        assertFailsWith<IllegalArgumentException> {
+            NetworkStatsUtils.constrain(5, 6, 3) // low > high
+        }
+        assertEquals(3, NetworkStatsUtils.constrain(5, 1, 3))
+        assertEquals(3, NetworkStatsUtils.constrain(3, 1, 3))
+        assertEquals(2, NetworkStatsUtils.constrain(2, 1, 3))
+        assertEquals(1, NetworkStatsUtils.constrain(1, 1, 3))
+        assertEquals(1, NetworkStatsUtils.constrain(0, 1, 3))
+
+        assertEquals(11, NetworkStatsUtils.constrain(15, 11, 11))
+        assertEquals(11, NetworkStatsUtils.constrain(11, 11, 11))
+        assertEquals(11, NetworkStatsUtils.constrain(1, 11, 11))
+    }
+}
\ No newline at end of file
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt
index 6da5e7d..1b6cbcb 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt
@@ -18,22 +18,28 @@
 
 import android.Manifest.permission.NETWORK_STACK
 import android.content.Context
+import android.content.pm.PackageManager
 import android.content.pm.PackageManager.PERMISSION_DENIED
 import android.content.pm.PackageManager.PERMISSION_GRANTED
 import android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
 import androidx.test.filters.SmallTest
 import androidx.test.runner.AndroidJUnit4
 import com.android.net.module.util.PermissionUtils.checkAnyPermissionOf
+import com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf
 import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission
 import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr
-import com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf
+import com.android.net.module.util.PermissionUtils.enforceSystemFeature
+import org.junit.Assert
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
 import org.mockito.ArgumentMatchers.any
 import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.mock
+import kotlin.test.assertEquals
 import kotlin.test.assertFailsWith
 
 /** Tests for PermissionUtils */
@@ -43,6 +49,12 @@
     private val TEST_PERMISSION1 = "android.permission.TEST_PERMISSION1"
     private val TEST_PERMISSION2 = "android.permission.TEST_PERMISSION2"
     private val context = mock(Context::class.java)
+    private val packageManager = mock(PackageManager::class.java)
+
+    @Before
+    fun setup() {
+        doReturn(packageManager).`when`(context).packageManager
+    }
 
     @Test
     fun testEnforceAnyPermissionOf() {
@@ -90,4 +102,26 @@
         assertFailsWith<SecurityException>("Expect fail but permission granted.") {
             enforceNetworkStackPermissionOr(context, TEST_PERMISSION2) }
     }
+
+    private fun mockHasSystemFeature(featureName: String, hasFeature: Boolean) {
+        doReturn(hasFeature).`when`(packageManager)
+                .hasSystemFeature(ArgumentMatchers.eq(featureName))
+    }
+
+    @Test
+    fun testEnforceSystemFeature() {
+        val systemFeature = "test.system.feature"
+        val exceptionMessage = "test exception message"
+        mockHasSystemFeature(featureName = systemFeature, hasFeature = false)
+        val e = assertFailsWith<UnsupportedOperationException>("Should fail without feature") {
+            enforceSystemFeature(context, systemFeature, exceptionMessage) }
+        assertEquals(exceptionMessage, e.message)
+
+        mockHasSystemFeature(featureName = systemFeature, hasFeature = true)
+        try {
+            enforceSystemFeature(context, systemFeature, "")
+        } catch (e: UnsupportedOperationException) {
+            Assert.fail("Exception should have not been thrown with system feature enabled")
+        }
+    }
 }
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java
index eabc14b..4e46210 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.annotation.SuppressLint;
 import android.net.InetAddresses;
 import android.net.IpPrefix;
 import android.net.MacAddress;
@@ -453,6 +454,7 @@
         }
     }
 
+    @SuppressLint("NewApi")
     private void verifyPrefixByteArrayParsing(final PrefixMessage msg) throws Exception {
         // The original PREF64 option message has just 12 bytes for prefix byte array
         // (Highest 96 bits of the Prefix), copyOf pads the 128-bits IPv6 address with
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java
index 57248ea..beed838 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
+import android.annotation.SuppressLint;
 import android.net.IpPrefix;
 
 import androidx.test.filters.SmallTest;
@@ -51,6 +52,7 @@
         return prefixBytes;
     }
 
+    @SuppressLint("NewApi")
     private static IpPrefix prefix(String addrString, int prefixLength) throws Exception {
         return new IpPrefix(InetAddress.getByName(addrString), prefixLength);
     }