Merge changes Ic18521b6,Ibede8137

* changes:
  Move tag/untag socket BPF map access from JNI to Java
  Move struct CookieTagMap{Key, Value} to Connectivity/common
diff --git a/service-t/src/com/android/server/net/CookieTagMapKey.java b/common/src/com/android/net/module/util/bpf/CookieTagMapKey.java
similarity index 95%
rename from service-t/src/com/android/server/net/CookieTagMapKey.java
rename to common/src/com/android/net/module/util/bpf/CookieTagMapKey.java
index 443e5b3..17da7a0 100644
--- a/service-t/src/com/android/server/net/CookieTagMapKey.java
+++ b/common/src/com/android/net/module/util/bpf/CookieTagMapKey.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net;
+package com.android.net.module.util.bpf;
 
 import com.android.net.module.util.Struct;
 import com.android.net.module.util.Struct.Field;
diff --git a/service-t/src/com/android/server/net/CookieTagMapValue.java b/common/src/com/android/net/module/util/bpf/CookieTagMapValue.java
similarity index 95%
rename from service-t/src/com/android/server/net/CookieTagMapValue.java
rename to common/src/com/android/net/module/util/bpf/CookieTagMapValue.java
index 93b9195..e1a221f 100644
--- a/service-t/src/com/android/server/net/CookieTagMapValue.java
+++ b/common/src/com/android/net/module/util/bpf/CookieTagMapValue.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net;
+package com.android.net.module.util.bpf;
 
 import com.android.net.module.util.Struct;
 import com.android.net.module.util.Struct.Field;
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 8032303..77931b1 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -158,6 +158,8 @@
 import com.android.net.module.util.PermissionUtils;
 import com.android.net.module.util.Struct.U32;
 import com.android.net.module.util.Struct.U8;
+import com.android.net.module.util.bpf.CookieTagMapKey;
+import com.android.net.module.util.bpf.CookieTagMapValue;
 
 import java.io.File;
 import java.io.FileDescriptor;
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index e2c5a63..de0e20a 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -421,7 +421,7 @@
     stopClatdProcess(pid);
 }
 
-static jlong com_android_server_connectivity_ClatCoordinator_tagSocketAsClat(
+static jlong com_android_server_connectivity_ClatCoordinator_getSocketCookie(
         JNIEnv* env, jobject clazz, jobject sockJavaFd) {
     int sockFd = netjniutils::GetNativeFileDescriptor(env, sockJavaFd);
     if (sockFd < 0) {
@@ -435,58 +435,10 @@
         return -1;
     }
 
-    bpf::BpfMap<uint64_t, UidTagValue> cookieTagMap;
-    auto res = cookieTagMap.init(COOKIE_TAG_MAP_PATH);
-    if (!res.ok()) {
-        throwIOException(env, "failed to init the cookieTagMap", res.error().code());
-        return -1;
-    }
-
-    // Tag raw socket with uid AID_CLAT and set tag as zero because tag is unused in bpf
-    // program for counting data usage in netd.c. Tagging socket is used to avoid counting
-    // duplicated clat traffic in bpf stat.
-    UidTagValue newKey = {.uid = (uint32_t)AID_CLAT, .tag = 0 /* unused */};
-    res = cookieTagMap.writeValue(sock_cookie, newKey, BPF_ANY);
-    if (!res.ok()) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "Failed to tag the socket: %s, fd: %d",
-                             strerror(res.error().code()), cookieTagMap.getMap().get());
-        return -1;
-    }
-
-    ALOGI("tag uid AID_CLAT to socket fd %d, cookie %" PRIu64 "", sockFd, sock_cookie);
+    ALOGI("Get cookie %" PRIu64 " for socket fd %d", sock_cookie, sockFd);
     return static_cast<jlong>(sock_cookie);
 }
 
