Move uidPermissionMap dump to BpfNetMaps

Also remove the dump of mPrivilegedUser because this is not used now and
the information is duplicated with uidPermissionMap dump.

Before this CL
....
mUidPermissionMap:
10049 PERMISSION_NONE
10027  BPF_PERMISSION_INTERNET BPF_PERMISSION_UPDATE_DEVICE_STATS
1041  BPF_PERMISSION_UPDATE_DEVICE_STATS
....

After this CL
....
sUidPermissionMap:
  10049 PERMISSION_NONE
  10027 PERMISSION_INTERNET PERMISSION_UPDATE_DEVICE_STATS
  1041 PERMISSION_UPDATE_DEVICE_STATS
....

Bug: 217624062
Test: dumpsys connectivity trafficcontroller, atest BpfNetMapsTest
Change-Id: I416501d5a28a5443f954f9c8c58ea255e5cdc897
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index 49b23c9..81ddd5a 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -717,21 +717,6 @@
     if (!res.ok()) {
         dw.println("mUidOwnerMap print end with error: %s", res.error().message().c_str());
     }
-    dumpBpfMap("mUidPermissionMap", dw, "");
-    const auto printUidPermissionInfo = [&dw](const uint32_t& key, const int& value,
-                                              const BpfMap<uint32_t, uint8_t>&) {
-        dw.println("%u %s", key, UidPermissionTypeToString(value).c_str());
-        return base::Result<void>();
-    };
-    res = mUidPermissionMap.iterateWithValue(printUidPermissionInfo);
-    if (!res.ok()) {
-        dw.println("mUidPermissionMap print end with error: %s", res.error().message().c_str());
-    }
-
-    dumpBpfMap("mPrivilegedUser", dw, "");
-    for (uid_t uid : mPrivilegedUser) {
-        dw.println("%u ALLOW_UPDATE_DEVICE_STATS", (uint32_t)uid);
-    }
 }
 
 }  // namespace net
diff --git a/service/native/TrafficControllerTest.cpp b/service/native/TrafficControllerTest.cpp
index 8525738..a9b4538 100644
--- a/service/native/TrafficControllerTest.cpp
+++ b/service/native/TrafficControllerTest.cpp
@@ -798,11 +798,6 @@
     expectedLines.emplace_back("mUidOwnerMap:");
     expectedLines.emplace_back(fmt::format("{}  HAPPY_BOX_MATCH", TEST_UID));
 
-    mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, {TEST_UID2});
-    expectedLines.emplace_back("mUidPermissionMap:");
-    expectedLines.emplace_back(fmt::format("{}  BPF_PERMISSION_UPDATE_DEVICE_STATS", TEST_UID2));
-    expectedLines.emplace_back("mPrivilegedUser:");
-    expectedLines.emplace_back(fmt::format("{} ALLOW_UPDATE_DEVICE_STATS", TEST_UID2));
     EXPECT_TRUE(expectDumpsysContains(expectedLines));
 }
 
@@ -821,8 +816,7 @@
         fmt::format("mIfaceStatsMap {}", kErrIterate),
         fmt::format("mConfigurationMap {}", kErrReadRulesConfig),
         fmt::format("mConfigurationMap {}", kErrReadStatsMapConfig),
-        fmt::format("mUidOwnerMap {}", kErrIterate),
-        fmt::format("mUidPermissionMap {}", kErrIterate)};
+        fmt::format("mUidOwnerMap {}", kErrIterate)};
     EXPECT_TRUE(expectDumpsysContains(expectedLines));
 }
 
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index dbfc383..0015da2 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -27,7 +27,9 @@
 import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
 import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
 import static android.net.INetd.PERMISSION_INTERNET;
+import static android.net.INetd.PERMISSION_NONE;
 import static android.net.INetd.PERMISSION_UNINSTALLED;
+import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
 import static android.system.OsConstants.EINVAL;
 import static android.system.OsConstants.ENODEV;
 import static android.system.OsConstants.ENOENT;
@@ -44,12 +46,15 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
+import android.util.Pair;
 import android.util.StatsEvent;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.modules.utils.BackgroundThread;
 import com.android.modules.utils.build.SdkLevel;
+import com.android.net.module.util.BpfDump;
 import com.android.net.module.util.BpfMap;
 import com.android.net.module.util.DeviceConfigUtils;
 import com.android.net.module.util.IBpfMap;
@@ -62,8 +67,10 @@
 
 import java.io.FileDescriptor;
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.StringJoiner;
 
 /**
  * BpfNetMaps is responsible for providing traffic controller relevant functionality.
@@ -134,6 +141,11 @@
     @VisibleForTesting public static final long OEM_DENY_3_MATCH = (1 << 11);
     // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/bpf_shared.h)
 
+    private static final List<Pair<Integer, String>> PERMISSION_LIST = Arrays.asList(
+            Pair.create(PERMISSION_INTERNET, "PERMISSION_INTERNET"),
+            Pair.create(PERMISSION_UPDATE_DEVICE_STATS, "PERMISSION_UPDATE_DEVICE_STATS")
+    );
+
     /**
      * Set sEnableJavaBpfMap for test.
      */
