Merge "Mock QuiConnectionCloser in ConnectivityServiceTest" into main
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 68cbdc7..97a78cf 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -15,6 +15,3 @@
 hidden_api_txt_checksorted_hook = ${REPO_ROOT}/tools/platform-compat/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
 
 python_hook = ${REPO_ROOT}/packages/modules/Connectivity/preupload_hook_script.py ${PREUPLOAD_FILES}
-
-# go/alint for details
-alint_hook = ${REPO_ROOT}/vendor/google/tools/alint
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 8f701ba..89edc32 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -501,6 +501,12 @@
                     lastMaxSessionCount);
         }
 
+        /** Send a BpfCoordinatorShimInitError event. */
+        public void sendBpfCoordinatorShimInitError() {
+            ConnectivityStatsLog.write(ConnectivityStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED,
+                    ConnectivityStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED__ERROR_TYPE__TYPE_BPF_COORDINATOR_SHIM_INIT_ERROR);
+        }
+
         /**
          * @see DeviceConfigUtils#isTetheringFeatureEnabled
          */
@@ -542,6 +548,7 @@
         mBpfCoordinatorShim = BpfCoordinatorShim.getBpfCoordinatorShim(deps);
         if (!mBpfCoordinatorShim.isInitialized()) {
             mLog.e("Bpf shim not initialized");
+            mDeps.sendBpfCoordinatorShimInitError();
         }
 
         // BPF IPv4 forwarding only supports on S+.
diff --git a/bpf/loader/netbpfload.35rc b/bpf/loader/netbpfload.35rc
index 683abce..a23bd60 100644
--- a/bpf/loader/netbpfload.35rc
+++ b/bpf/loader/netbpfload.35rc
@@ -1,6 +1,8 @@
+# This takes effect on Android 15+ (V+ 25Q2+)
+# Note that 'capabilities SYSLOG' lacks sepolicy prior to 25Q4
 service bpfloader /apex/com.android.tethering/bin/netbpfload
     # netbpfload will do network bpf loading, then execute /system/bin/bpfloader
-    capabilities CHOWN SYS_ADMIN NET_ADMIN
+    capabilities CHOWN SYS_ADMIN NET_ADMIN SYSLOG
     # The following group memberships are a workaround for lack of DAC_OVERRIDE
     # and allow us to open (among other things) files that we created and are
     # no longer root owned (due to CHOWN) but still have group read access to
diff --git a/bpf/progs/Android.bp b/bpf/progs/Android.bp
index 555cfef..4712c35 100644
--- a/bpf/progs/Android.bp
+++ b/bpf/progs/Android.bp
@@ -117,10 +117,3 @@
     include_dirs: ["packages/modules/Connectivity/bpf/progs/include"],
     sub_dir: "mainline",
 }
-
-bpf {
-    name: "tcpAccECN.o",
-    srcs: ["tcpAccECN.c"],
-    include_dirs: ["packages/modules/Connectivity/bpf/progs/include"],
-    sub_dir: "mainline",
-}
diff --git a/bpf/progs/netd.c b/bpf/progs/netd.c
index cb5ece7..e8299ef 100644
--- a/bpf/progs/netd.c
+++ b/bpf/progs/netd.c
@@ -902,4 +902,10 @@
     return BPF_ALLOW;
 }
 
+#undef BPFLOADER_MIN_VER
+#undef BPF_OBJ_NAME
+#undef DEFAULT_BPF_PIN_SUBDIR
+
+#include "tcpAccECN.c"
+
 LICENSE("Apache 2.0");
diff --git a/bpf/progs/netd.h b/bpf/progs/netd.h
index 79c6e37..8b9486e 100644
--- a/bpf/progs/netd.h
+++ b/bpf/progs/netd.h
@@ -236,8 +236,6 @@
 // Entry in the data saver enabled map that stores whether data saver is enabled or not.
 #define DATA_SAVER_ENABLED_KEY 0
 