-static void com_android_server_connectivity_ClatCoordinator_untagSocket(JNIEnv* env, jobject clazz,
-                                                                        jlong cookie) {
-    uint64_t sock_cookie = static_cast<uint64_t>(cookie);
-    if (sock_cookie == bpf::NONEXISTENT_COOKIE) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "Invalid socket cookie");
-        return;
-    }
-
-    // The reason that deleting entry from cookie tag map directly is that the tag socket destroy
-    // listener only monitors on group INET_TCP, INET_UDP, INET6_TCP, INET6_UDP. The other socket
-    // types, ex: raw, are not able to be removed automatically by the listener.
-    // See TrafficController::makeSkDestroyListener.
-    bpf::BpfMap<uint64_t, UidTagValue> cookieTagMap;
-    auto res = cookieTagMap.init(COOKIE_TAG_MAP_PATH);
-    if (!res.ok()) {
-        throwIOException(env, "failed to init the cookieTagMap", res.error().code());
-        return;
-    }
-
-    res = cookieTagMap.deleteValue(sock_cookie);
-    if (!res.ok()) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "Failed to untag the socket: %s",
-                             strerror(res.error().code()));
-        return;
-    }
-
-    ALOGI("untag socket cookie %" PRIu64 "", sock_cookie);
-    return;
-}
-
 /*
  * JNI registration.
  */
@@ -516,10 +468,8 @@
         {"native_stopClatd",
          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V",
          (void*)com_android_server_connectivity_ClatCoordinator_stopClatd},
-        {"native_tagSocketAsClat", "(Ljava/io/FileDescriptor;)J",
-         (void*)com_android_server_connectivity_ClatCoordinator_tagSocketAsClat},
-        {"native_untagSocket", "(J)V",
-         (void*)com_android_server_connectivity_ClatCoordinator_untagSocket},
+        {"native_getSocketCookie", "(Ljava/io/FileDescriptor;)J",
+         (void*)com_android_server_connectivity_ClatCoordinator_getSocketCookie},
 };
 
 int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env) {
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index 5ea586a..6c4a021 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -46,6 +46,8 @@
 import com.android.net.module.util.bpf.ClatEgress4Value;
 import com.android.net.module.util.bpf.ClatIngress6Key;
 import com.android.net.module.util.bpf.ClatIngress6Value;
+import com.android.net.module.util.bpf.CookieTagMapKey;
+import com.android.net.module.util.bpf.CookieTagMapValue;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -63,6 +65,10 @@
 public class ClatCoordinator {
     private static final String TAG = ClatCoordinator.class.getSimpleName();
 
+    // Sync from system/core/libcutils/include/private/android_filesystem_config.h
+    @VisibleForTesting
+    static final int AID_CLAT = 1029;
+
     // Sync from external/android-clat/clatd.c
     // 40 bytes IPv6 header - 20 bytes IPv4 header + 8 bytes fragment header.
     @VisibleForTesting
@@ -97,6 +103,8 @@
     @VisibleForTesting
     static final int PRIO_CLAT = 4;
 
+    private static final String COOKIE_TAG_MAP_PATH =
+            "/sys/fs/bpf/netd_shared/map_netd_cookie_tag_map";
     private static final String CLAT_EGRESS4_MAP_PATH = makeMapPath("egress4");
     private static final String CLAT_INGRESS6_MAP_PATH = makeMapPath("ingress6");
 
@@ -121,6 +129,8 @@
     @Nullable
     private final IBpfMap<ClatEgress4Key, ClatEgress4Value> mEgressMap;
     @Nullable
+    private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap;
+    @Nullable
     private ClatdTracker mClatdTracker = null;
 
     /**
@@ -232,17 +242,10 @@
         }
 
         /**
-         * Tag socket as clat.
+         * Get socket cookie.
          */
-        public long tagSocketAsClat(@NonNull FileDescriptor sock) throws IOException {
-            return native_tagSocketAsClat(sock);
-        }
-
-        /**
-         * Untag socket.
-         */
-        public void untagSocket(long cookie) throws IOException {
-            native_untagSocket(cookie);
+        public long getSocketCookie(@NonNull FileDescriptor sock) throws IOException {
+            return native_getSocketCookie(sock);
         }
 
         /** Get ingress6 BPF map. */
@@ -279,6 +282,23 @@
             }
         }
 
+        /** Get cookie tag map */
+        @Nullable
+        public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
+            // Pre-T devices don't use ClatCoordinator to access clat map. Since Nat464Xlat
+            // initializes a ClatCoordinator object to avoid redundant null pointer check
+            // while using, ignore the BPF map initialization on pre-T devices.
+            // TODO: probably don't initialize ClatCoordinator object on pre-T devices.
+            if (!SdkLevel.isAtLeastT()) return null;
+            try {
+                return new BpfMap<>(COOKIE_TAG_MAP_PATH,
+                        BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class);
+            } catch (ErrnoException e) {
+                Log.wtf(TAG, "Cannot open cookie tag map: " + e);
+                return null;
+            }
+        }
+
         /** Checks if the network interface uses an ethernet L2 header. */
         public boolean isEthernet(String iface) throws IOException {
             return TcUtils.isEthernet(iface);
@@ -388,6 +408,7 @@
         mNetd = mDeps.getNetd();
         mIngressMap = mDeps.getBpfIngress6Map();
         mEgressMap = mDeps.getBpfEgress4Map();
+        mCookieTagMap = mDeps.getBpfCookieTagMap();
     }
 
     private void maybeStartBpf(final ClatdTracker tracker) {
@@ -536,6 +557,43 @@
         }
     }
 
