Merge "bpfloader: ignore_on_(arch) support"
diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp
index 31adef9..41184ea 100644
--- a/staticlibs/native/bpf_headers/Android.bp
+++ b/staticlibs/native/bpf_headers/Android.bp
@@ -33,8 +33,10 @@
     min_sdk_version: "30",
     apex_available: [
         "//apex_available:platform",
-        "com.android.tethering",
         "com.android.art.debug",
+        "com.android.os.statsd",
+        "com.android.resolv",
+        "com.android.tethering",
     ],
 }
 
diff --git a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp
index d23afae..6c0841c 100644
--- a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp
+++ b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp
@@ -25,6 +25,7 @@
 #include "BpfSyscallWrappers.h"
 #include "bpf/BpfRingbuf.h"
 #include "bpf/BpfUtils.h"
+#include "bpf/KernelUtils.h"
 
 #define TEST_RINGBUF_MAGIC_NUM 12345
 
@@ -49,10 +50,6 @@
       GTEST_SKIP() << "BPF ring buffers not supported below 5.8";
     }
 
-    if (sizeof(unsigned long) != 8) {
-      GTEST_SKIP() << "BPF ring buffers not supported on 32 bit arch";
-    }
-
     errno = 0;
     mProgram.reset(retrieveProgram(mProgPath.c_str()));
     EXPECT_EQ(errno, 0);
diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
index cac1e43..dd1504c 100644
--- a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
+++ b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
@@ -24,6 +24,8 @@
 
 #include "bpf/BpfUtils.h"
 
+#include <atomic>
+
 namespace android {
 namespace bpf {
 
@@ -80,8 +82,28 @@
   android::base::unique_fd mRingFd;
 
   void* mDataPos = nullptr;
-  unsigned long* mConsumerPos = nullptr;
-  unsigned long* mProducerPos = nullptr;
+  // The kernel uses an "unsigned long" type for both consumer and producer position.
+  // Unsigned long is a 4 byte value on a 32-bit kernel, and an 8 byte value on a 64-bit kernel.
+  // To support 32-bit kernels, producer pos is capped at 4 bytes (despite it being 8 bytes on
+  // 64-bit kernels) and all comparisons of consumer and producer pos only compare the low-order 4
+  // bytes (an inequality comparison is performed to support overflow).
+  // This solution is bitness agnostic. The consumer only increments the 8 byte consumer pos, which,
+  // in a little-endian architecture, is safe since the entire page is mapped into memory and a
+  // 32-bit kernel will just ignore the high-order bits.
+  std::atomic_uint64_t* mConsumerPos = nullptr;
+  std::atomic_uint32_t* mProducerPos = nullptr;
+
+  // In order to guarantee atomic access in a 32 bit userspace environment, atomic_uint64_t is used
+  // in addition to std::atomic<T>::is_always_lock_free that guarantees that read / write operations
+  // are indeed atomic.
+  // Since std::atomic does not support wrapping preallocated memory, an additional static assert on
+  // the size of the atomic and the underlying type is added to ensure a reinterpret_cast from type
+  // to its atomic version is safe (is_always_lock_free being true should provide additional
+  // confidence).
+  static_assert(std::atomic_uint64_t::is_always_lock_free);
+  static_assert(std::atomic_uint32_t::is_always_lock_free);
+  static_assert(sizeof(std::atomic_uint64_t) == sizeof(uint64_t));
+  static_assert(sizeof(std::atomic_uint32_t) == sizeof(uint32_t));
 };
 
 // This is a class wrapper for eBPF ring buffers. An eBPF ring buffer is a
@@ -121,34 +143,8 @@
   BpfRingbuf() : BpfRingbufBase(sizeof(Value)) {}
 };
 
