Move Interface index name map 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
....
     mIfaceIndexNameMap:
      ifaceIndex=5 ifaceName=ip6_vti0
      ifaceIndex=19 ifaceName=r_rmnet_data3
      ifaceIndex=17 ifaceName=r_rmnet_data1
      ifaceIndex=18 ifaceName=r_rmnet_data2
      ifaceIndex=23 ifaceName=wifi-aware0
....

$ dumpsys netstats
....
  BPF map content:
    ifaceIndex=5 ifaceName=ip6_vti0
    ifaceIndex=19 ifaceName=r_rmnet_data3
    ifaceIndex=17 ifaceName=r_rmnet_data1
    ifaceIndex=18 ifaceName=r_rmnet_data2
    ifaceIndex=8 ifaceName=rmnet_ipa0
....

Bug: 217624062
Test: dumpsys netstats, atest
com.android.server.net.BpfInterfaceMapUpdaterTest

Change-Id: If182bd97f72713b6347028668cf7bd4676b8aea4
diff --git a/service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java b/service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java
index ed889e1..57466a6 100644
--- a/service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java
+++ b/service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java
@@ -22,10 +22,12 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.system.ErrnoException;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
+import com.android.net.module.util.BpfDump;
 import com.android.net.module.util.BpfMap;
 import com.android.net.module.util.IBpfMap;
 import com.android.net.module.util.InterfaceParams;
@@ -151,4 +153,22 @@
             return null;
         }
     }
+
+    /**
+     * Dump BPF map
+     *
+     * @param pw print writer
+     */
+    public void dump(final IndentingPrintWriter pw) {
+        pw.println("BPF map status:");
+        pw.increaseIndent();
+        BpfDump.dumpMapStatus(mBpfMap, pw, "IfaceIndexNameMap", IFACE_INDEX_NAME_MAP_PATH);
+        pw.decreaseIndent();
+        pw.println("BPF map content:");
+        pw.increaseIndent();
+        BpfDump.dumpMap(mBpfMap, pw, "IfaceIndexNameMap",
+                (key, value) -> "ifaceIndex=" + key.val
+                        + " ifaceName=" + value.getInterfaceNameString());
+        pw.decreaseIndent();
+    }
 }
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 1aa3af5..09eb54c 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -2741,6 +2741,12 @@
             }
 
             pw.println();
+            pw.println("InterfaceMapUpdater:");
+            pw.increaseIndent();
+            mInterfaceMapUpdater.dump(pw);
+            pw.decreaseIndent();
+
+            pw.println();
             pw.println("BPF map status:");
             pw.increaseIndent();
             dumpMapStatus(pw);
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index a21576d..49b23c9 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -647,19 +647,6 @@
         dw.println("mCookieTagMap 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,
-                                          const BpfMap<uint32_t, IfaceValue>&) {
-        const char* ifname = value.name;
-        dw.println("ifaceIndex=%u ifaceName=%s", key, ifname);
-        return base::Result<void>();
-    };
-    res = mIfaceIndexNameMap.iterateWithValue(printIfaceNameInfo);
-    if (!res.ok()) {
-        dw.println("mIfaceIndexNameMap print end with error: %s", res.error().message().c_str());
-    }
-
     // Print ifaceStatsMap content
     std::string ifaceStatsHeader = StringPrintf("ifaceIndex ifaceName rxBytes rxPackets txBytes"
                                                 " txPackets");
diff --git a/service/native/TrafficControllerTest.cpp b/service/native/TrafficControllerTest.cpp
index 4205d73..8525738 100644
--- a/service/native/TrafficControllerTest.cpp
+++ b/service/native/TrafficControllerTest.cpp
@@ -60,7 +60,6 @@
 constexpr uint32_t TEST_TAG = 42;
 constexpr uint32_t TEST_COUNTERSET = 1;
 constexpr int TEST_COOKIE = 1;
-constexpr char TEST_IFNAME[] = "test0";
 constexpr int TEST_IFINDEX = 999;
 constexpr int RXPACKETS = 1;
 constexpr int RXBYTES = 100;
@@ -794,11 +793,6 @@
         "mCookieTagMap:",
         fmt::format("cookie={} tag={:#x} uid={}", TEST_COOKIE, TEST_TAG, TEST_UID)};
 
-    populateFakeIfaceIndexName(TEST_IFNAME, TEST_IFINDEX);
-    expectedLines.emplace_back("mIfaceIndexNameMap:");
-    expectedLines.emplace_back(fmt::format("ifaceIndex={} ifaceName={}",
-                                           TEST_IFINDEX, TEST_IFNAME));
-
     ASSERT_TRUE(isOk(updateUidOwnerMaps({TEST_UID}, HAPPY_BOX_MATCH,
                                         TrafficController::IptOpInsert)));
     expectedLines.emplace_back("mUidOwnerMap:");
@@ -824,7 +818,6 @@
 
     std::vector<std::string> expectedLines = {
         fmt::format("mCookieTagMap {}", kErrIterate),
-        fmt::format("mIfaceIndexNameMap {}", kErrIterate),
         fmt::format("mIfaceStatsMap {}", kErrIterate),
         fmt::format("mConfigurationMap {}", kErrReadRulesConfig),
         fmt::format("mConfigurationMap {}", kErrReadStatsMapConfig),
diff --git a/tests/unit/java/com/android/server/net/BpfInterfaceMapUpdaterTest.java b/tests/unit/java/com/android/server/net/BpfInterfaceMapUpdaterTest.java
index 6f551c5..83e6b5f 100644
--- a/tests/unit/java/com/android/server/net/BpfInterfaceMapUpdaterTest.java
+++ b/tests/unit/java/com/android/server/net/BpfInterfaceMapUpdaterTest.java
@@ -20,6 +20,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.spy;
@@ -34,6 +35,7 @@
 import android.os.Handler;
 import android.os.test.TestLooper;
 import android.system.ErrnoException;
+import android.util.IndentingPrintWriter;
 
 import androidx.test.filters.SmallTest;
 
@@ -52,6 +54,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
 @SmallTest
 @RunWith(DevSdkIgnoreRunner.class)
 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
@@ -144,4 +149,26 @@
         doThrow(new ErrnoException("", EPERM)).when(mBpfMap).getValue(new U32(TEST_INDEX));
         assertNull(mUpdater.getIfNameByIndex(TEST_INDEX));
     }
+
+    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() {
+        final StringWriter sw = new StringWriter();
+        mUpdater.dump(new IndentingPrintWriter(new PrintWriter(sw), " "));
+        return sw.toString();
+    }
+
+    @Test
+    public void testDump() throws ErrnoException {
+        mBpfMap.updateEntry(new U32(TEST_INDEX), new InterfaceMapValue(TEST_INTERFACE_NAME));
+        mBpfMap.updateEntry(new U32(TEST_INDEX2), new InterfaceMapValue(TEST_INTERFACE_NAME2));
+
+        final String dump = getDump();
+        assertDumpContains(dump, "IfaceIndexNameMap: OK");
+        assertDumpContains(dump, "ifaceIndex=1 ifaceName=test1");
+        assertDumpContains(dump, "ifaceIndex=2 ifaceName=test2");
+    }
 }