Move stats map A/B dump to NetworkStatsService

Map status dump will do access check if map is null.
This could show different message from the current dump output.

Information in map content dump does not change
$ dumpsys connectivity trafficcontroller
....
      mStatsMapA:
      ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets
      20 wlan0 0x0 1051 0 144 2 312 4
      10 rmnet_data0 0x0 0 0 0 0 48 1
      20 wlan0 0x0 0 0 0 0 136 2
      20 wlan0 0xffffff82 1051 0 144 2 312 4

      mStatsMapB:
      ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets
....

$ dumpsys netstats
....
  mStatsMapA:
    ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets
    20 wlan0 0x0 1051 0 144 2 312 4
    10 rmnet_data0 0x0 0 0 0 0 48 1
    20 wlan0 0x0 0 0 0 0 136 2
    20 wlan0 0xffffff82 1051 0 144 2 312 4
  mStatsMapB:
    ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets
....

Bug: 217624062
Test: dumpsys netstats, dumpstate, atest NetworkStatsServiceTest

Change-Id: Ifbd45f0ad6dd9c519a15a7680cf0ea99fb5f5dcf
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 8d5c881..1aa3af5 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -2755,6 +2755,8 @@
             dumpCookieTagMapLocked(pw);
             dumpUidCounterSetMapLocked(pw);
             dumpAppUidStatsMapLocked(pw);
+            dumpStatsMapLocked(mStatsMapA, pw, "mStatsMapA");
+            dumpStatsMapLocked(mStatsMapB, pw, "mStatsMapB");
             pw.decreaseIndent();
         }
     }
@@ -2840,6 +2842,8 @@
         pw.println("mUidCounterSetMap: "
                 + getMapStatus(mUidCounterSetMap, UID_COUNTERSET_MAP_PATH));
         pw.println("mAppUidStatsMap: " + getMapStatus(mAppUidStatsMap, APP_UID_STATS_MAP_PATH));
+        pw.println("mStatsMapA: " + getMapStatus(mStatsMapA, STATS_MAP_A_PATH));
+        pw.println("mStatsMapB: " + getMapStatus(mStatsMapB, STATS_MAP_B_PATH));
     }
 
     @GuardedBy("mStatsLock")
@@ -2876,6 +2880,30 @@
                         + value.txPackets);
     }
 
