Merge "ethernet: replace netd link observer with NetlinkMonitor"
diff --git a/bpf_progs/bpf_tethering.h b/bpf_progs/bpf_tethering.h
index f9ef6ef..9dae6c9 100644
--- a/bpf_progs/bpf_tethering.h
+++ b/bpf_progs/bpf_tethering.h
@@ -26,31 +26,33 @@
 // - The BPF programs in Tethering/bpf_progs/
 // - JNI code that depends on the bpf_connectivity_headers library.
 
-#define BPF_TETHER_ERRORS    \
-    ERR(INVALID_IP_VERSION)  \
-    ERR(LOW_TTL)             \
-    ERR(INVALID_TCP_HEADER)  \
-    ERR(TCP_CONTROL_PACKET)  \
-    ERR(NON_GLOBAL_SRC)      \
-    ERR(NON_GLOBAL_DST)      \
-    ERR(LOCAL_SRC_DST)       \
-    ERR(NO_STATS_ENTRY)      \
-    ERR(NO_LIMIT_ENTRY)      \
-    ERR(BELOW_IPV4_MTU)      \
-    ERR(BELOW_IPV6_MTU)      \
-    ERR(LIMIT_REACHED)       \
-    ERR(CHANGE_HEAD_FAILED)  \
-    ERR(TOO_SHORT)           \
-    ERR(HAS_IP_OPTIONS)      \
-    ERR(IS_IP_FRAG)          \
-    ERR(CHECKSUM)            \
-    ERR(NON_TCP_UDP)         \
-    ERR(NON_TCP)             \
-    ERR(SHORT_L4_HEADER)     \
-    ERR(SHORT_TCP_HEADER)    \
-    ERR(SHORT_UDP_HEADER)    \
-    ERR(UDP_CSUM_ZERO)       \
-    ERR(TRUNCATED_IPV4)      \
+#define BPF_TETHER_ERRORS     \
+    ERR(INVALID_IPV4_VERSION) \
+    ERR(INVALID_IPV6_VERSION) \
+    ERR(LOW_TTL)              \
+    ERR(INVALID_TCP_HEADER)   \
+    ERR(TCPV4_CONTROL_PACKET) \
+    ERR(TCPV6_CONTROL_PACKET) \
+    ERR(NON_GLOBAL_SRC)       \
+    ERR(NON_GLOBAL_DST)       \
+    ERR(LOCAL_SRC_DST)        \
+    ERR(NO_STATS_ENTRY)       \
+    ERR(NO_LIMIT_ENTRY)       \
+    ERR(BELOW_IPV4_MTU)       \
+    ERR(BELOW_IPV6_MTU)       \
+    ERR(LIMIT_REACHED)        \
+    ERR(CHANGE_HEAD_FAILED)   \
+    ERR(TOO_SHORT)            \
+    ERR(HAS_IP_OPTIONS)       \
+    ERR(IS_IP_FRAG)           \
+    ERR(CHECKSUM)             \
+    ERR(NON_TCP_UDP)          \
+    ERR(NON_TCP)              \
+    ERR(SHORT_L4_HEADER)      \
+    ERR(SHORT_TCP_HEADER)     \
+    ERR(SHORT_UDP_HEADER)     \
+    ERR(UDP_CSUM_ZERO)        \
+    ERR(TRUNCATED_IPV4)       \
     ERR(_MAX)
 
 #define ERR(x) BPF_TETHER_ERR_ ##x,
diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c
index 898f2e2..bb9fc34 100644
--- a/bpf_progs/offload.c
+++ b/bpf_progs/offload.c
@@ -155,7 +155,7 @@
     if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_PIPE;
 
     // IP version must be 6
-    if (ip6->version != 6) TC_PUNT(INVALID_IP_VERSION);
+    if (ip6->version != 6) TC_PUNT(INVALID_IPV6_VERSION);
 
     // Cannot decrement during forward if already zero or would be zero,
     // Let the kernel's stack handle these cases and generate appropriate ICMP errors.
@@ -171,7 +171,7 @@
             TC_PUNT(INVALID_TCP_HEADER);
 
         // Do not offload TCP packets with any one of the SYN/FIN/RST flags
-        if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCP_CONTROL_PACKET);
+        if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCPV6_CONTROL_PACKET);
     }
 
     // Protect against forwarding packets sourced from ::1 or fe80::/64 or other weirdness.
@@ -370,7 +370,7 @@
 
         // If hardware offload is running and programming flows based on conntrack entries, try not
         // to interfere with it, so do not offload TCP packets with any one of the SYN/FIN/RST flags
