Merge "Add the fixed test case back into presubmit"
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 0b54783..bb435d8 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -206,4 +206,5 @@
 sdk {
     name: "tethering-module-sdk",
     bootclasspath_fragments: ["com.android.tethering-bootclasspath-fragment"],
+    systemserverclasspath_fragments: ["com.android.tethering-systemserverclasspath-fragment"],
 }
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 7863572..ee1c5fe 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -44,12 +44,15 @@
     bootclasspath_fragments: [
         "com.android.tethering-bootclasspath-fragment",
     ],
-    java_libs: [
-        "service-connectivity",
+    systemserverclasspath_fragments: [
+        "com.android.tethering-systemserverclasspath-fragment",
     ],
     multilib: {
         first: {
-            jni_libs: ["libservice-connectivity"],
+            jni_libs: [
+                "libservice-connectivity",
+                "libcom_android_connectivity_com_android_net_module_util_jni"
+            ],
         },
         both: {
             jni_libs: ["libframework-connectivity-jni"],
@@ -114,6 +117,12 @@
     },
 }
 
+systemserverclasspath_fragment {
+    name: "com.android.tethering-systemserverclasspath-fragment",
+    standalone_contents: ["service-connectivity"],
+    apex_available: ["com.android.tethering"],
+}
+
 override_apex {
     name: "com.android.tethering.inprocess",
     base: "com.android.tethering",
diff --git a/Tethering/tests/integration/src/android/net/TetheringTester.java b/Tethering/tests/integration/src/android/net/TetheringTester.java
index 38d74ad..d61bbb3 100644
--- a/Tethering/tests/integration/src/android/net/TetheringTester.java
+++ b/Tethering/tests/integration/src/android/net/TetheringTester.java
@@ -30,7 +30,7 @@
 import java.nio.ByteBuffer;
 import java.util.Random;
 import java.util.concurrent.TimeoutException;
-import java.util.function.Function;
+import java.util.function.Predicate;
 
 /**
  * A class simulate tethered client. When caller create TetheringTester, it would connect to
@@ -129,27 +129,43 @@
         mDownstreamReader.sendResponse(packet);
     }
 
-    private DhcpPacket getNextDhcpPacket() {
-        return getNextMatchedPacket((p) -> {
+    private DhcpPacket getNextDhcpPacket() throws Exception {
+        final byte[] packet = getNextMatchedPacket((p) -> {
+            // Test whether this is DHCP packet.
             try {
-                return DhcpPacket.decodeFullPacket(p, p.length, DhcpPacket.ENCAP_L2);
+                DhcpPacket.decodeFullPacket(p, p.length, DhcpPacket.ENCAP_L2);
             } catch (DhcpPacket.ParseException e) {
-                // Not a DHCP packet. Continue.
+                // Not a DHCP packet.
+                return false;
             }
 
-            return null;
+            return true;
         });
+
+        return packet == null ? null :
+                DhcpPacket.decodeFullPacket(packet, packet.length, DhcpPacket.ENCAP_L2);
     }
 
-    private <R> R getNextMatchedPacket(Function<byte[], R> match) {
-        byte[] packet;
-        R result;
-        while ((packet = mDownstreamReader.popPacket(PACKET_READ_TIMEOUT_MS)) != null) {
-            result = match.apply(packet);
+    public void sendPacket(ByteBuffer packet) throws Exception {
+        mDownstreamReader.sendResponse(packet);
+    }
 
-            if (result != null) return result;
+    public byte[] getNextMatchedPacket(Predicate<byte[]> filter) {
+        return mDownstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter);
+    }
+
+    public static class RemoteResponder {
+        final TapPacketReader mUpstreamReader;
+        public RemoteResponder(TapPacketReader reader) {
+            mUpstreamReader = reader;
         }
 
-        return null;
+        public void sendPacket(ByteBuffer packet) throws Exception {
+            mUpstreamReader.sendResponse(packet);
+        }
+
+        public byte[] getNextMatchedPacket(Predicate<byte[]> filter) throws Exception {
+            return mUpstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter);
+        }
     }
 }
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 9a77a3c..827da6d 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -206,6 +206,7 @@
   }
 
   public final class IpPrefix implements android.os.Parcelable {
+    ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     method public boolean contains(@NonNull java.net.InetAddress);
     method public int describeContents();
     method @NonNull public java.net.InetAddress getAddress();
@@ -293,6 +294,7 @@
     ctor public NetworkCapabilities(android.net.NetworkCapabilities);
     method public int describeContents();
     method @NonNull public int[] getCapabilities();
+    method @NonNull public int[] getEnterpriseCapabilitySubLevels();
     method public int getLinkDownstreamBandwidthKbps();
     method public int getLinkUpstreamBandwidthKbps();
     method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
@@ -316,6 +318,7 @@
     field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
     field public static final int NET_CAPABILITY_MCX = 23; // 0x17
     field public static final int NET_CAPABILITY_MMS = 0; // 0x0
+    field public static final int NET_CAPABILITY_MMTEL = 33; // 0x21
     field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14
     field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
     field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
@@ -439,11 +442,15 @@
     method @NonNull public android.net.IpPrefix getDestination();
     method @Nullable public java.net.InetAddress getGateway();
     method @Nullable public String getInterface();
+    method public int getType();
     method public boolean hasGateway();
     method public boolean isDefaultRoute();
     method public boolean matches(java.net.InetAddress);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR;
+    field public static final int RTN_THROW = 9; // 0x9
+    field public static final int RTN_UNICAST = 1; // 0x1
+    field public static final int RTN_UNREACHABLE = 7; // 0x7
   }
 
   public abstract class SocketKeepalive implements java.lang.AutoCloseable {
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 50dd2ad..81a1e5d 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -121,6 +121,11 @@
   public final class NetworkCapabilities implements android.os.Parcelable {
     method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
     method public boolean hasForbiddenCapability(int);
+    field public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1 = 1; // 0x1
+    field public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2 = 2; // 0x2
+    field public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3 = 3; // 0x3
+    field public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4 = 4; // 0x4
+    field public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5 = 5; // 0x5
     field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
     field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L
     field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index cfab872..8d084e6 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -131,7 +131,6 @@
   }
 
   public final class IpPrefix implements android.os.Parcelable {
-    ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     ctor public IpPrefix(@NonNull String);
   }
 
@@ -295,9 +294,11 @@
     ctor public NetworkCapabilities.Builder();
     ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
     method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
+    method @NonNull public android.net.NetworkCapabilities.Builder addEnterpriseCapabilitySubLevel(int);
     method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
     method @NonNull public android.net.NetworkCapabilities build();
     method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
+    method @NonNull public android.net.NetworkCapabilities.Builder removeEnterpriseCapabilitySubLevel(int);
     method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
     method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
@@ -432,10 +433,6 @@
     ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
     ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
     method public int getMtu();
-    method public int getType();
-    field public static final int RTN_THROW = 9; // 0x9
-    field public static final int RTN_UNICAST = 1; // 0x1
-    field public static final int RTN_UNREACHABLE = 7; // 0x7
   }
 
   public abstract class SocketKeepalive implements java.lang.AutoCloseable {
diff --git a/framework/src/android/net/IpPrefix.java b/framework/src/android/net/IpPrefix.java
index bf4481a..c26a0b5 100644
--- a/framework/src/android/net/IpPrefix.java
+++ b/framework/src/android/net/IpPrefix.java
@@ -87,9 +87,7 @@
      *
      * @param address the IP address. Must be non-null.
      * @param prefixLength the prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
-     * @hide
      */
-    @SystemApi
     public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) {
         // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
         // which is unnecessary because getAddress() already returns a clone.
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 03cf109..84f7cbb 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
 
 import android.annotation.IntDef;
@@ -146,6 +148,70 @@
      */
     private String mRequestorPackageName;
 
+    /**
+     * enterprise capability sub level 1
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1 = 1;
+
+    /**
+     * enterprise capability sub level 2
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2 = 2;
+
+    /**
+     * enterprise capability sub level 3
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3 = 3;
+
+    /**
+     * enterprise capability sub level 4
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4 = 4;
+
+    /**
+     * enterprise capability sub level 5
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5 = 5;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "NET_CAPABILITY_ENTERPRISE_SUB_LEVEL" }, value = {
+            NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1,
+            NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2,
+            NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3,
+            NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4,
+            NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5,
+    })
+
+    public @interface EnterpriseCapabilitySubLevel {
+    }
+
+    /**
+     * Bitfield representing the network's enterprise capability sublevel.  If any are specified
+     * they will be satisfied by any Network that matches all of them.
+     * {@see addEnterpriseCapabilitySubLevel} for details on how masks are added
+     */
+    private int mEnterpriseCapabilitySubLevel;
+
+    /**
+     * @return all the enteprise capabilities sub level set on this {@code NetworkCapability}
+     * instance.
+     *
+     */
+    public @NonNull @EnterpriseCapabilitySubLevel int[] getEnterpriseCapabilitySubLevels() {
+        return NetworkCapabilitiesUtils.unpackBits(mEnterpriseCapabilitySubLevel);
+    }
+
     public NetworkCapabilities() {
         clearAll();
         mNetworkCapabilities = DEFAULT_CAPABILITIES;
@@ -192,6 +258,7 @@
         mRequestorPackageName = null;
         mSubIds = new ArraySet<>();
         mUnderlyingNetworks = null;
+        mEnterpriseCapabilitySubLevel = 0;
     }
 
     /**
@@ -224,6 +291,7 @@
         // mUnderlyingNetworks is an unmodifiable list if non-null, so a defensive copy is not
         // necessary.
         mUnderlyingNetworks = nc.mUnderlyingNetworks;
+        mEnterpriseCapabilitySubLevel = nc.mEnterpriseCapabilitySubLevel;
     }
 
     /**
@@ -274,6 +342,7 @@
             NET_CAPABILITY_VSIM,
             NET_CAPABILITY_BIP,
             NET_CAPABILITY_HEAD_UNIT,
+            NET_CAPABILITY_MMTEL,
     })
     public @interface NetCapability { }
 
@@ -512,8 +581,13 @@
      */
     public static final int NET_CAPABILITY_HEAD_UNIT = 32;
 
+    /**
+     * Indicates that this network has ability to support MMTEL (Multimedia Telephony service).
+     */
+    public static final int NET_CAPABILITY_MMTEL = 33;
+
     private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
-    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_HEAD_UNIT;
+    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_MMTEL;
 
     /**
      * Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -710,6 +784,38 @@
     }
 
     /**
+     * Adds the given enterprise capability sub level to this {@code NetworkCapability} instance.
+     * Note that when searching for a network to satisfy a request, all capabilities sub level
+     * requested must be satisfied.
+     *
+     * @param enterpriseCapabilitySubLevel the enterprise capability sub level to be added.
+     * @return This NetworkCapabilities instance, to facilitate chaining.
+     * @hide
+     */
+    private @NonNull NetworkCapabilities addEnterpriseCapabilitySubLevel(
+            @EnterpriseCapabilitySubLevel int enterpriseCapabilitySubLevel) {
+        checkValidEnterpriseCapabilitySublevel(enterpriseCapabilitySubLevel);
+        mEnterpriseCapabilitySubLevel |= 1 << enterpriseCapabilitySubLevel;
+        return this;
+    }
+
+    /**
+     * Removes (if found) the given enterprise capability sublevel from this
+     * {@code NetworkCapability} instance that were added via addEnterpriseCapabilitySubLevel(int)
+     *
+     * @param enterpriseCapabilitySubLevel the enterprise capability sublevel to be removed.
+     * @return This NetworkCapabilities instance, to facilitate chaining.
+     * @hide
+     */
+    private @NonNull NetworkCapabilities removeEnterpriseCapabilitySubLevel(
+            @EnterpriseCapabilitySubLevel  int enterpriseCapabilitySubLevel) {
+        checkValidEnterpriseCapabilitySublevel(enterpriseCapabilitySubLevel);
+        final int mask = ~(1 << enterpriseCapabilitySubLevel);
+        mEnterpriseCapabilitySubLevel &= mask;
+        return this;
+    }
+
+    /**
      * Set the underlying networks of this network.
      *
      * @param networks The underlying networks of this network.
@@ -809,6 +915,22 @@
         return null;
     }
 
+    private boolean equalsEnterpriseCapabilitiesSubLevel(@NonNull NetworkCapabilities nc) {
+        return nc.mEnterpriseCapabilitySubLevel == this.mEnterpriseCapabilitySubLevel;
+    }
+
+    private boolean satisfiedByEnterpriseCapabilitiesSubLevel(@NonNull NetworkCapabilities nc) {
+        final int requestedEnterpriseCapabilitiesSubLevel = mEnterpriseCapabilitySubLevel;
+        final int providedEnterpriseCapabailitiesSubLevel = nc.mEnterpriseCapabilitySubLevel;
+
+        if ((providedEnterpriseCapabailitiesSubLevel & requestedEnterpriseCapabilitiesSubLevel)
+                == requestedEnterpriseCapabilitiesSubLevel) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     private boolean satisfiedByNetCapabilities(@NonNull NetworkCapabilities nc,
             boolean onlyImmutable) {
         long requestedCapabilities = mNetworkCapabilities;
@@ -1714,6 +1836,7 @@
                 && satisfiedByTransportTypes(nc)
                 && (onlyImmutable || satisfiedByLinkBandwidths(nc))
                 && satisfiedBySpecifier(nc)
+                && satisfiedByEnterpriseCapabilitiesSubLevel(nc)
                 && (onlyImmutable || satisfiedBySignalStrength(nc))
                 && (onlyImmutable || satisfiedByUids(nc))
                 && (onlyImmutable || satisfiedBySSID(nc))
@@ -1816,7 +1939,8 @@
                 && equalsRequestor(that)
                 && equalsAdministratorUids(that)
                 && equalsSubscriptionIds(that)
-                && equalsUnderlyingNetworks(that);
+                && equalsUnderlyingNetworks(that)
+                && equalsEnterpriseCapabilitiesSubLevel(that);
     }
 
     @Override
@@ -1840,7 +1964,8 @@
                 + Objects.hashCode(mRequestorPackageName) * 59
                 + Arrays.hashCode(mAdministratorUids) * 61
                 + Objects.hashCode(mSubIds) * 67
-                + Objects.hashCode(mUnderlyingNetworks) * 71;
+                + Objects.hashCode(mUnderlyingNetworks) * 71
+                + mEnterpriseCapabilitySubLevel * 73;
     }
 
     @Override
@@ -1876,6 +2001,7 @@
         dest.writeString(mRequestorPackageName);
         dest.writeIntArray(CollectionUtils.toIntArray(mSubIds));
         dest.writeTypedList(mUnderlyingNetworks);
+        dest.writeInt(mEnterpriseCapabilitySubLevel);
     }
 
     public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1905,6 +2031,7 @@
                     netCap.mSubIds.add(subIdInts[i]);
                 }
                 netCap.setUnderlyingNetworks(in.createTypedArrayList(Network.CREATOR));
+                netCap.mEnterpriseCapabilitySubLevel = in.readInt();
                 return netCap;
             }
             @Override
@@ -1996,6 +2123,12 @@
             sb.append(" SubscriptionIds: ").append(mSubIds);
         }
 
+        if (0 != mEnterpriseCapabilitySubLevel) {
+            sb.append(" EnterpriseCapabilitySublevel: ");
+            appendStringRepresentationOfBitMaskToStringBuilder(sb, mEnterpriseCapabilitySubLevel,
+                    NetworkCapabilities::enterpriseCapabilitySublevelNameOf, "&");
+        }
+
         sb.append(" UnderlyingNetworks: ");
         if (mUnderlyingNetworks != null) {
             sb.append("[");
@@ -2090,10 +2223,16 @@
             case NET_CAPABILITY_VSIM:                 return "VSIM";
             case NET_CAPABILITY_BIP:                  return "BIP";
             case NET_CAPABILITY_HEAD_UNIT:            return "HEAD_UNIT";
+            case NET_CAPABILITY_MMTEL:                return "MMTEL";
             default:                                  return Integer.toString(capability);
         }
     }
 
+    private static @NonNull String enterpriseCapabilitySublevelNameOf(
+            @NetCapability int capability) {
+        return Integer.toString(capability);
+    }
+
     /**
      * @hide
      */
@@ -2134,6 +2273,20 @@
         }
     }
 
