Merge "NetworkStatsFactory: no double looping on stats + stacked interfaces" am: b884b37cea am: cd6537edb5
am: b323e61584

Change-Id: I0312882bb8885aaa65f99a445fd0554d6ac054b3
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 2fb3532..3d3e148 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -192,46 +192,43 @@
             NetworkStats lastStats) throws IOException {
         final NetworkStats stats =
               readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats);
-        NetworkStats.Entry entry = null; // for recycling
-
+        final ArrayMap<String, String> stackedIfaces;
         synchronized (sStackedIfaces) {
-            // For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4
-            // packet on the stacked interface, and once as translated to an IPv6 packet on the
-            // base interface. For correct stats accounting on the base interface, every 464xlat
-            // packet needs to be subtracted from the root UID on the base interface both for tx
-            // and rx traffic (http://b/12249687, http:/b/33681750).
-            final int size = sStackedIfaces.size();
-            for (int i = 0; i < size; i++) {
-                final String stackedIface = sStackedIfaces.keyAt(i);
-                final String baseIface = sStackedIfaces.valueAt(i);
-                if (!stackedIface.startsWith(CLATD_INTERFACE_PREFIX)) {
-                    continue;
-                }
-
-                NetworkStats.Entry adjust =
-                    new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, 0L, 0L);
-                for (int j = 0; j < stats.size(); j++) {
-                    entry = stats.getValues(j, entry);
-                    if (Objects.equals(entry.iface, stackedIface)) {
-                        adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA);
-                        adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA);
-                        adjust.rxPackets -= entry.rxPackets;
-                        adjust.txPackets -= entry.txPackets;
-                    }
-                }
-                stats.combineValues(adjust);
-            }
+            stackedIfaces = new ArrayMap<>(sStackedIfaces);
         }
+        // Total 464xlat traffic to subtract from uid 0 on all base interfaces.
+        final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size());
 
-        // For 464xlat traffic, xt_qtaguid only counts the bytes of the inner IPv4 packet sent on
-        // the stacked interface with prefix "v4-" and drops the IPv6 header size after unwrapping.
-        // To account correctly for on-the-wire traffic, add the 20 additional bytes difference
-        // for all packets (http://b/12249687, http:/b/33681750).
+        NetworkStats.Entry entry = null; // For recycling
+
+        // For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4
+        // packet on the stacked interface, and once as translated to an IPv6 packet on the
+        // base interface. For correct stats accounting on the base interface, every 464xlat
+        // packet needs to be subtracted from the root UID on the base interface both for tx
+        // and rx traffic (http://b/12249687, http:/b/33681750).
         for (int i = 0; i < stats.size(); i++) {
             entry = stats.getValues(i, entry);
             if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) {
                 continue;
             }
+            final String baseIface = stackedIfaces.get(entry.iface);
+            if (baseIface == null) {
+                continue;
+            }
+
+            NetworkStats.Entry adjust =
+                    new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, 0L, 0L);
+            // Subtract any 464lat traffic seen for the root UID on the current base interface.
+            adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA);
+            adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA);
+            adjust.rxPackets -= entry.rxPackets;
+            adjust.txPackets -= entry.txPackets;
+            adjustments.combineValues(adjust);
+
+            // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent
+            // on the stacked interface with prefix "v4-" and drops the IPv6 header size after
+            // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes
+            // difference for all packets (http://b/12249687, http:/b/33681750).
             entry.rxBytes = entry.rxPackets * IPV4V6_HEADER_DELTA;
             entry.txBytes = entry.txPackets * IPV4V6_HEADER_DELTA;
             entry.rxPackets = 0;
@@ -239,6 +236,8 @@
             stats.combineValues(entry);
         }
 
+        stats.combineAllValues(adjustments);
+
         return stats;
     }