-#define ACCESS_ONCE(x) (*(volatile typeof(x)*)&(x))
-
-#if defined(__i386__) || defined(__x86_64__)
-#define smp_sync() asm volatile("" ::: "memory")
-#elif defined(__aarch64__)
-#define smp_sync() asm volatile("dmb ish" ::: "memory")
-#else
-#define smp_sync() __sync_synchronize()
-#endif
-
-#define smp_store_release(p, v) \
-  do {                          \
-    smp_sync();                 \
-    ACCESS_ONCE(*(p)) = (v);    \
-  } while (0)
-
-#define smp_load_acquire(p)        \
-  ({                               \
-    auto ___p = ACCESS_ONCE(*(p)); \
-    smp_sync();                    \
-    ___p;                          \
-  })
 
 inline base::Result<void> BpfRingbufBase::Init(const char* path) {
-  if (sizeof(unsigned long) != 8) {
-    return android::base::Error()
-           << "BpfRingbuf does not support 32 bit architectures";
-  }
   mRingFd.reset(mapRetrieveRW(path));
   if (!mRingFd.ok()) {
     return android::base::ErrnoError()
@@ -184,7 +180,7 @@
       return android::base::ErrnoError()
              << "failed to mmap ringbuf consumer pages";
     }
-    mConsumerPos = reinterpret_cast<unsigned long*>(ptr);
+    mConsumerPos = reinterpret_cast<decltype(mConsumerPos)>(ptr);
   }
 
   {
@@ -194,7 +190,7 @@
       return android::base::ErrnoError()
              << "failed to mmap ringbuf producer page";
     }
-    mProducerPos = reinterpret_cast<unsigned long*>(ptr);
+    mProducerPos = reinterpret_cast<decltype(mProducerPos)>(ptr);
   }
 
   mDataPos = pointerAddBytes<void*>(mProducerPos, getpagesize());
@@ -204,14 +200,19 @@
 inline base::Result<int> BpfRingbufBase::ConsumeAll(
     const std::function<void(const void*)>& callback) {
   int64_t count = 0;
-  unsigned long cons_pos = smp_load_acquire(mConsumerPos);
-  unsigned long prod_pos = smp_load_acquire(mProducerPos);
-  while (cons_pos < prod_pos) {
+  uint32_t prod_pos = mProducerPos->load(std::memory_order_acquire);
+  // Only userspace writes to mConsumerPos, so no need to use std::memory_order_acquire
+  uint64_t cons_pos = mConsumerPos->load(std::memory_order_relaxed);
+  while ((cons_pos & 0xFFFFFFFF) != prod_pos) {
     // Find the start of the entry for this read (wrapping is done here).
     void* start_ptr = pointerAddBytes<void*>(mDataPos, cons_pos & mPosMask);
 
     // The entry has an 8 byte header containing the sample length.
-    uint32_t length = smp_load_acquire(reinterpret_cast<uint32_t*>(start_ptr));
+    // struct bpf_ringbuf_hdr {
+    //   u32 len;
+    //   u32 pg_off;
+    // };
+    uint32_t length = *reinterpret_cast<volatile uint32_t*>(start_ptr);
 
     // If the sample isn't committed, we're caught up with the producer.
     if (length & BPF_RINGBUF_BUSY_BIT) return count;
@@ -220,7 +221,7 @@
 
     if ((length & BPF_RINGBUF_DISCARD_BIT) == 0) {
       if (length != mValueSize) {
-        smp_store_release(mConsumerPos, cons_pos);
+        mConsumerPos->store(cons_pos, std::memory_order_release);
         errno = EMSGSIZE;
         return android::base::ErrnoError()
                << "BPF ring buffer message has unexpected size (want "
@@ -230,7 +231,7 @@
       count++;
     }
 
-    smp_store_release(mConsumerPos, cons_pos);
+    mConsumerPos->store(cons_pos, std::memory_order_release);
   }
 
   return count;
@@ -252,10 +253,5 @@
   });
 }
 
-#undef ACCESS_ONCE
-#undef smp_sync
-#undef smp_store_release
-#undef smp_load_acquire
-
 }  // namespace bpf
 }  // namespace android
diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h
index 3f82deb..b3dd86c 100644
--- a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h
+++ b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h
@@ -48,12 +48,26 @@
 
 // Figure out the bitness of userspace.
 // Trivial and known at compile time.