+    private static boolean isValidEnterpriseCapabilitySubLevel(
+            @NetworkCapabilities.EnterpriseCapabilitySubLevel int enterpriseCapabilitySubLevel) {
+        return enterpriseCapabilitySubLevel >= NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1
+                && enterpriseCapabilitySubLevel <= NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5;
+    }
+
+    private static void checkValidEnterpriseCapabilitySublevel(
+            @NetworkCapabilities.EnterpriseCapabilitySubLevel int enterpriseCapabilitySubLevel) {
+        if (!isValidEnterpriseCapabilitySubLevel(enterpriseCapabilitySubLevel)) {
+            throw new IllegalArgumentException("enterprise capability sublevel "
+                    + enterpriseCapabilitySubLevel + " is out of range");
+        }
+    }
+
     /**
      * Check if this {@code NetworkCapability} instance is metered.
      *
@@ -2460,6 +2613,37 @@
         }
 
         /**
+         * Adds the given enterprise capability sub level.
+         * Note that when searching for a network to satisfy a request, all capabilities sub level
+         * requested must be satisfied. Enterprise capability sub-level is applicable only
+         * for NET_CAPABILITY_ENTERPRISE capability
+         *
+         * @param enterpriseCapabilitySubLevel enterprise capability sub-level.
+         *
+         * @return this builder
+         */
+        @NonNull
+        public Builder addEnterpriseCapabilitySubLevel(
+                @EnterpriseCapabilitySubLevel  int enterpriseCapabilitySubLevel) {
+            mCaps.addEnterpriseCapabilitySubLevel(enterpriseCapabilitySubLevel);
+            return this;
+        }
+
+        /**
+         * Removes the given enterprise capability sub level. Enterprise capability sub-level is
+         * applicable only for NET_CAPABILITY_ENTERPRISE capability
+         *
+         * @param enterpriseCapabilitySubLevel the enterprise capability subLevel
+         * @return this builder
+         */
+        @NonNull
+        public Builder removeEnterpriseCapabilitySubLevel(
+                @EnterpriseCapabilitySubLevel  int enterpriseCapabilitySubLevel) {
+            mCaps.removeEnterpriseCapabilitySubLevel(enterpriseCapabilitySubLevel);
+            return this;
+        }
+
+        /**
          * Sets the owner UID.
          *
          * The default value is {@link Process#INVALID_UID}. Pass this value to reset.
@@ -2717,6 +2901,12 @@
                             + " administrator UIDs.");
                 }
             }
+
+            if ((mCaps.getEnterpriseCapabilitySubLevels().length != 0)
+                    && !mCaps.hasCapability(NET_CAPABILITY_ENTERPRISE)) {
+                throw new IllegalStateException("Enterprise capability sublevel is applicable only"
+                        + " with ENTERPRISE capability.");
+            }
             return new NetworkCapabilities(mCaps);
         }
     }
diff --git a/framework/src/android/net/RouteInfo.java b/framework/src/android/net/RouteInfo.java
index fad3144..df5f151 100644
--- a/framework/src/android/net/RouteInfo.java
+++ b/framework/src/android/net/RouteInfo.java
@@ -86,16 +86,26 @@
     private final String mInterface;
 
 
-    /** Unicast route. @hide */
-    @SystemApi
+    /**
+     * Unicast route.
+     *
+     * Indicates that destination is reachable directly or via gateway.
+     **/
     public static final int RTN_UNICAST = 1;
 