-        if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCP_CONTROL_PACKET);
+        if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCPV4_CONTROL_PACKET);
     } else { // UDP
         // Make sure we can get at the udp header
         if (data + l2_header_size + sizeof(*ip) + sizeof(*udph) > data_end)
@@ -576,7 +576,7 @@
     if (is_ethernet && (eth->h_proto != htons(ETH_P_IP))) return TC_ACT_PIPE;
 
     // IP version must be 4
-    if (ip->version != 4) TC_PUNT(INVALID_IP_VERSION);
+    if (ip->version != 4) TC_PUNT(INVALID_IPV4_VERSION);
 
     // We cannot handle IP options, just standard 20 byte == 5 dword minimal IPv4 header
     if (ip->ihl != 5) TC_PUNT(HAS_IP_OPTIONS);
diff --git a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
index 8b6526f..a3299a7 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
@@ -93,118 +93,6 @@
     return env->NewLongArray(size);
 }
 
-static int legacyReadNetworkStatsDetail(std::vector<stats_line>* lines,
-                                        const std::vector<std::string>& limitIfaces,
-                                        int limitTag, int limitUid, const char* path) {
-    FILE* fp = fopen(path, "re");
-    if (fp == NULL) {
-        return -1;
-    }
-
-    int lastIdx = 1;
-    int idx;
-    char buffer[384];
-    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
-        stats_line s;
-        int64_t rawTag;
-        char* pos = buffer;
-        char* endPos;
-        // First field is the index.
-        idx = (int)strtol(pos, &endPos, 10);
-        //ALOGI("Index #%d: %s", idx, buffer);
-        if (pos == endPos) {
-            // Skip lines that don't start with in index.  In particular,
-            // this will skip the initial header line.
-            continue;
-        }
-        if (idx != lastIdx + 1) {
-            ALOGE("inconsistent idx=%d after lastIdx=%d: %s", idx, lastIdx, buffer);
-            fclose(fp);
-            return -1;
-        }
-        lastIdx = idx;
-        pos = endPos;
-        // Skip whitespace.
-        while (*pos == ' ') {
-            pos++;
-        }
-        // Next field is iface.
-        int ifaceIdx = 0;
-        while (*pos != ' ' && *pos != 0 && ifaceIdx < (int)(sizeof(s.iface)-1)) {
-            s.iface[ifaceIdx] = *pos;
-            ifaceIdx++;
-            pos++;
-        }
-        if (*pos != ' ') {
-            ALOGE("bad iface: %s", buffer);
-            fclose(fp);
-            return -1;
-        }
-        s.iface[ifaceIdx] = 0;
-        if (limitIfaces.size() > 0) {
-            // Is this an iface the caller is interested in?
-            int i = 0;
-            while (i < (int)limitIfaces.size()) {
-                if (limitIfaces[i] == s.iface) {
-                    break;
-                }
-                i++;
-            }
-            if (i >= (int)limitIfaces.size()) {
-                // Nothing matched; skip this line.
-                //ALOGI("skipping due to iface: %s", buffer);
-                continue;
-            }
-        }
-
-        // Ignore whitespace
-        while (*pos == ' ') pos++;
-
-        // Find end of tag field
-        endPos = pos;
-        while (*endPos != ' ') endPos++;
-
-        // Three digit field is always 0x0, otherwise parse
-        if (endPos - pos == 3) {
-            rawTag = 0;
-        } else {
-            if (sscanf(pos, "%" PRIx64, &rawTag) != 1) {
-                ALOGE("bad tag: %s", pos);
-                fclose(fp);
-                return -1;
-            }
-        }
-        s.tag = rawTag >> 32;
-        if (limitTag != -1 && s.tag != static_cast<uint32_t>(limitTag)) {
-            //ALOGI("skipping due to tag: %s", buffer);
-            continue;
-        }
-        pos = endPos;
-
-        // Ignore whitespace
-        while (*pos == ' ') pos++;
-
-        // Parse remaining fields.
-        if (sscanf(pos, "%u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64,
-                &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
-                &s.txBytes, &s.txPackets) == 6) {
-            if (limitUid != -1 && static_cast<uint32_t>(limitUid) != s.uid) {
-                //ALOGI("skipping due to uid: %s", buffer);
-                continue;
-            }
-            lines->push_back(s);
-        } else {
-            //ALOGI("skipping due to bad remaining fields: %s", pos);
-        }
-    }
-
-    if (fclose(fp) != 0) {
-        ALOGE("Failed to close netstats file");
-        return -1;
-    }
-    return 0;
-}
-
 static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats,
                             std::vector<stats_line>& lines) {
     int size = lines.size();
@@ -282,9 +170,8 @@
     return 0;
 }
 