+    @GuardedBy("mStatsLock")
+    private void dumpStatsMapLocked(final IBpfMap<StatsMapKey, StatsMapValue> statsMap,
+            final IndentingPrintWriter pw, final String mapName) {
+        if (statsMap == null) {
+            return;
+        }
+
+        BpfDump.dumpMap(statsMap, pw, mapName,
+                "ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets",
+                (key, value) -> {
+                    final long ifIndex = key.ifaceIndex;
+                    final String ifName = mInterfaceMapUpdater.getIfNameByIndex(ifIndex);
+                    return ifIndex + " "
+                            + (ifName != null ? ifName : "unknown") + " "
+                            + "0x" + Long.toHexString(key.tag) + " "
+                            + key.uid + " "
+                            + key.counterSet + " "
+                            + value.rxBytes + " "
+                            + value.rxPackets + " "
+                            + value.txBytes + " "
+                            + value.txPackets;
+                });
+    }
+
     private NetworkStats readNetworkStatsSummaryDev() {
         try {
             return mStatsFactory.readNetworkStatsSummaryDev();
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index 7fb1b34..a21576d 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -647,35 +647,6 @@
         dw.println("mCookieTagMap print end with error: %s", res.error().message().c_str());
     }
 
-
-    // Print uidStatsMap content.
-    std::string statsHeader = StringPrintf("ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes"
-                                           " rxPackets txBytes txPackets");
-    dumpBpfMap("mStatsMapA", dw, statsHeader);
-    const auto printStatsInfo = [&dw, this](const StatsKey& key, const StatsValue& value,
-                                            const BpfMap<StatsKey, StatsValue>&) {
-        uint32_t ifIndex = key.ifaceIndex;
-        auto ifname = mIfaceIndexNameMap.readValue(ifIndex);
-        if (!ifname.ok()) {
-            ifname = IfaceValue{"unknown"};
-        }
-        dw.println("%u %s 0x%x %u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, ifIndex,
-                   ifname.value().name, key.tag, key.uid, key.counterSet, value.rxBytes,
-                   value.rxPackets, value.txBytes, value.txPackets);
-        return base::Result<void>();
-    };
-    res = mStatsMapA.iterateWithValue(printStatsInfo);
-    if (!res.ok()) {
-        dw.println("mStatsMapA print end with error: %s", res.error().message().c_str());
-    }
-
-    // Print TagStatsMap content.
-    dumpBpfMap("mStatsMapB", dw, statsHeader);
-    res = mStatsMapB.iterateWithValue(printStatsInfo);
-    if (!res.ok()) {
-        dw.println("mStatsMapB print end with error: %s", res.error().message().c_str());
-    }
-
     // Print ifaceIndexToNameMap content.
     dumpBpfMap("mIfaceIndexNameMap", dw, "");
     const auto printIfaceNameInfo = [&dw](const uint32_t& key, const IfaceValue& value,
diff --git a/service/native/TrafficControllerTest.cpp b/service/native/TrafficControllerTest.cpp
index d08ffee..4205d73 100644
--- a/service/native/TrafficControllerTest.cpp
+++ b/service/native/TrafficControllerTest.cpp
@@ -792,12 +792,7 @@
     // 999 test0 0x2a 10086 1 100 1 0 0
     std::vector<std::string> expectedLines = {
         "mCookieTagMap:",
-        fmt::format("cookie={} tag={:#x} uid={}", TEST_COOKIE, TEST_TAG, TEST_UID),
-        "mStatsMapA",
-        "ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets",
-        fmt::format("{} {} {:#x} {} {} {} {} {} {}",
-                    TEST_IFINDEX, TEST_IFNAME, TEST_TAG, TEST_UID, TEST_COUNTERSET, RXBYTES,
-                    RXPACKETS, TXBYTES, TXPACKETS)};
+        fmt::format("cookie={} tag={:#x} uid={}", TEST_COOKIE, TEST_TAG, TEST_UID)};
 
     populateFakeIfaceIndexName(TEST_IFNAME, TEST_IFINDEX);
     expectedLines.emplace_back("mIfaceIndexNameMap:");
@@ -829,8 +824,6 @@
 
     std::vector<std::string> expectedLines = {
         fmt::format("mCookieTagMap {}", kErrIterate),
-        fmt::format("mStatsMapA {}", kErrIterate),
-        fmt::format("mStatsMapB {}", kErrIterate),
         fmt::format("mIfaceIndexNameMap {}", kErrIterate),
         fmt::format("mIfaceStatsMap {}", kErrIterate),
         fmt::format("mConfigurationMap {}", kErrReadRulesConfig),
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index e27e4e2..fdbccba 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -2528,4 +2528,28 @@
         assertDumpContains(dump, "uid rxBytes rxPackets txBytes txPackets");
         assertDumpContains(dump, "1002 10000 10 6000 6");
     }
+
+    private void doTestDumpStatsMap(final String expectedIfaceName) throws ErrnoException {
+        initBpfMapsWithTagData(UID_BLUE);
+
+        final String dump = getDump();
+        assertDumpContains(dump, "mStatsMapA: OK");
+        assertDumpContains(dump, "mStatsMapB: OK");
+        assertDumpContains(dump,
+                "ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets");
+        assertDumpContains(dump, "10 " + expectedIfaceName + " 0x2 1002 0 5000 5 3000 3");
+        assertDumpContains(dump, "10 " + expectedIfaceName + " 0x1 1002 0 5000 5 3000 3");
+    }
+
+    @Test
+    public void testDumpStatsMap() throws ErrnoException {
+        doReturn("wlan0").when(mBpfInterfaceMapUpdater).getIfNameByIndex(10 /* index */);
+        doTestDumpStatsMap("wlan0");
+    }
+
+    @Test
+    public void testDumpStatsMapUnknownInterface() throws ErrnoException {
+        doReturn(null).when(mBpfInterfaceMapUpdater).getIfNameByIndex(10 /* index */);
+        doTestDumpStatsMap("unknown");
+    }
 }