-    /** Unreachable route. @hide */
-    @SystemApi
+    /**
+     * Unreachable route.
+     *
+     * Indicates that destination is unreachable.
+     **/
     public static final int RTN_UNREACHABLE = 7;
 
-    /** Throw route. @hide */
-    @SystemApi
+    /**
+     * Throw route.
+     *
+     * Indicates that routing information about this destination is not in this table.
+     * Routing lookup should continue in another table.
+     **/
     public static final int RTN_THROW = 9;
 
     /**
@@ -391,10 +401,7 @@
      * Retrieves the type of this route.
      *
      * @return The type of this route; one of the {@code RTN_xxx} constants defined in this class.
-     *
-     * @hide
      */
-    @SystemApi
     @RouteType
     public int getType() {
         return mType;
diff --git a/service/Android.bp b/service/Android.bp
index b595ef2..1ec7daa 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -19,6 +19,33 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+// The library name match the service-connectivity jarjar rules that put the JNI utils in the
+// com.android.connectivity.com.android.net.module.util package.
+cc_library_shared {
+    name: "libcom_android_connectivity_com_android_net_module_util_jni",
+    min_sdk_version: "30",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
+    ],
+    srcs: [
+        "jni/com_android_net_module_util/onload.cpp",
+    ],
+    stl: "libc++_static",
+    static_libs: [
+        "libnet_utils_device_common_bpfjni",
+    ],
+    shared_libs: [
+        "liblog",
+        "libnativehelper",
+    ],
+    apex_available: [
+        "com.android.tethering",
+    ],
+}
+
 cc_library_shared {
     name: "libservice-connectivity",
     min_sdk_version: "30",
@@ -69,6 +96,7 @@
         "modules-utils-build",
         "modules-utils-shell-command-handler",
         "net-utils-device-common",
+        "net-utils-device-common-bpf",
         "net-utils-device-common-netlink",
         "net-utils-framework-common",
         "netd-client",
diff --git a/service/jni/com_android_net_module_util/onload.cpp b/service/jni/com_android_net_module_util/onload.cpp
new file mode 100644
index 0000000..1d17622
--- /dev/null
+++ b/service/jni/com_android_net_module_util/onload.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#include <nativehelper/JNIHelp.h>
+#include <log/log.h>
+
+namespace android {
+
+int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name);
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
+    JNIEnv *env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        ALOGE("GetEnv failed");
+        return JNI_ERR;
+    }
+
+    if (register_com_android_net_module_util_BpfMap(env,
+            "com/android/connectivity/com/android/net/module/util/BpfMap") < 0) return JNI_ERR;
+
+    return JNI_VERSION_1_6;
+}
+
+};
diff --git a/tests/common/Android.bp b/tests/common/Android.bp
index f47f6b0..c533dab 100644
--- a/tests/common/Android.bp
+++ b/tests/common/Android.bp
@@ -64,8 +64,7 @@
     name: "ConnectivityCoverageTests",
     // Tethering started on SDK 30
     min_sdk_version: "30",