-static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
-                                  jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
-                                  jboolean useBpfStats) {
+static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jint limitUid,
+        jobjectArray limitIfacesObj, jint limitTag) {
 
     std::vector<std::string> limitIfaces;
     if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
@@ -299,20 +186,8 @@
     }
     std::vector<stats_line> lines;
 
-
-    if (useBpfStats) {
-        if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
-            return -1;
-    } else {
-        ScopedUtfChars path8(env, path);
-        if (path8.c_str() == NULL) {
-            ALOGE("the qtaguid legacy path is invalid: %s", path8.c_str());
-            return -1;
-        }
-        if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
-                                         limitUid, path8.c_str()) < 0)
-            return -1;
-    }
+    if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
+        return -1;
 
     return statsLinesToNetworkStats(env, clazz, stats, lines);
 }
@@ -328,7 +203,7 @@
 
 static const JNINativeMethod gMethods[] = {
         { "nativeReadNetworkStatsDetail",
-                "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I",
+                "(Landroid/net/NetworkStats;I[Ljava/lang/String;I)I",
                 (void*) readNetworkStatsDetail },
         { "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I",
                 (void*) readNetworkStatsDev },
diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java
index 4a6741c..c9d1718 100644
--- a/service-t/src/com/android/server/net/NetworkStatsFactory.java
+++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java
@@ -91,8 +91,7 @@
             final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
             // TODO: remove both path and useBpfStats arguments.
             // The path is never used if useBpfStats is true.
-            final int ret = nativeReadNetworkStatsDetail(stats, null /* path */,
-                    limitUid, limitIfaces, limitTag, true /* useBpfStats */);
+            final int ret = nativeReadNetworkStatsDetail(stats, limitUid, limitIfaces, limitTag);
             if (ret != 0) {
                 throw new IOException("Failed to parse network stats");
             }
@@ -334,8 +333,8 @@
      * are expected to monotonically increase since device boot.
      */
     @VisibleForTesting
-    public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path,
-        int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats);
+    public static native int nativeReadNetworkStatsDetail(NetworkStats stats, int limitUid,
+            String[] limitIfaces, int limitTag);
 
     @VisibleForTesting
     public static native int nativeReadNetworkStatsDev(NetworkStats stats);
diff --git a/service/Android.bp b/service/Android.bp
index 1e70d68..b68d389 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -143,8 +143,6 @@
         "src/**/*.java",
         ":framework-connectivity-shared-srcs",
         ":services-connectivity-shared-srcs",
-        // TODO: move to net-utils-device-common
-        ":connectivity-module-utils-srcs",
     ],
     libs: [
         "framework-annotations-lib",
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index 303112f..a26d1e6 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -572,17 +572,6 @@
     }
 }
 