-#undef STRUCT_SIZE
-
 // DROP_IF_SET is set of rules that DROP if rule is globally enabled, and per-uid bit is set
 #define DROP_IF_SET (STANDBY_MATCH | OEM_DENY_1_MATCH | OEM_DENY_2_MATCH | OEM_DENY_3_MATCH)
 // DROP_IF_UNSET is set of rules that should DROP if globally enabled, and per-uid bit is NOT set
diff --git a/bpf/progs/tcpAccECN.c b/bpf/progs/tcpAccECN.c
index 33a8917..ac90ace 100644
--- a/bpf/progs/tcpAccECN.c
+++ b/bpf/progs/tcpAccECN.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2025 Samsung Electronics. 
+ * Copyright (C) 2025 Samsung Electronics.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,12 +20,8 @@
  *              Includes separate handling for Ethernet and raw IP packets.
  */
 
-// The resulting .o needs to load on Android T+
-#define BPFLOADER_MIN_VER BPFLOADER_MAINLINE_T_VERSION
-#define BPF_OBJ_NAME "tcpAccECN"
-#define DEFAULT_BPF_PIN_SUBDIR "netd_shared"
-
 #include <linux/bpf.h>
+#include <linux/filter.h>
 #include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
@@ -33,30 +29,21 @@
 #include <linux/in6.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
 #include <linux/tcp.h>
 #include <stdint.h>
-#include "bpf_helpers.h"
-#include <tcpAccECN.h>
-#include <linux/pkt_cls.h>
-#include <linux/filter.h>
 
-// Offsets from beginning of L4 (TCP) header
-#define TCP_OFFSET(field) offsetof(struct tcphdr, field)
+// The resulting .o needs to load on Android 26Q2+
+#define BPFLOADER_MIN_VER BPFLOADER_MAINLINE_26Q2_VERSION
+#define BPF_OBJ_NAME "tcpAccECN"
+#define DEFAULT_BPF_PIN_SUBDIR "netd_shared"
 
-// Offsets from beginning of L3 (IPv4) header
-#define IP4_OFFSET(field) offsetof(struct iphdr, field)
-#define IP6_OFFSET(field) offsetof(struct ipv6hdr, field)
-#define IP4_TCP_OFFSET(field) (sizeof(struct iphdr) + TCP_OFFSET(field))
-#define IP6_TCP_OFFSET(field) (sizeof(struct ipv6hdr) + TCP_OFFSET(field))
+#include "bpf_net_helpers.h"
+#include "tcpAccECN.h"
 
-// Offsets from beginning of L2 (ie. Ethernet) header (which must be present)
-#define ETH_IP4_OFFSET(field) (ETH_HLEN + IP4_OFFSET(field))
-#define ETH_IP4_TCP_OFFSET(field) (ETH_HLEN + IP4_TCP_OFFSET(field))
-#define ETH_IP6_OFFSET(field) (ETH_HLEN + IP6_OFFSET(field))
-#define ETH_IP6_TCP_OFFSET(field) (ETH_HLEN + IP6_TCP_OFFSET(field))
-
-#define IP4_TCP_FLAGS_OFF (sizeof(struct iphdr) + 12)
-#define IP6_TCP_FLAGS_OFF (sizeof(struct ipv6hdr) + 12)
+#define TCP_FLAGS_OFF 12
+#define IP4_TCP_FLAGS_OFF (sizeof(struct iphdr) + TCP_FLAGS_OFF)
+#define IP6_TCP_FLAGS_OFF (sizeof(struct ipv6hdr) + TCP_FLAGS_OFF)
 
 #define ETH_IP4_TCP_FLAGS_OFF (ETH_HLEN + IP4_TCP_FLAGS_OFF)
 #define ETH_IP6_TCP_FLAGS_OFF (ETH_HLEN + IP6_TCP_FLAGS_OFF)
@@ -71,27 +58,10 @@
 DEFINE_BPF_MAP(l4s_accecn_byte_map, LRU_HASH, uint32_t, EcnByteCounters, L4S_ACCECN_MAP_SIZE)
 DEFINE_BPF_MAP(l4s_accecn_mss_map, LRU_HASH, uint32_t, uint16_t, L4S_ACCECN_MAP_SIZE)
 