-    // TODO: change to 31 as soon as it is available
-    target_sdk_version: "30",
+    target_sdk_version: "31",
     test_suites: ["general-tests", "mts-tethering"],
     defaults: [
         "framework-connectivity-test-defaults",
diff --git a/tests/common/java/android/net/IpPrefixTest.java b/tests/common/java/android/net/IpPrefixTest.java
index 50ecb42..f61c8c3 100644
--- a/tests/common/java/android/net/IpPrefixTest.java
+++ b/tests/common/java/android/net/IpPrefixTest.java
@@ -122,6 +122,9 @@
 
         p = new IpPrefix("[2001:db8::123]/64");
         assertEquals("2001:db8::/64", p.toString());
+
+        p = new IpPrefix(InetAddresses.parseNumericAddress("::128"), 64);
+        assertEquals("::/64", p.toString());
     }
 
     @Test
diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
index 32f00a3..2a4df7a 100644
--- a/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -22,6 +22,12 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
@@ -347,7 +353,7 @@
         if (isAtLeastS()) {
             // When this test is run on S+, NetworkCapabilities is as recent as the test,
             // so this should be the most recent known number of fields.
-            assertParcelSane(cap, 17);
+            assertParcelSane(cap, 18);
         } else if (isAtLeastR()) {
             assertParcelSane(cap, 15);
         } else {
@@ -797,6 +803,87 @@
         } catch (IllegalStateException expected) { }
     }
 
