Merge "Change DnsPacket.DnsRecord.MAXNAMESIZE to public"
diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
index e69a844..f8b4716 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
@@ -39,6 +39,7 @@
 
 import android.net.util.SocketUtils;
 import android.os.Process;
+import android.os.SystemClock;
 import android.system.ErrnoException;
 import android.util.Log;
 import android.util.Range;
@@ -461,11 +462,15 @@
      */
     public static void destroyLiveTcpSockets(Set<Range<Integer>> ranges, Set<Integer> exemptUids)
             throws SocketException, InterruptedIOException, ErrnoException {
+        final long startTimeMs = SystemClock.elapsedRealtime();
         destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER,
                 (diagMsg) -> !exemptUids.contains(diagMsg.inetDiagMsg.idiag_uid)
                         && containsUid(diagMsg, ranges)
                         && !isLoopback(diagMsg)
                         && !isAdbSocket(diagMsg));
+        final long durationMs = SystemClock.elapsedRealtime() - startTimeMs;
+        Log.d(TAG, "Destroyed live tcp sockets for uids=" + ranges + " exemptUids=" + exemptUids
+                + " in " + durationMs + "ms");
     }
 
     /**
@@ -479,10 +484,13 @@
      */
     public static void destroyLiveTcpSocketsByOwnerUids(Set<Integer> ownerUids)
             throws SocketException, InterruptedIOException, ErrnoException {
+        final long startTimeMs = SystemClock.elapsedRealtime();
         destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER,
                 (diagMsg) -> ownerUids.contains(diagMsg.inetDiagMsg.idiag_uid)
                         && !isLoopback(diagMsg)
                         && !isAdbSocket(diagMsg));
+        final long durationMs = SystemClock.elapsedRealtime() - startTimeMs;
+        Log.d(TAG, "Destroyed live tcp sockets for uids=" + ownerUids + " in " + durationMs + "ms");
     }
 
     @Override
diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
index 308ea24..b512a95 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
@@ -93,6 +93,15 @@
         if (nlmsghdr == null || nlmsghdr.nlmsg_type != NetlinkConstants.NLMSG_ERROR) {
             return null;
         }
+
+        final int messageLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len);
+        final int payloadLength = messageLength - StructNlMsgHdr.STRUCT_SIZE;
+        if (payloadLength < 0 || payloadLength > bytes.remaining()) {
+            // Malformed message or runt buffer.  Pretend the buffer was consumed.
+            bytes.position(bytes.limit());
+            return null;
+        }
+
         return NetlinkErrorMessage.parse(nlmsghdr, bytes);
     }
 
diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h
index b3dd86c..59257b8 100644
--- a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h
+++ b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h
@@ -57,11 +57,11 @@
 }
 
 #if defined(__LP64__)
-static_assert(isUserspace64bit(), "huh?");
+static_assert(isUserspace64bit(), "huh? LP64 must have 64-bit userspace");
 #elif defined(__ILP32__)
-static_assert(isUserspace32bit(), "huh?");
+static_assert(isUserspace32bit(), "huh? ILP32 must have 32-bit userspace");
 #else
-#error "huh?"
+#error "huh? must be either LP64 (64-bit userspace) or ILP32 (32-bit userspace)"
 #endif
 
 static_assert(isUserspace32bit() || isUserspace64bit(), "must be either 32 or 64 bit");
@@ -119,7 +119,11 @@
 }
 
 static constexpr bool isArm() {
-#if defined(__arm__) || defined(__aarch64__)
+#if defined(__arm__)
+    static_assert(isUserspace32bit(), "huh? arm must be 32 bit");
+    return true;
+#elif defined(__aarch64__)
+    static_assert(isUserspace64bit(), "aarch64 must be LP64 - no support for ILP32");
     return true;
 #else
     return false;
@@ -127,7 +131,11 @@
 }
 
 static constexpr bool isX86() {
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__)
+    static_assert(isUserspace32bit(), "huh? i386 must be 32 bit");
+    return true;
+#elif defined(__x86_64__)
+    static_assert(isUserspace64bit(), "x86_64 must be LP64 - no support for ILP32 (x32)");
     return true;
 #else
     return false;
diff --git a/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt b/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt
index 30e0daf..0f6fa48 100644
--- a/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt
+++ b/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt
@@ -18,8 +18,10 @@
 
 import android.os.Handler
 import android.os.HandlerThread
+import com.android.testutils.FunctionalUtils.ThrowingSupplier
 import kotlin.test.assertEquals
 import kotlin.test.assertFailsWith
+import kotlin.test.assertNull
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -69,13 +71,18 @@
 
         repeat(ATTEMPTS) { attempt ->
             var x = -10
-            visibleOnHandlerThread(handler) { x = attempt }
+            var y = -11
+            y = visibleOnHandlerThread(handler, ThrowingSupplier<Int> { x = attempt; attempt })
             assertEquals(attempt, x)
+            assertEquals(attempt, y)
             handler.post { assertEquals(attempt, x) }
         }
 
         assertFailsWith<IllegalArgumentException> {
             visibleOnHandlerThread(handler) { throw IllegalArgumentException() }
         }