+    private void tagSocketAsClat(long cookie) throws IOException {
+        if (mCookieTagMap == null) {
+            throw new IOException("Cookie tag map is not initialized");
+        }
+
+        // Tag raw socket with uid AID_CLAT and set tag as zero because tag is unused in bpf
+        // program for counting data usage in netd.c. Tagging socket is used to avoid counting
+        // duplicated clat traffic in bpf stat.
+        final CookieTagMapKey key = new CookieTagMapKey(cookie);
+        final CookieTagMapValue value = new CookieTagMapValue(AID_CLAT, 0 /* tag, unused */);
+        try {
+            mCookieTagMap.insertEntry(key, value);
+        } catch (ErrnoException | IllegalStateException e) {
+            throw new IOException("Could not insert entry (" + key + ", " + value
+                    + ") on cookie tag map: " + e);
+        }
+        Log.i(TAG, "tag socket cookie " + cookie);
+    }
+
+    private void untagSocket(long cookie) throws IOException {
+        if (mCookieTagMap == null) {
+            throw new IOException("Cookie tag map is not initialized");
+        }
+
+        // The reason that deleting entry from cookie tag map directly is that the tag socket
+        // destroy listener only monitors on group INET_TCP, INET_UDP, INET6_TCP, INET6_UDP.
+        // The other socket types, ex: raw, are not able to be removed automatically by the
+        // listener. See TrafficController::makeSkDestroyListener.
+        final CookieTagMapKey key = new CookieTagMapKey(cookie);
+        try {
+            mCookieTagMap.deleteEntry(key);
+        } catch (ErrnoException | IllegalStateException e) {
+            throw new IOException("Could not delete entry (" + key + ") on cookie tag map: " + e);
+        }
+        Log.i(TAG, "untag socket cookie " + cookie);
+    }
+
     /**
      * Start clatd for a given interface and NAT64 prefix.
      */
@@ -686,7 +744,8 @@
         // Tag socket as AID_CLAT to avoid duplicated CLAT data usage accounting.
         final long cookie;
         try {
-            cookie = mDeps.tagSocketAsClat(writeSock6.getFileDescriptor());
+            cookie = mDeps.getSocketCookie(writeSock6.getFileDescriptor());
+            tagSocketAsClat(cookie);
         } catch (IOException e) {
             maybeCleanUp(tunFd, readSock6, writeSock6);
             throw new IOException("tag raw socket failed: " + e);
@@ -696,6 +755,11 @@
         try {
             mDeps.configurePacketSocket(readSock6.getFileDescriptor(), v6Str, ifIndex);
         } catch (IOException e) {
+            try {
+                untagSocket(cookie);
+            } catch (IOException e2) {
+                Log.e(TAG, "untagSocket cookie " + cookie + " failed: " + e2);
+            }
             maybeCleanUp(tunFd, readSock6, writeSock6);
             throw new IOException("configure packet socket failed: " + e);
         }
@@ -706,8 +770,11 @@
             pid = mDeps.startClatd(tunFd.getFileDescriptor(), readSock6.getFileDescriptor(),
                     writeSock6.getFileDescriptor(), iface, pfx96Str, v4Str, v6Str);
         } catch (IOException e) {
-            // TODO: probably refactor to handle the exception of #untagSocket if any.
-            mDeps.untagSocket(cookie);
+            try {
+                untagSocket(cookie);
+            } catch (IOException e2) {
+                Log.e(TAG, "untagSocket cookie " + cookie + " failed: " + e2);
+            }
             throw new IOException("Error start clatd on " + iface + ": " + e);
         } finally {
             // The file descriptors have been duplicated (dup2) to clatd in native_startClatd().
@@ -774,7 +841,7 @@
         mDeps.stopClatd(mClatdTracker.iface, mClatdTracker.pfx96.getHostAddress(),
                 mClatdTracker.v4.getHostAddress(), mClatdTracker.v6.getHostAddress(),
                 mClatdTracker.pid);
-        mDeps.untagSocket(mClatdTracker.cookie);
+        untagSocket(mClatdTracker.cookie);
 
         Log.i(TAG, "clatd on " + mClatdTracker.iface + " stopped");
         mClatdTracker = null;
@@ -870,6 +937,5 @@
             throws IOException;
     private static native void native_stopClatd(String iface, String pfx96, String v4, String v6,
             int pid) throws IOException;
-    private static native long native_tagSocketAsClat(FileDescriptor sock) throws IOException;
-    private static native void native_untagSocket(long cookie) throws IOException;
+    private static native long native_getSocketCookie(FileDescriptor sock) throws IOException;
 }
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index feee293..bbb61cd 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -21,6 +21,7 @@
 import static android.system.OsConstants.ETH_P_IPV6;
 
 import static com.android.net.module.util.NetworkStackConstants.ETHER_MTU;