-static int (*bpf_skb_store_bytes)(struct __sk_buff* skb, __u32 offset, const void* from, __u32 len,
-                                  __u64 flags) = (void*)BPF_FUNC_skb_store_bytes;
-
-static int (*bpf_l4_csum_replace)(struct __sk_buff* skb, __u32 offset, __u64 from, __u64 to,
-                                  __u64 flags) = (void*)BPF_FUNC_l4_csum_replace;
-
-static int (*bpf_l3_csum_replace)(struct __sk_buff* skb, __u32 offset, __u64 from, __u64 to,
-                                  __u64 flags) = (void*)BPF_FUNC_l3_csum_replace;
-
-static int (*bpf_skb_load_bytes)(struct __sk_buff *skb, int off, void *to, int len) = (void *) BPF_FUNC_skb_load_bytes;
-static int64_t (*bpf_csum_diff)(__be32 *from, __u32 from_size, __be32 *to, __u32 to_size, __wsum seed) = (void*) BPF_FUNC_csum_diff;
 static int (*bpf_sock_ops_cb_flags_set)(struct bpf_sock_ops *skops, int flags) = (void *) BPF_FUNC_sock_ops_cb_flags_set;
 static int (*bpf_reserve_hdr_opt)(struct bpf_sock_ops *skops, int space, int flags) = (void *) BPF_FUNC_reserve_hdr_opt;
 static int (*bpf_store_hdr_opt)(struct bpf_sock_ops *skops, void *from, int len, int flags) = (void *) BPF_FUNC_store_hdr_opt;
 
-// Android only supports little endian architectures
-#define htons(x) (__builtin_constant_p(x) ? ___constant_swab16(x) : __builtin_bswap16(x))
-#define htonl(x) (__builtin_constant_p(x) ? ___constant_swab32(x) : __builtin_bswap32(x))
-#define ntohs(x) htons(x)
-#define ntohl(x) htonl(x)
-
 static inline __attribute__((always_inline)) int
 find_accecn_options_offset(struct __sk_buff *skb, uint8_t offset) {
     int ret;
@@ -729,5 +699,3 @@
     }
     return TC_ACT_PIPE;
 }
-
-LICENSE("Apache 2.0");
diff --git a/bpf/progs/tcpAccECN.h b/bpf/progs/tcpAccECN.h
index ceb4a41..e927c6d 100644
--- a/bpf/progs/tcpAccECN.h
+++ b/bpf/progs/tcpAccECN.h
@@ -1,22 +1,13 @@
 #pragma once
 