+
+        // Null values may be returned by the supplier
+        assertNull(visibleOnHandlerThread(handler, ThrowingSupplier<Nothing?> { null }))
     }
 }
diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt
index 4ed881a..e838bdc 100644
--- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt
+++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt
@@ -354,6 +354,13 @@
     }
 
     @Test
+    fun testExpectClass() {
+        val net = Network(1)
+        mCallback.onAvailable(net)
+        assertFails { mCallback.expect(LOST, net) }
+    }
+
+    @Test
     fun testPoll() {
         assertNull(mCallback.poll(SHORT_TIMEOUT_MS))
         TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1,
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt
index aa252a5..f00ca11 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt
@@ -23,6 +23,7 @@
 import android.os.HandlerThread
 import android.util.Log
 import com.android.testutils.FunctionalUtils.ThrowingRunnable
+import com.android.testutils.FunctionalUtils.ThrowingSupplier
 import java.lang.Exception
 import java.util.concurrent.Executor
 import kotlin.test.fail
@@ -55,7 +56,8 @@
 }
 
 /**
- * Executes a block of code, making its side effects visible on the caller and the handler thread
+ * Executes a block of code that returns a value, making its side effects visible on the caller and
+ * the handler thread.
  *
  * After this function returns, the side effects of the passed block of code are guaranteed to be
  * observed both on the thread running the handler and on the thread running this method.
@@ -63,15 +65,15 @@
  * until it's executed, so keep in mind this method will block, (including, if the handler isn't
  * running, blocking forever).
  */
-fun visibleOnHandlerThread(handler: Handler, r: ThrowingRunnable) {
+fun <T> visibleOnHandlerThread(handler: Handler, supplier: ThrowingSupplier<T>): T {
     val cv = ConditionVariable()
-    var e: Exception? = null
+    var rv: Result<T> = Result.failure(RuntimeException("Not run"))
     handler.post {
         try {
-            r.run()
+            rv = Result.success(supplier.get())
         } catch (exception: Exception) {
             Log.e(TAG, "visibleOnHandlerThread caught exception", exception)
-            e = exception
+            rv = Result.failure(exception)
         }
         cv.open()
     }
@@ -79,5 +81,10 @@
     // and this thread also has seen the change (since cv.open() happens-before cv.block()
     // returns).
     cv.block()
-    e?.let { throw it }
+    return rv.getOrThrow()
+}
+
+/** Overload of visibleOnHandlerThread but executes a block of code that does not return a value. */
+inline fun visibleOnHandlerThread(handler: Handler, r: ThrowingRunnable){
+    visibleOnHandlerThread(handler, ThrowingSupplier<Unit> { r.run() })
 }
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java b/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java
index 85c6493..0a2b5d4 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java
+++ b/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java
@@ -151,7 +151,8 @@
     private void processPacket() {
         final int len = PacketReflectorUtil.readPacket(mSrcFd, mBuf);
         if (len < 1) {
-            throw new IllegalStateException("Unexpected buffer length: " + len);
+            // Usually happens when socket read is being interrupted, e.g. stopping PacketForwarder.
+            return;
         }
 
         final int version = mBuf[0] >>> 4;
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt
index b028045..498b1a3 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt
@@ -20,11 +20,12 @@
 
 import android.system.ErrnoException
 import android.system.Os
+import android.system.OsConstants
 import com.android.net.module.util.IpUtils
 import com.android.testutils.PacketReflector.IPV4_HEADER_LENGTH
 import com.android.testutils.PacketReflector.IPV6_HEADER_LENGTH
 import java.io.FileDescriptor
-import java.io.IOException
+import java.io.InterruptedIOException
 import java.net.InetAddress
 import java.nio.ByteBuffer
 
@@ -32,8 +33,15 @@
     return try {
         Os.read(fd, buf, 0, buf.size)
     } catch (e: ErrnoException) {
-        -1
-    } catch (e: IOException) {
+        // Ignore normal use cases such as the EAGAIN error indicates that the read operation
+        // cannot be completed immediately, or the EINTR error indicates that the read
+        // operation was interrupted by a signal.
+        if (e.errno == OsConstants.EAGAIN || e.errno == OsConstants.EINTR) {
+            -1
+        } else {
+            throw e
+        }
+    } catch (e: InterruptedIOException) {
         -1
     }
 }
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt
index 0e73112..4b6aea2 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt
@@ -236,7 +236,11 @@
         errorMsg: String? = null,
         test: (T) -> Boolean = { true }
     ) = expect<CallbackEntry>(network, timeoutMs, errorMsg) {
-        test(it as? T ?: fail("Expected callback ${type.simpleName}, got $it"))
+        if (type.isInstance(it)) {
+            test(it as T) // Cast can't fail since type.isInstance(it) and type: KClass<T>
+        } else {
+            fail("Expected callback ${type.simpleName}, got $it")
+        }
     } as T
 
     @JvmOverloads