+import static com.android.server.connectivity.ClatCoordinator.AID_CLAT;
 import static com.android.server.connectivity.ClatCoordinator.CLAT_MAX_MTU;
 import static com.android.server.connectivity.ClatCoordinator.EGRESS;
 import static com.android.server.connectivity.ClatCoordinator.INGRESS;
@@ -56,6 +57,8 @@
 import com.android.net.module.util.bpf.ClatEgress4Value;
 import com.android.net.module.util.bpf.ClatIngress6Key;
 import com.android.net.module.util.bpf.ClatIngress6Value;
+import com.android.net.module.util.bpf.CookieTagMapKey;
+import com.android.net.module.util.bpf.CookieTagMapValue;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
 import com.android.testutils.TestBpfMap;
@@ -127,11 +130,16 @@
             INET6_PFX96, INET6_LOCAL6);
     private static final ClatIngress6Value INGRESS_VALUE = new ClatIngress6Value(STACKED_IFINDEX,
             INET4_LOCAL4);
+    private static final CookieTagMapKey COOKIE_TAG_KEY = new CookieTagMapKey(RAW_SOCK_COOKIE);
+    private static final CookieTagMapValue COOKIE_TAG_VALUE = new CookieTagMapValue(AID_CLAT,
+            0 /* tag, unused */);
 
     private final TestBpfMap<ClatIngress6Key, ClatIngress6Value> mIngressMap =
             spy(new TestBpfMap<>(ClatIngress6Key.class, ClatIngress6Value.class));
     private final TestBpfMap<ClatEgress4Key, ClatEgress4Value> mEgressMap =
             spy(new TestBpfMap<>(ClatEgress4Key.class, ClatEgress4Value.class));
+    private final TestBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap =
+            spy(new TestBpfMap<>(CookieTagMapKey.class, CookieTagMapValue.class));
 
     @Mock private INetd mNetd;
     @Spy private TestDependencies mDeps = new TestDependencies();
@@ -313,25 +321,10 @@
         }
 
         /**
-         * Tag socket as clat.
+         * Get socket cookie.
          */
-        @Override
-        public long tagSocketAsClat(@NonNull FileDescriptor sock) throws IOException {
-            if (Objects.equals(RAW_SOCK_PFD.getFileDescriptor(), sock)) {
-                return RAW_SOCK_COOKIE;
-            }
-            fail("unsupported arg: " + sock);
-            return 0;
-        }
-
-        /**
-         * Untag socket.
-         */
-        @Override
-        public void untagSocket(long cookie) throws IOException {
-            if (cookie != RAW_SOCK_COOKIE) {
-                fail("unsupported arg: " + cookie);
-            }
+        public long getSocketCookie(@NonNull FileDescriptor sock) throws IOException {
+            return RAW_SOCK_COOKIE;
         }
 
         /** Get ingress6 BPF map. */
@@ -346,6 +339,12 @@
             return mEgressMap;
         }
 