+    @Test @IgnoreUpTo(Build.VERSION_CODES.S)
+    public void testEnterpriseCapabilitySubLevel() {
+        final NetworkCapabilities nc1 = new NetworkCapabilities.Builder()
+                .addCapability(NET_CAPABILITY_ENTERPRISE)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+                .build();
+        assertEquals(1, nc1.getEnterpriseCapabilitySubLevels().length);
+        assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1,
+                nc1.getEnterpriseCapabilitySubLevels()[0]);
+        final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
+                .addCapability(NET_CAPABILITY_ENTERPRISE)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+                .build();
+        assertEquals(2, nc2.getEnterpriseCapabilitySubLevels().length);
+        assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1,
+                nc2.getEnterpriseCapabilitySubLevels()[0]);
+        assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2,
+                nc2.getEnterpriseCapabilitySubLevels()[1]);
+        final NetworkCapabilities nc3 = new NetworkCapabilities.Builder()
+                .addCapability(NET_CAPABILITY_ENTERPRISE)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5)
+                .build();
+        assertEquals(5, nc3.getEnterpriseCapabilitySubLevels().length);
+        assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1,
+                nc3.getEnterpriseCapabilitySubLevels()[0]);
+        assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2,
+                nc3.getEnterpriseCapabilitySubLevels()[1]);
+        assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3,
+                nc3.getEnterpriseCapabilitySubLevels()[2]);
+        assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4,
+                nc3.getEnterpriseCapabilitySubLevels()[3]);
+        assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5,
+                nc3.getEnterpriseCapabilitySubLevels()[4]);
+
+        final Class<IllegalArgumentException> illegalArgumentExceptionClass =
+                IllegalArgumentException.class;
+        assertThrows(illegalArgumentExceptionClass, () -> new NetworkCapabilities.Builder()
+                .addEnterpriseCapabilitySubLevel(6)
+                .build());
+        assertThrows(illegalArgumentExceptionClass, () -> new NetworkCapabilities.Builder()
+                .removeEnterpriseCapabilitySubLevel(6)
+                .build());
+
+        final Class<IllegalStateException> illegalStateException =
+                IllegalStateException.class;
+        assertThrows(illegalStateException, () -> new NetworkCapabilities.Builder()
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+                .build());
+
+        final NetworkCapabilities nc4 = new NetworkCapabilities.Builder()
+                .addCapability(NET_CAPABILITY_ENTERPRISE)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+                .removeEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+                .removeEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+                .build();
+        assertEquals(0, nc4.getEnterpriseCapabilitySubLevels().length);
+
+        final NetworkCapabilities nc5 = new NetworkCapabilities.Builder()
+                .addCapability(NET_CAPABILITY_CBS)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+                .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+                .removeEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+                .removeEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+                .build();
+
+        assertTrue(nc4.satisfiedByNetworkCapabilities(nc1));
+        assertFalse(nc1.satisfiedByNetworkCapabilities(nc4));
+
+        assertFalse(nc3.satisfiedByNetworkCapabilities(nc2));
+        assertTrue(nc2.satisfiedByNetworkCapabilities(nc3));
+
+        assertFalse(nc1.satisfiedByNetworkCapabilities(nc5));
+        assertFalse(nc5.satisfiedByNetworkCapabilities(nc1));
+    }
+
     @Test
     public void testWifiAwareNetworkSpecifier() {
         final NetworkCapabilities nc = new NetworkCapabilities()
diff --git a/tests/common/java/android/net/RouteInfoTest.java b/tests/common/java/android/net/RouteInfoTest.java
index 71689f9..b69b045 100644
--- a/tests/common/java/android/net/RouteInfoTest.java
+++ b/tests/common/java/android/net/RouteInfoTest.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import static android.net.RouteInfo.RTN_THROW;
+import static android.net.RouteInfo.RTN_UNICAST;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 
 import static com.android.testutils.MiscAsserts.assertEqualBothWays;
@@ -329,6 +331,16 @@
     }
 
     @Test
