Merge "Move bit utility methods to a new BitUtils class."
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
index 35d9f31..6eb8aa7 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
@@ -138,6 +138,10 @@
 static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map,
                                          const void* key) = (void*)BPF_FUNC_map_delete_elem;
 
+static int (*bpf_for_each_map_elem)(const struct bpf_map_def* map, void *callback_fn,
+                                    void *callback_ctx, unsigned long long flags) = (void*)
+        BPF_FUNC_for_each_map_elem;
+
 #define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)  \
         struct ____btf_map_##name {                     \
                 type_key key;                           \
diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt
new file mode 100644
index 0000000..557f1fd
--- /dev/null
+++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt
@@ -0,0 +1,385 @@
+/*
+ * 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 android.annotation.SuppressLint
+import android.net.LinkAddress
+import android.net.LinkProperties
+import android.net.Network
+import android.net.NetworkCapabilities
+import com.android.testutils.RecorderCallback.CallbackEntry
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.AVAILABLE
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.BLOCKED_STATUS
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LINK_PROPERTIES_CHANGED
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LOSING
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.NETWORK_CAPS_UPDATED
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LOST
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.RESUMED
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.SUSPENDED
+import com.android.testutils.RecorderCallback.CallbackEntry.Companion.UNAVAILABLE
+import com.android.testutils.RecorderCallback.CallbackEntry.Available
+import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus
+import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import kotlin.reflect.KClass
+import kotlin.test.assertEquals
+import kotlin.test.assertFails
+import kotlin.test.assertNull
+import kotlin.test.assertTrue
+import kotlin.test.fail
+
+const val SHORT_TIMEOUT_MS = 20L
+const val DEFAULT_LINGER_DELAY_MS = 30000
+const val NOT_METERED = NetworkCapabilities.NET_CAPABILITY_NOT_METERED
+const val WIFI = NetworkCapabilities.TRANSPORT_WIFI
+const val CELLULAR = NetworkCapabilities.TRANSPORT_CELLULAR
+const val TEST_INTERFACE_NAME = "testInterfaceName"
+
+@RunWith(JUnit4::class)
+@SuppressLint("NewApi") // Uses hidden APIs, which the linter would identify as missing APIs.
+class TestableNetworkCallbackTest {
+    private lateinit var mCallback: TestableNetworkCallback
+
+    private fun makeHasNetwork(netId: Int) = object : TestableNetworkCallback.HasNetwork {
+        override val network: Network = Network(netId)
+    }
+
+    @Before
+    fun setUp() {
+        mCallback = TestableNetworkCallback()
+    }
+
+    @Test
+    fun testLastAvailableNetwork() {
+        // Make sure there is no last available network at first, then the last available network
+        // is returned after onAvailable is called.
+        val net2097 = Network(2097)
+        assertNull(mCallback.lastAvailableNetwork)
+        mCallback.onAvailable(net2097)
+        assertEquals(mCallback.lastAvailableNetwork, net2097)
+
+        // Make sure calling onCapsChanged/onLinkPropertiesChanged don't affect the last available
+        // network.
+        mCallback.onCapabilitiesChanged(net2097, NetworkCapabilities())
+        mCallback.onLinkPropertiesChanged(net2097, LinkProperties())
+        assertEquals(mCallback.lastAvailableNetwork, net2097)
+
+        // Make sure onLost clears the last available network.
+        mCallback.onLost(net2097)
+        assertNull(mCallback.lastAvailableNetwork)
+
+        // Do the same but with a different network after onLost : make sure the last available
+        // network is the new one, not the original one.
+        val net2098 = Network(2098)
+        mCallback.onAvailable(net2098)
+        mCallback.onCapabilitiesChanged(net2098, NetworkCapabilities())
+        mCallback.onLinkPropertiesChanged(net2098, LinkProperties())
+        assertEquals(mCallback.lastAvailableNetwork, net2098)
+
+        // Make sure onAvailable changes the last available network even if onLost was not called.
+        val net2099 = Network(2099)
+        mCallback.onAvailable(net2099)
+        assertEquals(mCallback.lastAvailableNetwork, net2099)
+
+        // For legacy reasons, lastAvailableNetwork is null as soon as any is lost, not necessarily
+        // the last available one. Check that behavior.
+        mCallback.onLost(net2098)
+        assertNull(mCallback.lastAvailableNetwork)
+
+        // Make sure that losing the really last available one still results in null.
+        mCallback.onLost(net2099)
+        assertNull(mCallback.lastAvailableNetwork)
+
+        // Make sure multiple onAvailable in a row then onLost still results in null.
+        mCallback.onAvailable(net2097)
+        mCallback.onAvailable(net2098)
+        mCallback.onAvailable(net2099)
+        mCallback.onLost(net2097)
+        assertNull(mCallback.lastAvailableNetwork)
+    }
+
+    @Test
+    fun testAssertNoCallback() {
+        mCallback.assertNoCallback(SHORT_TIMEOUT_MS)
+        mCallback.onAvailable(Network(100))
+        assertFails { mCallback.assertNoCallback(SHORT_TIMEOUT_MS) }
+    }
+
+    @Test
+    fun testAssertNoCallbackThat() {
+        val net = Network(101)
+        mCallback.assertNoCallbackThat { it is Available }
+        mCallback.onAvailable(net)
+        // Expect no blocked status change. Receive other callback does not fail the test.
+        mCallback.assertNoCallbackThat { it is BlockedStatus }
+        mCallback.onBlockedStatusChanged(net, true)
+        assertFails { mCallback.assertNoCallbackThat { it is BlockedStatus } }
+        mCallback.onBlockedStatusChanged(net, false)
+        mCallback.onCapabilitiesChanged(net, NetworkCapabilities())
+        assertFails { mCallback.assertNoCallbackThat { it is CapabilitiesChanged } }
+    }
+
+    @Test
+    fun testCapabilitiesWithAndWithout() {
+        val net = Network(101)
+        val matcher = makeHasNetwork(101)
+        val meteredNc = NetworkCapabilities()
+        val unmeteredNc = NetworkCapabilities().addCapability(NOT_METERED)
+        // Check that expecting caps (with or without) fails when no callback has been received.
+        assertFails { mCallback.expectCapabilitiesWith(NOT_METERED, matcher, SHORT_TIMEOUT_MS) }
+        assertFails { mCallback.expectCapabilitiesWithout(NOT_METERED, matcher, SHORT_TIMEOUT_MS) }
+
+        // Add NOT_METERED and check that With succeeds and Without fails.
+        mCallback.onCapabilitiesChanged(net, unmeteredNc)
+        mCallback.expectCapabilitiesWith(NOT_METERED, matcher)
+        mCallback.onCapabilitiesChanged(net, unmeteredNc)
+        assertFails { mCallback.expectCapabilitiesWithout(NOT_METERED, matcher, SHORT_TIMEOUT_MS) }
+
+        // Don't add NOT_METERED and check that With fails and Without succeeds.
+        mCallback.onCapabilitiesChanged(net, meteredNc)
+        assertFails { mCallback.expectCapabilitiesWith(NOT_METERED, matcher, SHORT_TIMEOUT_MS) }
+        mCallback.onCapabilitiesChanged(net, meteredNc)
+        mCallback.expectCapabilitiesWithout(NOT_METERED, matcher)
+    }
+
+    @Test
+    fun testExpectCallbackThat() {
+        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 } }
+
+        // Basic test for true and false
+        mCallback.onAvailable(net)
+        mCallback.expectCallbackThat { true }
+        mCallback.onAvailable(net)
+        assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { false } }
+
+        // Try a positive and a negative case
+        mCallback.onBlockedStatusChanged(net, true)
+        mCallback.expectCallbackThat { cb -> cb is BlockedStatus && cb.blocked }
+        mCallback.onCapabilitiesChanged(net, netCaps)
+        assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { cb ->
+            cb is CapabilitiesChanged && cb.caps.hasTransport(WIFI)
+        } }
+    }
+
+    @Test
+    fun testCapabilitiesThat() {
+        val net = Network(101)
+        val netCaps = NetworkCapabilities().addCapability(NOT_METERED).addTransportType(WIFI)
+        // Check that expecting capabilitiesThat anything fails when no callback has been received.
+        assertFails { mCallback.expectCapabilitiesThat(net, SHORT_TIMEOUT_MS) { true } }
+
+        // Basic test for true and false
+        mCallback.onCapabilitiesChanged(net, netCaps)
+        mCallback.expectCapabilitiesThat(net) { true }
+        mCallback.onCapabilitiesChanged(net, netCaps)
+        assertFails { mCallback.expectCapabilitiesThat(net, SHORT_TIMEOUT_MS) { false } }
+
+        // Try a positive and a negative case
+        mCallback.onCapabilitiesChanged(net, netCaps)
+        mCallback.expectCapabilitiesThat(net) { caps ->
+            caps.hasCapability(NOT_METERED) &&
+                    caps.hasTransport(WIFI) &&
+                    !caps.hasTransport(CELLULAR)
+        }
+        mCallback.onCapabilitiesChanged(net, netCaps)
+        assertFails { mCallback.expectCapabilitiesThat(net, SHORT_TIMEOUT_MS) { caps ->
+            caps.hasTransport(CELLULAR)
+        } }
+
+        // Try a matching callback on the wrong network
+        mCallback.onCapabilitiesChanged(net, netCaps)
+        assertFails { mCallback.expectCapabilitiesThat(Network(100), SHORT_TIMEOUT_MS) { true } }
+    }
+
+    @Test
+    fun testLinkPropertiesThat() {
+        val net = Network(112)
+        val linkAddress = LinkAddress("fe80::ace:d00d/64")
+        val mtu = 1984
+        val linkProps = LinkProperties().apply {
+            this.mtu = mtu
+            interfaceName = TEST_INTERFACE_NAME
+            addLinkAddress(linkAddress)
+        }
+
+        // Check that expecting linkPropsThat anything fails when no callback has been received.
+        assertFails { mCallback.expectLinkPropertiesThat(net, SHORT_TIMEOUT_MS) { true } }
+
+        // Basic test for true and false
+        mCallback.onLinkPropertiesChanged(net, linkProps)
+        mCallback.expectLinkPropertiesThat(net) { true }
+        mCallback.onLinkPropertiesChanged(net, linkProps)
+        assertFails { mCallback.expectLinkPropertiesThat(net, SHORT_TIMEOUT_MS) { false } }
+
+        // Try a positive and negative case
+        mCallback.onLinkPropertiesChanged(net, linkProps)
+        mCallback.expectLinkPropertiesThat(net) { lp ->
+            lp.interfaceName == TEST_INTERFACE_NAME &&
+                    lp.linkAddresses.contains(linkAddress) &&
+                    lp.mtu == mtu
+        }
+        mCallback.onLinkPropertiesChanged(net, linkProps)
+        assertFails { mCallback.expectLinkPropertiesThat(net, SHORT_TIMEOUT_MS) { lp ->
+            lp.interfaceName != TEST_INTERFACE_NAME
+        } }
+
+        // Try a matching callback on the wrong network
+        mCallback.onLinkPropertiesChanged(net, linkProps)
+        assertFails { mCallback.expectLinkPropertiesThat(Network(114), SHORT_TIMEOUT_MS) { lp ->
+            lp.interfaceName == TEST_INTERFACE_NAME
+        } }
+    }
+
+    @Test
+    fun testExpectCallback() {
+        val net = Network(103)
+        // Test expectCallback fails when nothing was sent.
+        assertFails { mCallback.expectCallback<BlockedStatus>(net, SHORT_TIMEOUT_MS) }
+
+        // Test onAvailable is seen and can be expected
+        mCallback.onAvailable(net)
+        mCallback.expectCallback<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) }
+
+        // Test onAvailable won't return calls with a different callback
+        mCallback.onAvailable(net)
+        assertFails { mCallback.expectCallback<BlockedStatus>(net, SHORT_TIMEOUT_MS) }
+    }
+
+    @Test
+    fun testPollForNextCallback() {
+        assertFails { mCallback.pollForNextCallback(SHORT_TIMEOUT_MS) }
+        TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1,
+                threadTransform = { cb -> cb.createLinkedCopy() }, spec = """
+            sleep; onAvailable(133)    | poll(2) = Available(133) time 1..4
+                                       | poll(1) fails
+            onCapabilitiesChanged(108) | poll(1) = CapabilitiesChanged(108) time 0..3
+            onBlockedStatus(199)       | poll(1) = BlockedStatus(199) time 0..3
+        """)
+    }
+
+    @Test
+    fun testEventuallyExpect() {
+        // TODO: Current test does not verify the inline one. Also verify the behavior after
+        // aligning two eventuallyExpect()
+        val net1 = Network(100)
+        val net2 = Network(101)
+        mCallback.onAvailable(net1)
+        mCallback.onCapabilitiesChanged(net1, NetworkCapabilities())
+        mCallback.onLinkPropertiesChanged(net1, LinkProperties())
+        mCallback.eventuallyExpect(LINK_PROPERTIES_CHANGED) {
+            net1.equals(it.network)
+        }
+        // No further new callback. Expect no callback.
+        assertFails { mCallback.eventuallyExpect(LINK_PROPERTIES_CHANGED, SHORT_TIMEOUT_MS) }
+
+        // Verify no predicate set.
+        mCallback.onAvailable(net2)
+        mCallback.onLinkPropertiesChanged(net2, LinkProperties())
+        mCallback.onBlockedStatusChanged(net1, false)
+        mCallback.eventuallyExpect(BLOCKED_STATUS) { net1.equals(it.network) }
+        // Verify no callback received if the callback does not happen.
+        assertFails { mCallback.eventuallyExpect(LOSING, SHORT_TIMEOUT_MS) }
+    }
+
+    @Test
+    fun testEventuallyExpectOnMultiThreads() {
+        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)
+                onAvailable(101) ; onBlockedStatus(101) | eventually(BlockedStatus(100), 2) fails
+                onSuspended(100) ; sleep ; onLost(100)  | eventually(Lost(100), 2)
+        """)
+    }
+}
+
+private object TNCInterpreter : ConcurrentInterpreter<TestableNetworkCallback>(interpretTable)
+
+val EntryList = CallbackEntry::class.sealedSubclasses.map { it.simpleName }.joinToString("|")
+private fun callbackEntryFromString(name: String): KClass<out CallbackEntry> {
+    return CallbackEntry::class.sealedSubclasses.first { it.simpleName == name }
+}
+
+@SuppressLint("NewApi") // Uses hidden APIs, which the linter would identify as missing APIs.
+private val interpretTable = listOf<InterpretMatcher<TestableNetworkCallback>>(
+    // Interpret "Available(xx)" as "call to onAvailable with netId xx", and likewise for
+    // all callback types. This is implemented above by enumerating the subclasses of
+    // CallbackEntry and reading their simpleName.
+    Regex("""(.*)\s+=\s+($EntryList)\((\d+)\)""") to { i, cb, t ->
+        val record = i.interpret(t.strArg(1), cb)
+        assertTrue(callbackEntryFromString(t.strArg(2)).isInstance(record))
+        // Strictly speaking testing for is CallbackEntry is useless as it's been tested above
+        // but the compiler can't figure things out from the isInstance call. It does understand
+        // from the assertTrue(is CallbackEntry) that this is true, which allows to access
+        // the 'network' member below.
+        assertTrue(record is CallbackEntry)
+        assertEquals(record.network.netId, t.intArg(3))
+    },
+    // Interpret "onAvailable(xx)" as calling "onAvailable" with a netId of xx, and likewise for
+    // all callback types. NetworkCapabilities and LinkProperties just get an empty object
+    // as their argument. Losing gets the default linger timer. Blocked gets false.
+    Regex("""on($EntryList)\((\d+)\)""") to { i, cb, t ->
+        val net = Network(t.intArg(2))
+        when (t.strArg(1)) {
+            "Available" -> cb.onAvailable(net)
+            // PreCheck not used in tests. Add it here if it becomes useful.
+            "CapabilitiesChanged" -> cb.onCapabilitiesChanged(net, NetworkCapabilities())
+            "LinkPropertiesChanged" -> cb.onLinkPropertiesChanged(net, LinkProperties())
+            "Suspended" -> cb.onNetworkSuspended(net)
+            "Resumed" -> cb.onNetworkResumed(net)
+            "Losing" -> cb.onLosing(net, DEFAULT_LINGER_DELAY_MS)
+            "Lost" -> cb.onLost(net)
+            "Unavailable" -> cb.onUnavailable()
+            "BlockedStatus" -> cb.onBlockedStatusChanged(net, false)
+            else -> fail("Unknown callback type")
+        }
+    },
+    Regex("""poll\((\d+)\)""") to { i, cb, t ->
+        cb.pollForNextCallback(t.timeArg(1))
+    },
+    // Interpret "eventually(Available(xx), timeout)" as calling eventuallyExpect that expects
+    // CallbackEntry.AVAILABLE with netId of xx within timeout*INTERPRET_TIME_UNIT timeout, and
+    // likewise for all callback types.
+    Regex("""eventually\(($EntryList)\((\d+)\),\s+(\d+)\)""") to { i, cb, t ->
+        val net = Network(t.intArg(2))
+        val timeout = t.timeArg(3)
+        when (t.strArg(1)) {
+            "Available" -> cb.eventuallyExpect(AVAILABLE, timeout) { net == it.network }
+            "Suspended" -> cb.eventuallyExpect(SUSPENDED, timeout) { net == it.network }
+            "Resumed" -> cb.eventuallyExpect(RESUMED, timeout) { net == it.network }
+            "Losing" -> cb.eventuallyExpect(LOSING, timeout) { net == it.network }
+            "Lost" -> cb.eventuallyExpect(LOST, timeout) { net == it.network }
+            "Unavailable" -> cb.eventuallyExpect(UNAVAILABLE, timeout) { net == it.network }
+            "BlockedStatus" -> cb.eventuallyExpect(BLOCKED_STATUS, timeout) { net == it.network }
+            "CapabilitiesChanged" ->
+                cb.eventuallyExpect(NETWORK_CAPS_UPDATED, timeout) { net == it.network }
+            "LinkPropertiesChanged" ->
+                cb.eventuallyExpect(LINK_PROPERTIES_CHANGED, timeout) { net == it.network }
+            else -> fail("Unknown callback type")
+        }
+    }
+)
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt
index fc951d8..7e92af1 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt
@@ -75,7 +75,7 @@
                     timeoutMs = WIFI_CONNECT_TIMEOUT_MS)
 
             assertNotNull(cb, "Could not connect to a wifi access point within " +
-                    "$WIFI_CONNECT_INTERVAL_MS ms. Check that the test device has a wifi network " +
+                    "$WIFI_CONNECT_TIMEOUT_MS ms. Check that the test device has a wifi network " +
                     "configured, and that the test access point is functioning properly.")
             return cb.network
         } finally {