+        /** Get cookie tag map */
+        @Override
+        public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
+            return mCookieTagMap;
+        }
+
         /** Checks if the network interface uses an ethernet L2 header. */
         public boolean isEthernet(String iface) throws IOException {
             if (BASE_IFACE.equals(iface)) return true;
@@ -400,8 +399,8 @@
     @Test
     public void testStartStopClatd() throws Exception {
         final ClatCoordinator coordinator = makeClatCoordinator();
-        final InOrder inOrder = inOrder(mNetd, mDeps, mIngressMap, mEgressMap);
-        clearInvocations(mNetd, mDeps, mIngressMap, mEgressMap);
+        final InOrder inOrder = inOrder(mNetd, mDeps, mIngressMap, mEgressMap, mCookieTagMap);
+        clearInvocations(mNetd, mDeps, mIngressMap, mEgressMap, mCookieTagMap);
 
         // [1] Start clatd.
         final String addr6For464xlat = coordinator.clatStart(BASE_IFACE, NETID, NAT64_IP_PREFIX);
@@ -444,8 +443,9 @@
         inOrder.verify(mDeps).addAnycastSetsockopt(
                 argThat(fd -> Objects.equals(RAW_SOCK_PFD.getFileDescriptor(), fd)),
                 eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(BASE_IFINDEX));
-        inOrder.verify(mDeps).tagSocketAsClat(
+        inOrder.verify(mDeps).getSocketCookie(
                 argThat(fd -> Objects.equals(RAW_SOCK_PFD.getFileDescriptor(), fd)));
+        inOrder.verify(mCookieTagMap).insertEntry(eq(COOKIE_TAG_KEY), eq(COOKIE_TAG_VALUE));
         inOrder.verify(mDeps).configurePacketSocket(
                 argThat(fd -> Objects.equals(PACKET_SOCK_PFD.getFileDescriptor(), fd)),
                 eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(BASE_IFINDEX));
@@ -481,7 +481,7 @@
         inOrder.verify(mIngressMap).deleteEntry(eq(INGRESS_KEY));
         inOrder.verify(mDeps).stopClatd(eq(BASE_IFACE), eq(NAT64_PREFIX_STRING),
                 eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(CLATD_PID));
-        inOrder.verify(mDeps).untagSocket(eq(RAW_SOCK_COOKIE));
+        inOrder.verify(mCookieTagMap).deleteEntry(eq(COOKIE_TAG_KEY));
         assertNull(coordinator.getClatdTrackerForTesting());
         inOrder.verifyNoMoreInteractions();
 
@@ -680,18 +680,6 @@
     }
 
     @Test
-    public void testNotStartClatWithNativeFailureTagSocketAsClat() throws Exception {
-        class FailureDependencies extends TestDependencies {
-            @Override
-            public long tagSocketAsClat(@NonNull FileDescriptor sock) throws IOException {
-                throw new IOException();
-            }
-        }
-        checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
-                true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
-    }
-
-    @Test
     public void testNotStartClatWithNativeFailureConfigurePacketSocket() throws Exception {
         class FailureDependencies extends TestDependencies {
             @Override
@@ -718,4 +706,28 @@
         checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
                 true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
     }
+
+    @Test
+    public void testNotStartClatWithNativeFailureGetSocketCookie() throws Exception {
+        class FailureDependencies extends TestDependencies {
+            @Override
+            public long getSocketCookie(@NonNull FileDescriptor sock) throws IOException {
+                throw new IOException();
+            }
+        }
+        checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+                true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
+    }
+
+    @Test
+    public void testNotStartClatWithNullCookieTagMap() throws Exception {
+        class FailureDependencies extends TestDependencies {
+            @Override
+            public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
+                return null;
+            }
+        }
+        checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+                true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
+    }
 }
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 1a5620b..484d717 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -133,6 +133,8 @@
 import com.android.net.module.util.LocationPermissionChecker;
 import com.android.net.module.util.Struct.U32;
 import com.android.net.module.util.Struct.U8;
+import com.android.net.module.util.bpf.CookieTagMapKey;
+import com.android.net.module.util.bpf.CookieTagMapValue;
 import com.android.server.net.NetworkStatsService.AlertObserver;
 import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
 import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;