+    public void testRouteTypes() {
+        RouteInfo r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
+        assertEquals(RTN_UNREACHABLE, r.getType());
+        r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNICAST);
+        assertEquals(RTN_UNICAST, r.getType());
+        r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_THROW);
+        assertEquals(RTN_THROW, r.getType());
+    }
+
+    @Test
     public void testTruncation() {
       LinkAddress l;
       RouteInfo r;
diff --git a/tests/unit/java/android/net/NetworkStatsAccessTest.java b/tests/unit/java/android/net/NetworkStatsAccessTest.java
index 0f9ed41..bcbbcc92 100644
--- a/tests/unit/java/android/net/NetworkStatsAccessTest.java
+++ b/tests/unit/java/android/net/NetworkStatsAccessTest.java
@@ -22,7 +22,7 @@
 import android.Manifest;
 import android.Manifest.permission;
 import android.app.AppOpsManager;
-import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Build;
@@ -30,7 +30,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.LocalServices;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
 
@@ -49,29 +48,26 @@
     private static final int TEST_UID = 12345;
 
     @Mock private Context mContext;
-    @Mock private DevicePolicyManagerInternal mDpmi;
+    @Mock private DevicePolicyManager mDpm;
     @Mock private TelephonyManager mTm;
     @Mock private AppOpsManager mAppOps;
 
     // Hold the real service so we can restore it when tearing down the test.
-    private DevicePolicyManagerInternal mSystemDpmi;
+    private DevicePolicyManager mSystemDpm;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
-        mSystemDpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
-        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
-        LocalServices.addService(DevicePolicyManagerInternal.class, mDpmi);
-
         when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTm);
         when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOps);