-// This header file is shared by eBPF kernel programs (C) and netd (C++) and
-// some of the maps are also accessed directly from Java mainline module code.
-//
-// Hence: explicitly pad all relevant structures and assert that their size
-// is the sum of the sizes of their fields.
-#define STRUCT_SIZE(name, size) _Static_assert(sizeof(name) == (size), "Incorrect struct size.")
-
-#define SS_BPF_PATH "/sys/fs/bpf/"
-
-#define L4S_INGRESS_ETHER_PROG_PATH SS_BPF_PATH "prog_tcpAccECN_schedcls_ingress_l4s_accecn_eth"
-#define L4S_EGRESS_ETHER_PROG_PATH SS_BPF_PATH "prog_tcpAccECN_schedcls_egress_l4s_accecn_eth"
-#define L4S_INGRESS_RAWIP_PROG_PATH SS_BPF_PATH "prog_tcpAccECN_schedcls_ingress_l4s_accecn_rawip"
-#define L4S_EGRESS_RAWIP_PROG_PATH SS_BPF_PATH "prog_tcpAccECN_schedcls_egress_l4s_accecn_rawip"
-#define L4S_OPTIONS_SOCKOPS_PROG_PATH SS_BPF_PATH "prog_tcpAccECN_sockops_l4s_accecn_option"
-#define L4S_ACCECN_CE_MAP_PATH SS_BPF_PATH "map_tcpAccECN_l4s_accecn_ce_map"
-#define L4S_ACCECN_BYTE_MAP_PATH SS_BPF_PATH "map_tcpAccECN_l4s_accecn_byte_map"
-#define L4S_ACCECN_MSS_MAP_PATH SS_BPF_PATH "map_tcpAccECN_l4s_accecn_mss_map"
+#define L4S_INGRESS_ETHER_PROG_PATH   BPF_NETD_PATH "prog_tcpAccECN_schedcls_ingress_accecn_eth"
+#define L4S_EGRESS_ETHER_PROG_PATH    BPF_NETD_PATH "prog_tcpAccECN_schedcls_egress_accecn_eth"
+#define L4S_INGRESS_RAWIP_PROG_PATH   BPF_NETD_PATH "prog_tcpAccECN_schedcls_ingress_accecn_rawip"
+#define L4S_EGRESS_RAWIP_PROG_PATH    BPF_NETD_PATH "prog_tcpAccECN_schedcls_egress_accecn_rawip"
+#define L4S_OPTIONS_SOCKOPS_PROG_PATH BPF_NETD_PATH "prog_tcpAccECN_sockops_l4s_accecn_option"
+#define L4S_ACCECN_CE_MAP_PATH        BPF_NETD_PATH "map_tcpAccECN_l4s_accecn_ce_map"
+#define L4S_ACCECN_BYTE_MAP_PATH      BPF_NETD_PATH "map_tcpAccECN_l4s_accecn_byte_map"
+#define L4S_ACCECN_MSS_MAP_PATH       BPF_NETD_PATH "map_tcpAccECN_l4s_accecn_mss_map"
 
 typedef struct{
     uint64_t ceb;
diff --git a/bpf/tests/mts/bpf_existence_test.cpp b/bpf/tests/mts/bpf_existence_test.cpp
index 3a2d962..dc15e22 100644
--- a/bpf/tests/mts/bpf_existence_test.cpp
+++ b/bpf/tests/mts/bpf_existence_test.cpp
@@ -49,15 +49,6 @@
 class BpfExistenceTest : public ::testing::Test {
 };
 
-// Part of Android R platform (for 4.9+), but mainlined in S
-static const set<string> PLATFORM_ONLY_IN_R = {
-    PLATFORM "map_offload_tether_ingress_map",
-    PLATFORM "map_offload_tether_limit_map",
-    PLATFORM "map_offload_tether_stats_map",
-    PLATFORM "prog_offload_schedcls_ingress_tether_ether",
-    PLATFORM "prog_offload_schedcls_ingress_tether_rawip",
-};
-
 // Provided by *current* mainline module for S+ devices
 static const set<string> MAINLINE_FOR_S_PLUS = {
     TETHERING "map_kernel_bugs",
@@ -182,19 +173,14 @@
     set<string> mustExist;
     set<string> mustNotExist;
 
-    // We do not actually check the platform P/Q (netd) and Q (clatd) things
-    // and only verify the mainline module relevant R+ offload maps & progs.
+    // We only verify the mainline module relevant S+ offload maps & progs.
     //
     // The goal of this test is to verify compatibility with the tethering mainline module,
     // and not to test the platform itself, which may have been modified by vendor or oems,
     // so we should only test for the removal of stuff that was mainline'd,
     // and for the presence of mainline stuff.
 
-    // Note: Q is no longer supported by mainline
-    ASSERT_TRUE(isAtLeastR);
-
-    // R can potentially run on pre-4.9 kernel non-eBPF capable devices.
-    DO_EXPECT(isAtLeastR && !isAtLeastS && isAtLeastKernelVersion(4, 9, 0), PLATFORM_ONLY_IN_R);
+    ASSERT_TRUE(isAtLeastS);  // Q & R are no longer supported by mainline
 
     // S requires Linux Kernel 4.9+ and thus requires eBPF support.
     if (isAtLeastS) ASSERT_TRUE(isAtLeastKernelVersion(4, 9, 0));
diff --git a/service/src/com/android/metrics/SatelliteCoarseUsageMetricsCollector.java b/service/src/com/android/metrics/SatelliteCoarseUsageMetricsCollector.java
index 7e8e463..0dea382 100644
--- a/service/src/com/android/metrics/SatelliteCoarseUsageMetricsCollector.java
+++ b/service/src/com/android/metrics/SatelliteCoarseUsageMetricsCollector.java
@@ -299,12 +299,11 @@
     private void handleStartMonitoring() {
         // Note that in the constructor it is too early to get the managers.
         mCm = mContext.getSystemService(ConnectivityManager.class);
+        // Note: there is no need to call setPollOnOpen(true) to obtain accurate data. This class
+        // collects data usage only when processing the onLost callback, and ConnectivityService
+        // calls onLost only after it calls notifyIfacesChangedForNetworkStats, which forces a poll.
+        // Also, it is not safe to call setPollOnOpen(true) inside system server. b/427909947 .
         mNsm = mContext.getSystemService(NetworkStatsManager.class);
-        // Note: This might create heavy workload on NetworkStatsService if queried with high
-        // frequency, as the calling UID is system. Each query made with this manager
-        // updates usage stored in files before returning the newest result.
-        // This behavior is not rate-limited because the calling uid is the system UID.
-        mNsm.setPollOnOpen(true);
         // Get the first baseline.
         updateStartTimestamp();
         mSatelliteBaseline = mDeps.getSummary(mNsm, mStartTime);
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt
index 0b239b4..1211260 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt
@@ -16,6 +16,7 @@
 
 package com.android.testutils.com.android.testutils
 
+import com.android.testutils.tryTest
 import org.junit.rules.TestRule
 import org.junit.runner.Description
 import org.junit.runners.model.Statement
@@ -90,10 +91,12 @@
 
                 // Execute the test method, which includes methods annotated with
                 // @Before, @Test and @After.
-                base.evaluate()
-
-                valuesToBeRestored.forEach {
-                    setFlagsMethod(it.key, it.value)
+                tryTest {
+                    base.evaluate()
+                } cleanup {
+                    valuesToBeRestored.forEach {
+                        setFlagsMethod(it.key, it.value)
+                    }
                 }
             }
         }
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index 3b7d588..f795905 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -324,6 +324,12 @@
             val cb = events.poll(NO_CALLBACK_TIMEOUT_MS)
             assertNull(cb, "Expected no callback but got $cb")
         }
+
+        fun assumeNoCallback() {
+            val cb = events.poll(0 /* timeout */)
+            // Note that assumeNull does not exist.
+            assumeTrue(cb == null)
+        }
     }
 
     private class TetheredInterfaceListener : TetheredInterfaceCallback {
@@ -617,7 +623,7 @@
         // check is explicitly *not* using an interface state listener.
         // Since restricted interfaces cannot be used for tethering,
         // assumeNoInterfaceForTetheringAvailable() is an okay proxy.
-        assumeNoInterfaceForTetheringAvailable()
+        assumeNoUnrestrictedInterfacesAvailable()
 
         // If an interface exists when the callback is registered, it is reported on registration.
         val iface = createInterface()
@@ -680,6 +686,15 @@
         }
     }
 
+    private fun assumeNoUnrestrictedInterfacesAvailable() {
+        val listener = EthernetStateListener()
+        addInterfaceStateListener(listener)
+
+        // Force interface state listener callbacks to be processed before proceeding.
+        setEthernetEnabled(ethernetEnabled)
+        listener.assumeNoCallback()
+    }
+
     @Test
     fun testCallbacks_forServerModeInterfaces() {
         // do not run this test if an interface that can be used for tethering already exists.
diff --git a/tests/smoketest/Android.bp b/tests/smoketest/Android.bp
index 121efa1..0456c72 100644
--- a/tests/smoketest/Android.bp
+++ b/tests/smoketest/Android.bp
@@ -17,6 +17,7 @@
 
 android_test {
     name: "FrameworksNetSmokeTests",
+    min_sdk_version: "31",
     defaults: ["FrameworksNetTests-jni-defaults"],
     srcs: ["java/SmokeTest.java"],
     test_suites: ["device-tests"],
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 28d01c5..299d03e 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -147,6 +147,7 @@
 
 android_test {
     name: "FrameworksNetTests",
+    min_sdk_version: "31",
     enabled: enable_frameworks_net_tests,
     defaults: [
         "framework-connectivity-internal-test-defaults",