-std::string getProgramStatus(const char *path) {
-    int ret = access(path, R_OK);
-    if (ret == 0) {
-        return StringPrintf("OK");
-    }
-    if (ret != 0 && errno == ENOENT) {
-        return StringPrintf("program is missing at: %s", path);
-    }
-    return StringPrintf("check Program %s error: %s", path, strerror(errno));
-}
-
 std::string getMapStatus(const base::unique_fd& map_fd, const char* path) {
     if (map_fd.get() < 0) {
         return StringPrintf("map fd lost");
@@ -614,6 +603,10 @@
     dw.blankline();
     dw.println("mCookieTagMap status: %s",
                getMapStatus(mCookieTagMap.getMap(), COOKIE_TAG_MAP_PATH).c_str());
+    dw.println("mUidCounterSetMap status: %s",
+               getMapStatus(mUidCounterSetMap.getMap(), UID_COUNTERSET_MAP_PATH).c_str());
+    dw.println("mAppUidStatsMap status: %s",
+               getMapStatus(mAppUidStatsMap.getMap(), APP_UID_STATS_MAP_PATH).c_str());
     dw.println("mStatsMapA status: %s",
                getMapStatus(mStatsMapA.getMap(), STATS_MAP_A_PATH).c_str());
     dw.println("mStatsMapB status: %s",
@@ -627,19 +620,6 @@
     dw.println("mUidOwnerMap status: %s",
                getMapStatus(mUidOwnerMap.getMap(), UID_OWNER_MAP_PATH).c_str());
 
-    dw.blankline();
-    dw.println("Cgroup ingress program status: %s",
-               getProgramStatus(BPF_INGRESS_PROG_PATH).c_str());
-    dw.println("Cgroup egress program status: %s", getProgramStatus(BPF_EGRESS_PROG_PATH).c_str());
-    dw.println("xt_bpf ingress program status: %s",
-               getProgramStatus(XT_BPF_INGRESS_PROG_PATH).c_str());
-    dw.println("xt_bpf egress program status: %s",
-               getProgramStatus(XT_BPF_EGRESS_PROG_PATH).c_str());
-    dw.println("xt_bpf bandwidth allowlist program status: %s",
-               getProgramStatus(XT_BPF_ALLOWLIST_PROG_PATH).c_str());
-    dw.println("xt_bpf bandwidth denylist program status: %s",
-               getProgramStatus(XT_BPF_DENYLIST_PROG_PATH).c_str());
-
     if (!verbose) {
         return;
     }
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 0ca0d83..1caca01 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -89,7 +89,6 @@
 import static android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY;
-import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
 import static android.os.Process.INVALID_UID;
 import static android.os.Process.VPN_UID;
 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
@@ -98,6 +97,7 @@
 import static android.system.OsConstants.IPPROTO_UDP;
 
 import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
+import static com.android.net.module.util.NetworkMonitorUtils.isPrivateDnsValidationRequired;
 import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf;
 import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission;
 import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr;
@@ -1220,16 +1220,7 @@
         public void incrementCountOrThrow(final int uid) {
             synchronized (mUidToNetworkRequestCount) {
                 final int newRequestCount = mUidToNetworkRequestCount.get(uid, 0) + 1;
-                if (newRequestCount >= mMaxCountPerUid
-                        // HACK : the system server is allowed to go over the request count limit
-                        // when it is creating requests on behalf of another app (but not itself,
-                        // so it can still detect its own request leaks). This only happens in the
-                        // per-app API flows in which case the old requests for that particular
-                        // UID will be removed soon.
-                        // TODO : with the removal of the legacy transact() method, exempting the
-                        // system server UID should no longer be necessary. Make sure this is the
-                        // case and remove this test.
-                        && (Process.myUid() == uid || Process.myUid() != Binder.getCallingUid())) {
+                if (newRequestCount >= mMaxCountPerUid) {
                     throw new ServiceSpecificException(
                             ConnectivityManager.Errors.TOO_MANY_REQUESTS,
                             "Uid " + uid + " exceeded its allotted requests limit");
@@ -10856,6 +10847,7 @@
         removeDefaultNetworkRequestsForPreference(PREFERENCE_ORDER_PROFILE);
         addPerAppDefaultNetworkRequests(
                 createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences));
+
         // Finally, rematch.
         rematchAllNetworksAndRequests();
 
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 06f7300..f8e70c4 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -300,7 +300,6 @@
 import android.net.networkstack.NetworkStackClientBase;
 import android.net.resolv.aidl.Nat64PrefixEventParcel;
 import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
-import android.net.shared.NetworkMonitorUtils;
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.wifi.WifiInfo;
@@ -356,6 +355,7 @@
 import com.android.net.module.util.ArrayTrackRecord;
 import com.android.net.module.util.CollectionUtils;
 import com.android.net.module.util.LocationPermissionChecker;
+import com.android.net.module.util.NetworkMonitorUtils;
 import com.android.networkstack.apishim.NetworkAgentConfigShimImpl;
 import com.android.networkstack.apishim.api29.ConstantsShim;
 import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
@@ -2989,8 +2989,7 @@
 
     @Test
     public void testRequiresValidation() {
-        assertTrue(NetworkMonitorUtils.isValidationRequired(
-                NetworkAgentConfigShimImpl.newInstance(null),
+        assertTrue(NetworkMonitorUtils.isValidationRequired(false /* isVpnValidationRequired */,
                 mCm.getDefaultRequest().networkCapabilities));
     }
 
@@ -7980,7 +7979,8 @@
         // VPN networks do not satisfy the default request and are automatically validated
         // by NetworkMonitor
         assertFalse(NetworkMonitorUtils.isValidationRequired(
-                NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig()),
+                NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig())
+                        .isVpnValidationRequired(),
                 mMockVpn.getAgent().getNetworkCapabilities()));
         mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
 
@@ -8131,7 +8131,8 @@
         assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
 
         assertFalse(NetworkMonitorUtils.isValidationRequired(
-                NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig()),
+                NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig())
+                        .isVpnValidationRequired(),
                 mMockVpn.getAgent().getNetworkCapabilities()));
         assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired(
                 mMockVpn.getAgent().getNetworkCapabilities()));