+        when(mContext.getSystemServiceName(DevicePolicyManager.class))
+                .thenReturn(Context.DEVICE_POLICY_SERVICE);
+        when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(mDpm);
     }
 
     @After
     public void tearDown() throws Exception {
-        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
-        LocalServices.addService(DevicePolicyManagerInternal.class, mSystemDpmi);
     }
 
     @Test
@@ -169,11 +165,11 @@
     }
 
     private void setIsDeviceOwner(boolean isOwner) {
-        when(mDpmi.isActiveDeviceOwner(TEST_UID)).thenReturn(isOwner);
+        when(mDpm.isDeviceOwnerApp(TEST_PKG)).thenReturn(isOwner);
     }
 
     private void setIsProfileOwner(boolean isOwner) {
-        when(mDpmi.isActiveProfileOwner(TEST_UID)).thenReturn(isOwner);
+        when(mDpm.isProfileOwnerApp(TEST_PKG)).thenReturn(isOwner);
     }
 
     private void setHasAppOpsPermission(int appOpsMode, boolean hasPermission) {
diff --git a/tests/unit/java/android/net/NetworkTemplateTest.kt b/tests/unit/java/android/net/NetworkTemplateTest.kt
index de8469c..5d6e6dd 100644
--- a/tests/unit/java/android/net/NetworkTemplateTest.kt
+++ b/tests/unit/java/android/net/NetworkTemplateTest.kt
@@ -42,8 +42,6 @@
 import android.net.NetworkTemplate.OEM_MANAGED_ALL
 import android.net.NetworkTemplate.OEM_MANAGED_NO
 import android.net.NetworkTemplate.OEM_MANAGED_YES
-import android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_ALL
-import android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT
 import android.net.NetworkTemplate.WIFI_NETWORK_KEY_ALL
 import android.net.NetworkTemplate.buildTemplateCarrierMetered
 import android.net.NetworkTemplate.buildTemplateMobileAll
@@ -54,6 +52,8 @@
 import android.net.NetworkTemplate.normalize
 import android.os.Build
 import android.telephony.TelephonyManager
+import com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+import com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT
 import com.android.testutils.DevSdkIgnoreRule
 import com.android.testutils.DevSdkIgnoreRunner
 import com.android.testutils.assertParcelSane
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 044ff02..c47604c 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -81,6 +81,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMTEL;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
@@ -3586,7 +3587,7 @@
                 || capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS
                 || capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
                 || capability == NET_CAPABILITY_VSIM || capability == NET_CAPABILITY_BIP
-                || capability == NET_CAPABILITY_ENTERPRISE) {
+                || capability == NET_CAPABILITY_ENTERPRISE || capability == NET_CAPABILITY_MMTEL) {
             assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
         } else {
             assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
@@ -3714,6 +3715,7 @@
         tryNetworkFactoryRequests(NET_CAPABILITY_WIFI_P2P);
         tryNetworkFactoryRequests(NET_CAPABILITY_IA);
         tryNetworkFactoryRequests(NET_CAPABILITY_RCS);
+        tryNetworkFactoryRequests(NET_CAPABILITY_MMTEL);
         tryNetworkFactoryRequests(NET_CAPABILITY_XCAP);
         tryNetworkFactoryRequests(NET_CAPABILITY_ENTERPRISE);
         tryNetworkFactoryRequests(NET_CAPABILITY_EIMS);
diff --git a/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index e2ad00d..a3da05d 100644
--- a/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -94,6 +94,7 @@
 public class MultipathPolicyTrackerTest {
     private static final Network TEST_NETWORK = new Network(123);
     private static final int POLICY_SNOOZED = -100;
+    private static final String TEST_IMSI1 = "TEST_IMSI1";
 
     @Mock private Context mContext;
     @Mock private Context mUserAllContext;
@@ -148,6 +149,7 @@
         when(mDeps.getClock()).thenReturn(mClock);
 
         when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+        when(mTelephonyManager.getSubscriberId()).thenReturn(TEST_IMSI1);
 
         mContentResolver = Mockito.spy(new MockContentResolver(mContext));
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 4948e66..dd92f3a 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -50,7 +50,6 @@
 import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
 import static android.net.NetworkTemplate.OEM_MANAGED_NO;
 import static android.net.NetworkTemplate.OEM_MANAGED_YES;
-import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
 import static android.net.NetworkTemplate.buildTemplateWifi;
@@ -63,6 +62,7 @@
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 
+import static com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
 
 import static org.junit.Assert.assertEquals;