@@ -914,14 +926,40 @@
         return StatsManager.PULL_SUCCESS;
     }
 
+    private String permissionToString(int permissionMask) {
+        if (permissionMask == PERMISSION_NONE) {
+            return "PERMISSION_NONE";
+        }
+        if (permissionMask == PERMISSION_UNINSTALLED) {
+            // PERMISSION_UNINSTALLED should never appear in the map
+            return "PERMISSION_UNINSTALLED error!";
+        }
+
+        final StringJoiner sj = new StringJoiner(" ");
+        for (Pair<Integer, String> permission: PERMISSION_LIST) {
+            final int permissionFlag = permission.first;
+            final String permissionName = permission.second;
+            if ((permissionMask & permissionFlag) != 0) {
+                sj.add(permissionName);
+                permissionMask &= ~permissionFlag;
+            }
+        }
+        if (permissionMask != 0) {
+            sj.add("PERMISSION_UNKNOWN(" + permissionMask + ")");
+        }
+        return sj.toString();
+    }
+
     /**
      * Dump BPF maps
      *
+     * @param pw print writer
      * @param fd file descriptor to output
+     * @param verbose verbose dump flag, if true dump the BpfMap contents
      * @throws IOException when file descriptor is invalid.
      * @throws ServiceSpecificException when the method is called on an unsupported device.
      */
-    public void dump(final FileDescriptor fd, boolean verbose)
+    public void dump(final IndentingPrintWriter pw, final FileDescriptor fd, boolean verbose)
             throws IOException, ServiceSpecificException {
         if (PRE_T) {
             throw new ServiceSpecificException(
@@ -929,6 +967,11 @@
                     + " devices, use dumpsys netd trafficcontroller instead.");
         }
         mDeps.nativeDump(fd, verbose);
+
+        if (verbose) {
+            BpfDump.dumpMap(sUidPermissionMap, pw, "sUidPermissionMap",
+                    (uid, permission) -> uid.val + " " + permissionToString(permission.val));
+        }
     }
 
     private static native void native_init(boolean startSkDestroyListener);
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 84cf561..6804baf 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -3457,7 +3457,7 @@
     private void dumpTrafficController(IndentingPrintWriter pw, final FileDescriptor fd,
             boolean verbose) {
         try {
-            mBpfNetMaps.dump(fd, verbose);
+            mBpfNetMaps.dump(pw, fd, verbose);
         } catch (ServiceSpecificException e) {
             pw.println(e.getMessage());
         } catch (IOException e) {
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index 4966aed..7c31607 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -61,6 +61,7 @@
 import android.os.Build;
 import android.os.ServiceSpecificException;
 import android.system.ErrnoException;
+import android.util.IndentingPrintWriter;
 
 import androidx.test.filters.SmallTest;
 
@@ -84,6 +85,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.FileDescriptor;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -927,4 +930,37 @@
         final int ret = mBpfNetMaps.pullBpfMapInfoAtom(-1 /* atomTag */, new ArrayList<>());
         assertEquals(StatsManager.PULL_SKIP, ret);
     }
+
+    private void assertDumpContains(final String dump, final String message) {
+        assertTrue(String.format("dump(%s) does not contain '%s'", dump, message),
+                dump.contains(message));
+    }
+
+    private String getDump() throws Exception {
+        final StringWriter sw = new StringWriter();
+        mBpfNetMaps.dump(new IndentingPrintWriter(sw), new FileDescriptor(), true /* verbose */);
+        return sw.toString();
+    }
+
+    private void doTestDumpUidPermissionMap(final int permission, final String permissionString)
+            throws Exception {
+        mUidPermissionMap.updateEntry(new S32(TEST_UID), new U8((short) permission));
+        assertDumpContains(getDump(), TEST_UID + " " + permissionString);
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testDumpUidPermissionMap() throws Exception {
+        doTestDumpUidPermissionMap(PERMISSION_NONE, "PERMISSION_NONE");
+        doTestDumpUidPermissionMap(PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS,
+                "PERMISSION_INTERNET PERMISSION_UPDATE_DEVICE_STATS");
+    }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testDumpUidPermissionMapInvalidPermission() throws Exception {
+        doTestDumpUidPermissionMap(PERMISSION_UNINSTALLED, "PERMISSION_UNINSTALLED error!");
+        doTestDumpUidPermissionMap(PERMISSION_INTERNET | 1 << 6,
+                "PERMISSION_INTERNET PERMISSION_UNKNOWN(64)");
+    }
 }