Merge "Make firewall bpf code multi-user aware" into main
diff --git a/netbpfload/NetBpfLoad.cpp b/netbpfload/NetBpfLoad.cpp
index e9c6d8a..0d4a5c4 100644
--- a/netbpfload/NetBpfLoad.cpp
+++ b/netbpfload/NetBpfLoad.cpp
@@ -57,6 +57,7 @@
 using base::StartsWith;
 using base::EndsWith;
 using std::string;
+using std::vector;
 
 static bool exists(const char* const path) {
     int v = access(path, F_OK);
@@ -248,6 +249,22 @@
     return tv;
 }
 
+static bool isWear() {
+    static string wearSdkStr = base::GetProperty("ro.cw_build.wear_sdk.version", "");
+    static int wearSdkInt = base::GetIntProperty("ro.cw_build.wear_sdk.version", 0);
+    static string buildChars = base::GetProperty("ro.build.characteristics", "");
+    static vector<string> v = base::Tokenize(buildChars, ",");
+    static bool watch = (std::find(v.begin(), v.end(), "watch") != v.end());
+    static bool wear = (wearSdkInt > 0) || watch;
+    static bool logged = false;
+    if (!logged) {
+        logged = true;
+        ALOGI("isWear(ro.cw_build.wear_sdk.version=%d[%s] ro.build.characteristics='%s'): %s",
+              wearSdkInt, wearSdkStr.c_str(), buildChars.c_str(), wear ? "true" : "false");
+    }
+    return wear;
+}
+
 static int doLoad(char** argv, char * const envp[]) {
     const bool runningAsRoot = !getuid();  // true iff U QPR3 or V+
 
@@ -402,7 +419,8 @@
          * and 32-bit userspace on 64-bit kernel bpf ringbuffer compatibility is broken.
          */
         ALOGE("64-bit userspace required on 6.2+ kernels.");
-        if (!isTV()) return 1;
+        // Stuff won't work reliably, but exempt TVs & Arm Wear devices
+        if (!isTV() && !(isWear() && isArm())) return 1;
     }
 
     // Ensure we can determine the Android build type.
diff --git a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
index 3563f2c..f6cbeeb 100644
--- a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
+++ b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
@@ -29,7 +29,11 @@
 import android.net.apf.ApfConstants.ETH_ETHERTYPE_OFFSET
 import android.net.apf.ApfConstants.ICMP6_TYPE_OFFSET
 import android.net.apf.ApfConstants.IPV6_NEXT_HEADER_OFFSET
+import android.net.apf.ApfCounterTracker
+import android.net.apf.ApfCounterTracker.Counter.FILTER_AGE_16384THS
 import android.net.apf.ApfV4Generator
+import android.net.apf.ApfV4GeneratorBase
+import android.net.apf.ApfV6Generator
 import android.net.apf.BaseApfGenerator
 import android.net.apf.BaseApfGenerator.MemorySlot
 import android.net.apf.BaseApfGenerator.Register.R0
@@ -73,7 +77,6 @@
 import com.google.common.truth.Truth.assertWithMessage
 import com.google.common.truth.TruthJUnit.assume
 import java.io.FileDescriptor
-import java.lang.Thread
 import java.net.InetSocketAddress
 import java.nio.ByteBuffer
 import java.util.concurrent.CompletableFuture
@@ -394,7 +397,7 @@
         }
     }
 
-    fun ApfV4Generator.addPassIfNotIcmpv6EchoReply() {
+    fun ApfV4GeneratorBase<*>.addPassIfNotIcmpv6EchoReply() {
         // If not IPv6 -> PASS
         addLoad16(R0, ETH_ETHERTYPE_OFFSET)
         addJumpIfR0NotEquals(ETH_P_IPV6.toLong(), BaseApfGenerator.PASS_LABEL)
@@ -573,4 +576,50 @@
         val timeDiff = filterAgeSeconds - filterAgeSecondsOrig
         assertThat(timeDiff).isAnyOf(5, 6)
     }
+
+    @VsrTest(requirements = ["VSR-5.3.12-002", "VSR-5.3.12-005"])
+    @Test
+    fun testFilterAge16384thsIncreasesBetweenPackets() {
+        assumeApfVersionSupportAtLeast(6000)
+        clearApfMemory()
+        val gen = ApfV6Generator(
+                caps.apfVersionSupported,
+                caps.maximumApfProgramSize,
+                caps.maximumApfProgramSize
+        )
+
+        // If not ICMPv6 Echo Reply -> PASS
+        gen.addPassIfNotIcmpv6EchoReply()
+
+        // Store all prefilled memory slots in counter region [500, 520)
+        gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_16384THS)
+        gen.addStoreCounter(FILTER_AGE_16384THS, R0)
+
+        installProgram(gen.generate())
+        readProgram() // wait for install completion
+
+        val payloadSize = 56
+        val data = ByteArray(payloadSize).also { Random.nextBytes(it) }
+        packetReader.sendPing(data, payloadSize)
+        packetReader.expectPingReply()
+
+        var apfRam = readProgram()
+        val filterAge16384thSecondsOrig =
+                ApfCounterTracker.getCounterValue(apfRam, FILTER_AGE_16384THS)
+
+        Thread.sleep(5000)
+
+        packetReader.sendPing(data, payloadSize)
+        packetReader.expectPingReply()
+
+        apfRam = readProgram()
+        val filterAge16384thSeconds = ApfCounterTracker.getCounterValue(apfRam, FILTER_AGE_16384THS)
+        val timeDiff = (filterAge16384thSeconds - filterAge16384thSecondsOrig)
+        // Expect the HAL plus ping latency to be less than 800ms.
+        val timeDiffLowerBound = (4.99 * 16384).toInt()
+        val timeDiffUpperBound = (5.81 * 16384).toInt()
+        // Assert that filter age has increased, but not too much.
+        assertThat(timeDiff).isGreaterThan(timeDiffLowerBound)
+        assertThat(timeDiff).isLessThan(timeDiffUpperBound)
+    }
 }