-static constexpr bool isUserspace64bit() {
-    return sizeof(long) == 8;
+static constexpr bool isUserspace32bit() {
+    return sizeof(void*) == 4;
 }
 
+static constexpr bool isUserspace64bit() {
+    return sizeof(void*) == 8;
+}
+
+#if defined(__LP64__)
+static_assert(isUserspace64bit(), "huh?");
+#elif defined(__ILP32__)
+static_assert(isUserspace32bit(), "huh?");
+#else
+#error "huh?"
+#endif
+
+static_assert(isUserspace32bit() || isUserspace64bit(), "must be either 32 or 64 bit");
+
 // Figure out the bitness of the kernel.
-static inline __unused bool isKernel64Bit() {
+static inline bool isKernel64Bit() {
     // a 64-bit userspace requires a 64-bit kernel
     if (isUserspace64bit()) return true;
 
@@ -100,5 +114,52 @@
     return cache;
 }
 
+static inline __unused bool isKernel32Bit() {
+    return !isKernel64Bit();
+}
+
+static constexpr bool isArm() {
+#if defined(__arm__) || defined(__aarch64__)
+    return true;
+#else
+    return false;
+#endif
+}
+
+static constexpr bool isX86() {
+#if defined(__i386__) || defined(__x86_64__)
+    return true;
+#else
+    return false;
+#endif
+}
+
+static constexpr bool isRiscV() {
+#if defined(__riscv)
+    static_assert(isUserspace64bit(), "riscv must be 64 bit");
+    return true;
+#else
+    return false;
+#endif
+}
+
+static_assert(isArm() || isX86() || isRiscV(), "Unknown architecture");
+
+static __unused const char * describeArch() {
+    // ordered so as to make it easier to compile time optimize,
+    // only thing not known at compile time is isKernel64Bit()
+    if (isUserspace64bit()) {
+        if (isArm()) return "64-on-aarch64";
+        if (isX86()) return "64-on-x86-64";
+        if (isRiscV()) return "64-on-riscv64";
+    } else if (isKernel64Bit()) {
+        if (isArm()) return "32-on-aarch64";
+        if (isX86()) return "32-on-x86-64";
+    } else {
+        if (isArm()) return "32-on-arm32";
+        if (isX86()) return "32-on-x86-32";
+    }
+}
+
 }  // namespace bpf
 }  // namespace android
diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp
index 125d631..b3efc21 100644
--- a/staticlibs/native/bpf_syscall_wrappers/Android.bp
+++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp
@@ -33,6 +33,8 @@
         "//apex_available:platform",
         "com.android.art.debug",
         "com.android.mediaprovider",
+        "com.android.os.statsd",
+        "com.android.resolv",
         "com.android.tethering",
     ],
 }
diff --git a/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt b/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt
index fd837aa..3fc74aa 100644
--- a/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt
+++ b/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt
@@ -48,6 +48,11 @@
 
     override fun setUp(testInformation: TestInformation) {
         if (isDisabled) return
+        disableGmsUpdate(testInformation)
+        runPreparerApk(testInformation)
+    }
+
+    private fun runPreparerApk(testInformation: TestInformation) {
         installer.setCleanApk(true)
         installer.addTestFileName(CONNECTIVITY_CHECKER_APK)
         installer.setShouldGrantPermission(true)
@@ -90,8 +95,22 @@
                 testInformation.device.deviceDescriptor)
     }
 
-    override fun tearDown(testInformation: TestInformation?, e: Throwable?) {
+    private fun disableGmsUpdate(testInformation: TestInformation) {
+        // This will be a no-op on devices without root (su) or not using gservices, but that's OK.
+        testInformation.device.executeShellCommand("su 0 am broadcast " +
+                "-a com.google.gservices.intent.action.GSERVICES_OVERRIDE " +
+                "-e finsky.play_services_auto_update_enabled false")
+    }
+
+    private fun clearGmsUpdateOverride(testInformation: TestInformation) {
+        testInformation.device.executeShellCommand("su 0 am broadcast " +
+                "-a com.google.gservices.intent.action.GSERVICES_OVERRIDE " +
+                "--esn finsky.play_services_auto_update_enabled")
+    }
+
+    override fun tearDown(testInformation: TestInformation, e: Throwable?) {
         if (isTearDownDisabled) return
         installer.tearDown(testInformation, e)
+        clearGmsUpdateOverride(testInformation)
     }
 }