Merge "Add option to validate DUN networks"
diff --git a/staticlibs/framework/com/android/net/module/util/ByteUtils.java b/staticlibs/framework/com/android/net/module/util/ByteUtils.java
new file mode 100644
index 0000000..290ed46
--- /dev/null
+++ b/staticlibs/framework/com/android/net/module/util/ByteUtils.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 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.annotation.NonNull;
+
+/**
+ * Byte utility functions.
+ * @hide
+ */
+public class ByteUtils {
+    /**
+     * Returns the index of the first appearance of the value {@code target} in {@code array}.
+     *
+     * @param array an array of {@code byte} values, possibly empty
+     * @param target a primitive {@code byte} value
+     * @return the least index {@code i} for which {@code array[i] == target}, or {@code -1} if no
+     *     such index exists.
+     */
+    public static int indexOf(@NonNull byte[] array, byte target) {
+        return indexOf(array, target, 0, array.length);
+    }
+
+    private static int indexOf(byte[] array, byte target, int start, int end) {
+        for (int i = start; i < end; i++) {
+            if (array[i] == target) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the values from each provided array combined into a single array. For example, {@code
+     * concat(new byte[] {a, b}, new byte[] {}, new byte[] {c}} returns the array {@code {a, b, c}}.
+     *
+     * @param arrays zero or more {@code byte} arrays
+     * @return a single array containing all the values from the source arrays, in order
+     */
+    public static byte[] concat(@NonNull byte[]... arrays) {
+        int length = 0;
+        for (byte[] array : arrays) {
+            length += array.length;
+        }
+        byte[] result = new byte[length];
+        int pos = 0;
+        for (byte[] array : arrays) {
+            System.arraycopy(array, 0, result, pos, array.length);
+            pos += array.length;
+        }
+        return result;
+    }
+}
diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h
index 4429164..157f210 100644
--- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h
+++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h
@@ -115,23 +115,16 @@
     return kernelVersion() >= KVER(major, minor, sub);
 }
 
-#define SKIP_IF_BPF_SUPPORTED                              \
-    do {                                                   \
-        if (android::bpf::isAtLeastKernelVersion(4, 9, 0)) \
-            GTEST_SKIP() << "Skip: bpf is supported.";     \
-    } while (0)
-
 #define SKIP_IF_BPF_NOT_SUPPORTED                           \
     do {                                                    \
         if (!android::bpf::isAtLeastKernelVersion(4, 9, 0)) \
             GTEST_SKIP() << "Skip: bpf is not supported.";  \
     } while (0)
 
-#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED                               \
-    do {                                                                 \
-        if (!android::bpf::isAtLeastKernelVersion(4, 14, 0))             \
-            GTEST_SKIP() << "Skip: extended bpf feature not supported."; \
-    } while (0)
+// Only used by tm-mainline-prod's system/netd/tests/bpf_base_test.cpp
+// but platform and platform tests aren't expected to build/work in tm-mainline-prod
+// so we can just trivialize this
+#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED
 
 #define SKIP_IF_XDP_NOT_SUPPORTED                           \
     do {                                                    \
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
index 6eb8aa7..56bc7d0 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
@@ -151,6 +151,23 @@
         __attribute__ ((section(".maps." #name), used)) \
                 ____btf_map_##name = { }
 
+/* There exist buggy kernels with pre-T OS, that due to
+ * kernel patch "[ALPS05162612] bpf: fix ubsan error"
+ * do not support userspace writes into non-zero index of bpf map arrays.
+ *
+ * We use this assert to prevent us from being able to define such a map.
+ */
+
+#ifdef THIS_BPF_PROGRAM_IS_FOR_TEST_PURPOSES_ONLY
+#define BPF_MAP_ASSERT_OK(type, entries, mode)
+#elif BPFLOADER_MIN_VER >= BPFLOADER_T_BETA3_VERSION
+#define BPF_MAP_ASSERT_OK(type, entries, mode)
+#else
+#define BPF_MAP_ASSERT_OK(type, entries, mode) \
+  _Static_assert(((type) != BPF_MAP_TYPE_ARRAY) || ((entries) <= 1) || !((mode) & 0222), \
+  "Writable arrays with more than 1 element not supported on pre-T devices.")
+#endif
+
 /* type safe macro to declare a map and related accessor functions */
 #define DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md,         \
                            selinux, pindir, share)                                               \
@@ -171,6 +188,7 @@
             .pin_subdir = pindir,                                                                \
             .shared = share,                                                                     \
     };                                                                                           \
+    BPF_MAP_ASSERT_OK(BPF_MAP_TYPE_##TYPE, (num_entries), (md));                                 \
     BPF_ANNOTATE_KV_PAIR(the_map, KeyType, ValueType);                                           \
                                                                                                  \
     static inline __always_inline __unused ValueType* bpf_##the_map##_lookup_elem(               \
@@ -209,6 +227,10 @@
     DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \
                        DEFAULT_BPF_MAP_UID, AID_ROOT, 0600)
 
+#define DEFINE_BPF_MAP_RO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \
+    DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \
+                       DEFAULT_BPF_MAP_UID, gid, 0440)
+
 #define DEFINE_BPF_MAP_GWO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \
     DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \
                        DEFAULT_BPF_MAP_UID, gid, 0620)
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/ByteUtilsTests.kt b/staticlibs/tests/unit/src/com/android/net/module/util/ByteUtilsTests.kt
new file mode 100644
index 0000000..e58adad
--- /dev/null
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/ByteUtilsTests.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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 com.android.net.module.util.ByteUtils.indexOf
+import com.android.net.module.util.ByteUtils.concat
+import org.junit.Test
+import kotlin.test.assertContentEquals
+import kotlin.test.assertEquals
+import kotlin.test.assertNotSame
+
+class ByteUtilsTests {
+    private val EMPTY = byteArrayOf()
+    private val ARRAY1 = byteArrayOf(1)
+    private val ARRAY234 = byteArrayOf(2, 3, 4)
+
+    @Test
+    fun testIndexOf() {
+        assertEquals(-1, indexOf(EMPTY, 1))
+        assertEquals(-1, indexOf(ARRAY1, 2))
+        assertEquals(-1, indexOf(ARRAY234, 1))
+        assertEquals(0, indexOf(byteArrayOf(-1), -1))
+        assertEquals(0, indexOf(ARRAY234, 2))
+        assertEquals(1, indexOf(ARRAY234, 3))
+        assertEquals(2, indexOf(ARRAY234, 4))
+        assertEquals(1, indexOf(byteArrayOf(2, 3, 2, 3), 3))
+    }
+
+    @Test
+    fun testConcat() {
+        assertContentEquals(EMPTY, concat())
+        assertContentEquals(EMPTY, concat(EMPTY))
+        assertContentEquals(EMPTY, concat(EMPTY, EMPTY, EMPTY))
+        assertContentEquals(ARRAY1, concat(ARRAY1))
+        assertNotSame(ARRAY1, concat(ARRAY1))
+        assertContentEquals(ARRAY1, concat(EMPTY, ARRAY1, EMPTY))
+        assertContentEquals(byteArrayOf(1, 1, 1), concat(ARRAY1, ARRAY1, ARRAY1))
+        assertContentEquals(byteArrayOf(1, 2, 3, 4), concat(ARRAY1, ARRAY234))
+    }
+}
\ No newline at end of file
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt
index 9fb4d8c..8e320d0 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt
@@ -17,6 +17,7 @@
 package com.android.net.module.util
 
 import com.android.testutils.ConcurrentInterpreter
+import com.android.testutils.INTERPRET_TIME_UNIT
 import com.android.testutils.InterpretException
 import com.android.testutils.InterpretMatcher
 import com.android.testutils.SyntaxException
@@ -420,7 +421,7 @@
     // the test code to not compile instead of throw, but it's vastly more complex and this will
     // fail 100% at runtime any test that would not have compiled.
     Regex("""poll\((\d+)?\)\s*(\{.*\})?""") to { i, t, r ->
-        (if (r.strArg(1).isEmpty()) i.interpretTimeUnit else r.timeArg(1)).let { time ->
+        (if (r.strArg(1).isEmpty()) INTERPRET_TIME_UNIT else r.timeArg(1)).let { time ->
             (t as ArrayTrackRecord<Int>.ReadHead).poll(time, makePredicate(r.strArg(2)))
         }
     },
diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt
index 690ef2e..f8f2da0 100644
--- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt
+++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt
@@ -38,6 +38,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
+import org.junit.Assume.assumeTrue
 import kotlin.reflect.KClass
 import kotlin.test.assertEquals
 import kotlin.test.assertFails
@@ -160,23 +161,23 @@
     }
 
     @Test
-    fun testExpectCallbackThat() {
+    fun testExpectWithPredicate() {
         val net = Network(193)
         val netCaps = NetworkCapabilities().addTransportType(CELLULAR)
         // Check that expecting callbackThat anything fails when no callback has been received.
-        assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { true } }
+        assertFails { mCallback.expect<CallbackEntry>(timeoutMs = SHORT_TIMEOUT_MS) { true } }
 
         // Basic test for true and false
         mCallback.onAvailable(net)
-        mCallback.expectCallbackThat { true }
+        mCallback.expect<Available> { true }
         mCallback.onAvailable(net)
-        assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { false } }
+        assertFails { mCallback.expect<CallbackEntry>(timeoutMs = SHORT_TIMEOUT_MS) { false } }
 
         // Try a positive and a negative case
         mCallback.onBlockedStatusChanged(net, true)
-        mCallback.expectCallbackThat { cb -> cb is BlockedStatus && cb.blocked }
+        mCallback.expect<CallbackEntry> { cb -> cb is BlockedStatus && cb.blocked }
         mCallback.onCapabilitiesChanged(net, netCaps)
-        assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { cb ->
+        assertFails { mCallback.expect<CallbackEntry>(timeoutMs = SHORT_TIMEOUT_MS) { cb ->
             cb is CapabilitiesChanged && cb.caps.hasTransport(WIFI)
         } }
     }
@@ -251,22 +252,102 @@
     }
 
     @Test
-    fun testExpectCallback() {
+    fun testExpect() {
         val net = Network(103)
         // Test expectCallback fails when nothing was sent.
-        assertFails { mCallback.expectCallback<BlockedStatus>(net, SHORT_TIMEOUT_MS) }
+        assertFails { mCallback.expect<BlockedStatus>(net, SHORT_TIMEOUT_MS) }
 
         // Test onAvailable is seen and can be expected
         mCallback.onAvailable(net)
-        mCallback.expectCallback<Available>(net, SHORT_TIMEOUT_MS)
+        mCallback.expect<Available>(net, SHORT_TIMEOUT_MS)
 
         // Test onAvailable won't return calls with a different network
         mCallback.onAvailable(Network(106))
-        assertFails { mCallback.expectCallback<Available>(net, SHORT_TIMEOUT_MS) }
+        assertFails { mCallback.expect<Available>(net, SHORT_TIMEOUT_MS) }
 
         // Test onAvailable won't return calls with a different callback
         mCallback.onAvailable(net)
-        assertFails { mCallback.expectCallback<BlockedStatus>(net, SHORT_TIMEOUT_MS) }
+        assertFails { mCallback.expect<BlockedStatus>(net, SHORT_TIMEOUT_MS) }
+    }
+
+    @Test
+    fun testAllExpectOverloads() {
+        // This test should never run, it only checks that all overloads exist and build
+        assumeTrue(false)
+        val hn = object : TestableNetworkCallback.HasNetwork { override val network = ANY_NETWORK }
+
+        // Method with all arguments (version that takes a Network)
+        mCallback.expect(AVAILABLE, ANY_NETWORK, 10, "error") { true }
+
+        // Java overloads omitting one argument. One line for omitting each argument, in positional
+        // order. Versions that take a Network.
+        mCallback.expect(AVAILABLE, 10, "error") { true }
+        mCallback.expect(AVAILABLE, ANY_NETWORK, "error") { true }
+        mCallback.expect(AVAILABLE, ANY_NETWORK, 10) { true }
+        mCallback.expect(AVAILABLE, ANY_NETWORK, 10, "error")
+
+        // Java overloads for omitting two arguments. One line for omitting each pair of arguments.
+        // Versions that take a Network.
+        mCallback.expect(AVAILABLE, "error") { true }
+        mCallback.expect(AVAILABLE, 10) { true }
+        mCallback.expect(AVAILABLE, 10, "error")
+        mCallback.expect(AVAILABLE, ANY_NETWORK) { true }
+        mCallback.expect(AVAILABLE, ANY_NETWORK, "error")
+        mCallback.expect(AVAILABLE, ANY_NETWORK, 10)
+
+        // Java overloads for omitting three arguments. One line for each remaining argument.
+        // Versions that take a Network.
+        mCallback.expect(AVAILABLE) { true }
+        mCallback.expect(AVAILABLE, "error")
+        mCallback.expect(AVAILABLE, 10)
+        mCallback.expect(AVAILABLE, ANY_NETWORK)
+
+        // Java overload for omitting all four arguments.
+        mCallback.expect(AVAILABLE)
+
+        // Same orders as above, but versions that take a HasNetwork. Except overloads that
+        // were already tested because they omitted the Network argument
+        mCallback.expect(AVAILABLE, hn, 10, "error") { true }
+        mCallback.expect(AVAILABLE, hn, "error") { true }
+        mCallback.expect(AVAILABLE, hn, 10) { true }
+        mCallback.expect(AVAILABLE, hn, 10, "error")
+
+        mCallback.expect(AVAILABLE, hn) { true }
+        mCallback.expect(AVAILABLE, hn, "error")
+        mCallback.expect(AVAILABLE, hn, 10)
+
+        mCallback.expect(AVAILABLE, hn)
+
+        // Same as above but for reified versions.
+        mCallback.expect<Available>(ANY_NETWORK, 10, "error") { true }
+        mCallback.expect<Available>(timeoutMs = 10, errorMsg = "error") { true }
+        mCallback.expect<Available>(network = ANY_NETWORK, errorMsg = "error") { true }
+        mCallback.expect<Available>(network = ANY_NETWORK, timeoutMs = 10) { true }
+        mCallback.expect<Available>(network = ANY_NETWORK, timeoutMs = 10, errorMsg = "error")
+
+        mCallback.expect<Available>(errorMsg = "error") { true }
+        mCallback.expect<Available>(timeoutMs = 10) { true }
+        mCallback.expect<Available>(timeoutMs = 10, errorMsg = "error")
+        mCallback.expect<Available>(network = ANY_NETWORK) { true }
+        mCallback.expect<Available>(network = ANY_NETWORK, errorMsg = "error")
+        mCallback.expect<Available>(network = ANY_NETWORK, timeoutMs = 10)
+
+        mCallback.expect<Available> { true }
+        mCallback.expect<Available>(errorMsg = "error")
+        mCallback.expect<Available>(timeoutMs = 10)
+        mCallback.expect<Available>(network = ANY_NETWORK)
+        mCallback.expect<Available>()
+
+        mCallback.expect<Available>(hn, 10, "error") { true }
+        mCallback.expect<Available>(network = hn, errorMsg = "error") { true }
+        mCallback.expect<Available>(network = hn, timeoutMs = 10) { true }
+        mCallback.expect<Available>(network = hn, timeoutMs = 10, errorMsg = "error")
+
+        mCallback.expect<Available>(network = hn) { true }
+        mCallback.expect<Available>(network = hn, errorMsg = "error")
+        mCallback.expect<Available>(network = hn, timeoutMs = 10)
+
+        mCallback.expect<Available>(network = hn)
     }
 
     @Test
@@ -322,9 +403,9 @@
         TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1,
                 threadTransform = { cb -> cb.createLinkedCopy() }, spec = """
                 onAvailable(100)                   | eventually(CapabilitiesChanged(100), 1) fails
-                sleep ; onCapabilitiesChanged(100) | eventually(CapabilitiesChanged(100), 2)
+                sleep ; onCapabilitiesChanged(100) | eventually(CapabilitiesChanged(100), 3)
                 onAvailable(101) ; onBlockedStatus(101) | eventually(BlockedStatus(100), 2) fails
-                onSuspended(100) ; sleep ; onLost(100)  | eventually(Lost(100), 2)
+                onSuspended(100) ; sleep ; onLost(100)  | eventually(Lost(100), 3)
         """)
     }
 }
diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTestJava.java b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTestJava.java
new file mode 100644
index 0000000..4570d0a
--- /dev/null
+++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTestJava.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 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.testutils;
+
+import static com.android.testutils.RecorderCallback.CallbackEntry.AVAILABLE;
+import static com.android.testutils.TestableNetworkCallbackKt.anyNetwork;
+
+import static org.junit.Assume.assumeTrue;
+
+import org.junit.Test;
+
+public class TestableNetworkCallbackTestJava {
+    @Test
+    void testAllExpectOverloads() {
+        // This test should never run, it only checks that all overloads exist and build
+        assumeTrue(false);
+        final TestableNetworkCallback callback = new TestableNetworkCallback();
+        TestableNetworkCallback.HasNetwork hn = TestableNetworkCallbackKt::anyNetwork;
+
+        // Method with all arguments (version that takes a Network)
+        callback.expect(AVAILABLE, anyNetwork(), 10, "error", cb -> true);
+
+        // Overloads omitting one argument. One line for omitting each argument, in positional
+        // order. Versions that take a Network.
+        callback.expect(AVAILABLE, 10, "error", cb -> true);
+        callback.expect(AVAILABLE, anyNetwork(), "error", cb -> true);
+        callback.expect(AVAILABLE, anyNetwork(), 10, cb -> true);
+        callback.expect(AVAILABLE, anyNetwork(), 10, "error");
+
+        // Overloads for omitting two arguments. One line for omitting each pair of arguments.
+        // Versions that take a Network.
+        callback.expect(AVAILABLE, "error", cb -> true);
+        callback.expect(AVAILABLE, 10, cb -> true);
+        callback.expect(AVAILABLE, 10, "error");
+        callback.expect(AVAILABLE, anyNetwork(), cb -> true);
+        callback.expect(AVAILABLE, anyNetwork(), "error");
+        callback.expect(AVAILABLE, anyNetwork(), 10);
+
+        // Overloads for omitting three arguments. One line for each remaining argument.
+        // Versions that take a Network.
+        callback.expect(AVAILABLE, cb -> true);
+        callback.expect(AVAILABLE, "error");
+        callback.expect(AVAILABLE, 10);
+        callback.expect(AVAILABLE, anyNetwork());
+
+        // Java overload for omitting all four arguments.
+        callback.expect(AVAILABLE);
+
+        // Same orders as above, but versions that take a HasNetwork. Except overloads that
+        // were already tested because they omitted the Network argument
+        callback.expect(AVAILABLE, hn, 10, "error", cb -> true);
+        callback.expect(AVAILABLE, hn, "error", cb -> true);
+        callback.expect(AVAILABLE, hn, 10, cb -> true);
+        callback.expect(AVAILABLE, hn, 10, "error");
+
+        callback.expect(AVAILABLE, hn, cb -> true);
+        callback.expect(AVAILABLE, hn, "error");
+        callback.expect(AVAILABLE, hn, 10);
+
+        callback.expect(AVAILABLE, hn);
+    }
+}
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt
index cbdc017..9e72f4b 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt
@@ -13,7 +13,7 @@
 typealias InterpretMatcher<T> = Pair<Regex, (ConcurrentInterpreter<T>, T, MatchResult) -> Any?>
 
 // The default unit of time for interpreted tests
-val INTERPRET_TIME_UNIT = 40L // ms
+const val INTERPRET_TIME_UNIT = 60L // ms
 
 /**
  * A small interpreter for testing parallel code.
@@ -40,10 +40,7 @@
  * Some expressions already exist by default and can be used by all interpreters. Refer to
  * getDefaultInstructions() below for a list and documentation.
  */
-open class ConcurrentInterpreter<T>(
-    localInterpretTable: List<InterpretMatcher<T>>,
-    val interpretTimeUnit: Long = INTERPRET_TIME_UNIT
-) {
+open class ConcurrentInterpreter<T>(localInterpretTable: List<InterpretMatcher<T>>) {
     private val interpretTable: List<InterpretMatcher<T>> =
             localInterpretTable + getDefaultInstructions()
     // The last time the thread became blocked, with base System.currentTimeMillis(). This should
@@ -211,7 +208,7 @@
     },
     // Interpret sleep. Optional argument for the count, in INTERPRET_TIME_UNIT units.
     Regex("""sleep(\((\d+)\))?""") to { i, t, r ->
-        SystemClock.sleep(if (r.strArg(2).isEmpty()) i.interpretTimeUnit else r.timeArg(2))
+        SystemClock.sleep(if (r.strArg(2).isEmpty()) INTERPRET_TIME_UNIT else r.timeArg(2))
     },
     Regex("""(.*)\s*fails""") to { i, t, r ->
         assertFails { i.interpret(r.strArg(1), t) }
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt
index 7e92af1..7b5ad01 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt
@@ -63,6 +63,7 @@
 
         try {
             val connInfo = wifiManager.connectionInfo
+            Log.d(TAG, "connInfo=" + connInfo)
             if (connInfo == null || connInfo.networkId == -1) {
                 clearWifiBlocklist()
                 val pfd = getInstrumentation().uiAutomation.executeShellCommand("svc wifi enable")
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java
index ea89eda..ce55fdc 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java
+++ b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java
@@ -20,6 +20,7 @@
 import android.text.TextUtils;
 import android.util.Pair;
 
+import java.util.Objects;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -128,7 +129,7 @@
         final Pair<Integer, Integer> v1 = getMajorMinorVersion(s1);
         final Pair<Integer, Integer> v2 = getMajorMinorVersion(s2);
 
-        if (v1.first == v2.first) {
+        if (Objects.equals(v1.first, v2.first)) {
             return Integer.compare(v1.second, v2.second);
         } else {
             return Integer.compare(v1.first, v2.first);
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt
index a40e57d..406a179 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt
@@ -212,10 +212,11 @@
     ): CallbackEntry = poll(timeoutMs) ?: fail(errorMsg)
 
     /*****
-     * AssertNextIs family of methods.
+     * expect family of methods.
      * These methods fetch the next callback and assert it matches the conditions : type,
      * passed predicate. If no callback is received within the timeout, these methods fail.
      */
+    @JvmOverloads
     fun <T : CallbackEntry> expect(
         type: KClass<T>,
         network: Network = ANY_NETWORK,
@@ -226,6 +227,7 @@
         test(it as? T ?: fail("Expected callback ${type.simpleName}, got $it"))
     } as T
 
+    @JvmOverloads
     fun <T : CallbackEntry> expect(
         type: KClass<T>,
         network: HasNetwork,
@@ -269,7 +271,7 @@
         type: KClass<T>,
         network: Network,
         timeoutMs: Long,
-        test: (T) -> Boolean = { true }
+        test: (T) -> Boolean
     ) = expect(type, network, timeoutMs, null, test)
 
     @JvmOverloads
@@ -277,7 +279,7 @@
         type: KClass<T>,
         network: HasNetwork,
         timeoutMs: Long,
-        test: (T) -> Boolean = { true }
+        test: (T) -> Boolean
     ) = expect(type, network.network, timeoutMs, null, test)
 
     // Without |network| or |timeout|
@@ -301,21 +303,21 @@
     fun <T : CallbackEntry> expect(
         type: KClass<T>,
         network: Network,
-        test: (T) -> Boolean = { true }
+        test: (T) -> Boolean
     ) = expect(type, network, defaultTimeoutMs, null, test)
 
     @JvmOverloads
     fun <T : CallbackEntry> expect(
         type: KClass<T>,
         network: HasNetwork,
-        test: (T) -> Boolean = { true }
+        test: (T) -> Boolean
     ) = expect(type, network.network, defaultTimeoutMs, null, test)
 
     // Without |network| or |timeout| or |errorMsg|
     @JvmOverloads
     fun <T : CallbackEntry> expect(
         type: KClass<T>,
-        test: (T) -> Boolean = { true }
+        test: (T) -> Boolean
     ) = expect(type, ANY_NETWORK, defaultTimeoutMs, null, test)
 
     // Kotlin reified versions. Don't call methods above, or the predicate would need to be noinline