Merge "Remove system_server_current related work arounds"
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index e7d049f..e07601f 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -2066,6 +2066,36 @@
     }
 
     /**
+     * Returns a short but human-readable string of updates from an older set of capabilities.
+     * @param old the old capabilities to diff from
+     * @return a string fit for logging differences, or null if no differences.
+     *         this never returns the empty string.
+     * @hide
+     */
+    @Nullable
+    public String describeCapsDifferencesFrom(@Nullable final NetworkCapabilities old) {
+        final long oldCaps = null == old ? 0 : old.mNetworkCapabilities;
+        final long changed = oldCaps ^ mNetworkCapabilities;
+        if (0 == changed) return null;
+        // If the control reaches here, there are changes (additions, removals, or both) so
+        // the code below is guaranteed to add something to the string and can't return "".
+        final long removed = oldCaps & changed;
+        final long added = mNetworkCapabilities & changed;
+        final StringBuilder sb = new StringBuilder();
+        if (0 != removed) {
+            sb.append("-");
+            appendStringRepresentationOfBitMaskToStringBuilder(sb, removed,
+                    NetworkCapabilities::capabilityNameOf, "-");
+        }
+        if (0 != added) {
+            sb.append("+");
+            appendStringRepresentationOfBitMaskToStringBuilder(sb, added,
+                    NetworkCapabilities::capabilityNameOf, "+");
+        }
+        return sb.toString();
+    }
+
+    /**
      * Checks that our requestable capabilities are the same as those of the given
      * {@code NetworkCapabilities}.
      *
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 629bf73..cf53002 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -430,12 +430,7 @@
     private long mLastStatsSessionPoll;
 
     private final Object mOpenSessionCallsLock = new Object();
-    /**
-     * Map from UID to number of opened sessions. This is used for rate-limt an app to open
-     * session frequently
-     */
-    @GuardedBy("mOpenSessionCallsLock")
-    private final SparseIntArray mOpenSessionCallsPerUid = new SparseIntArray();
+
     /**
      * Map from key {@code OpenSessionKey} to count of opened sessions. This is for recording
      * the caller of open session and it is only for debugging.
@@ -1361,9 +1356,6 @@
                 mOpenSessionCallsPerCaller.put(key, Integer.sum(callsPerCaller, 1));
             }
 
-            int callsPerUid = mOpenSessionCallsPerUid.get(key.uid, 0);
-            mOpenSessionCallsPerUid.put(key.uid, callsPerUid + 1);
-
             if (key.uid == android.os.Process.SYSTEM_UID) {
                 return false;
             }
@@ -2514,8 +2506,7 @@
         for (int uid : uids) {
             deleteKernelTagData(uid);
         }
-        // TODO: Remove the UID's entries from mOpenSessionCallsPerUid and
-        // mOpenSessionCallsPerCaller
+        // TODO: Remove the UID's entries from mOpenSessionCallsPerCaller.
     }
 
     /**
@@ -2959,7 +2950,7 @@
      */
     private NetworkStats getNetworkStatsUidDetail(String[] ifaces)
             throws RemoteException {
-        final NetworkStats uidSnapshot = readNetworkStatsUidDetail(UID_ALL,  ifaces, TAG_ALL);
+        final NetworkStats uidSnapshot = readNetworkStatsUidDetail(UID_ALL, ifaces, TAG_ALL);
 
         // fold tethering stats and operations into uid snapshot
         final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID);
@@ -2974,6 +2965,7 @@
         uidSnapshot.combineAllValues(providerStats);
 
         uidSnapshot.combineAllValues(mUidOperations);
+        uidSnapshot.filter(UID_ALL, ifaces, TAG_ALL);
 
         return uidSnapshot;
     }
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index fc76ae5..8f6df21 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -595,7 +595,7 @@
     }
 }
 
-void TrafficController::dump(int fd, bool verbose) {
+void TrafficController::dump(int fd, bool verbose __unused) {
     std::lock_guard guard(mMutex);
     DumpWriter dw(fd);
 
@@ -623,31 +623,6 @@
                getMapStatus(mConfigurationMap.getMap(), CONFIGURATION_MAP_PATH).c_str());
     dw.println("mUidOwnerMap status: %s",
                getMapStatus(mUidOwnerMap.getMap(), UID_OWNER_MAP_PATH).c_str());
-
-    if (!verbose) {
-        return;
-    }
-
-    dw.blankline();
-    dw.println("BPF map content:");
-
-    ScopedIndent indentForMapContent(dw);
-
-    // Print CookieTagMap content.
-    // TagSocketTest in CTS was using the output of mCookieTagMap dump.
-    // So, mCookieTagMap dump can not be removed until the previous CTS support period is over.
-    dumpBpfMap("mCookieTagMap", dw, "");
-    const auto printCookieTagInfo = [&dw](const uint64_t& key, const UidTagValue& value,
-                                          const BpfMap<uint64_t, UidTagValue>&) {
-        dw.println("cookie=%" PRIu64 " tag=0x%x uid=%u", key, value.tag, value.uid);
-        return base::Result<void>();
-    };
-    base::Result<void> res = mCookieTagMap.iterateWithValue(printCookieTagInfo);
-    if (!res.ok()) {
-        dw.println("mCookieTagMap print end with error: %s", res.error().message().c_str());
-    }
-
-    dw.blankline();
 }
 
 }  // namespace net
diff --git a/service/native/TrafficControllerTest.cpp b/service/native/TrafficControllerTest.cpp
index 6cb0940..57f32af 100644
--- a/service/native/TrafficControllerTest.cpp
+++ b/service/native/TrafficControllerTest.cpp
@@ -59,7 +59,6 @@
 constexpr uid_t TEST_UID3 = 98765;
 constexpr uint32_t TEST_TAG = 42;
 constexpr uint32_t TEST_COUNTERSET = 1;
-constexpr int TEST_COOKIE = 1;
 constexpr int TEST_IFINDEX = 999;
 constexpr int RXPACKETS = 1;
 constexpr int RXBYTES = 100;
@@ -769,46 +768,6 @@
     expectPrivilegedUserSetEmpty();
 }
 
-TEST_F(TrafficControllerTest, TestDumpsys) {
-    StatsKey tagStatsMapKey;
-    populateFakeStats(TEST_COOKIE, TEST_UID, TEST_TAG, &tagStatsMapKey);
-    populateFakeCounterSet(TEST_UID3, TEST_COUNTERSET);
-
-    // Expect: (part of this depends on hard-code values in populateFakeStats())
-    //
-    // mCookieTagMap:
-    // cookie=1 tag=0x2a uid=10086
-    //
-    // mUidCounterSetMap:
-    // 98765 1
-    //
-    // mAppUidStatsMap::
-    // uid rxBytes rxPackets txBytes txPackets
-    // 10086 100 1 0 0
-    //
-    // mStatsMapA:
-    // ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets
-    // 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)};
-
-    EXPECT_TRUE(expectDumpsysContains(expectedLines));
-}
-
-TEST_F(TrafficControllerTest, dumpsysInvalidMaps) {
-    makeTrafficControllerMapsInvalid();
-
-    const std::string kErrIterate = "print end with error: Get firstKey map -1 failed: "
-            "Bad file descriptor";
-    const std::string kErrReadRulesConfig = "read ownerMatch configure failed with error: "
-            "Read value of map -1 failed: Bad file descriptor";
-
-    std::vector<std::string> expectedLines = {
-        fmt::format("mCookieTagMap {}", kErrIterate)};
-    EXPECT_TRUE(expectDumpsysContains(expectedLines));
-}
-
 TEST_F(TrafficControllerTest, getFirewallType) {
     static const struct TestConfig {
         ChildChain childChain;
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index d560747..aea2103 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -1022,11 +1022,25 @@
         }
         mDeps.nativeDump(fd, verbose);
 
+        pw.println();
+        pw.println("sEnableJavaBpfMap: " + sEnableJavaBpfMap);
         if (verbose) {
+            pw.println();
+            pw.println("BPF map content:");
+            pw.increaseIndent();
+
             dumpOwnerMatchConfig(pw);
             dumpCurrentStatsMapConfig(pw);
             pw.println();
 
+            // TODO: Remove CookieTagMap content dump
+            // NetworkStatsService also dumps CookieTagMap and NetworkStatsService is a right place
+            // to dump CookieTagMap. But the TagSocketTest in CTS depends on this dump so the tests
+            // need to be updated before remove the dump from BpfNetMaps.
+            BpfDump.dumpMap(sCookieTagMap, pw, "sCookieTagMap",
+                    (key, value) -> "cookie=" + key.socketCookie
+                            + " tag=0x" + Long.toHexString(value.tag)
+                            + " uid=" + value.uid);
             BpfDump.dumpMap(sUidOwnerMap, pw, "sUidOwnerMap",
                     (uid, match) -> {
                         if ((match.rule & IIF_MATCH) != 0) {
@@ -1038,6 +1052,7 @@
                     });
             BpfDump.dumpMap(sUidPermissionMap, pw, "sUidPermissionMap",
                     (uid, permission) -> uid.val + " " + permissionToString(permission.val));
+            pw.decreaseIndent();
         }
     }
 
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index d409d51..e732001 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -8008,6 +8008,10 @@
             @NonNull final NetworkCapabilities nc) {
         NetworkCapabilities newNc = mixInCapabilities(nai, nc);
         if (Objects.equals(nai.networkCapabilities, newNc)) return;
+        final String differences = newNc.describeCapsDifferencesFrom(nai.networkCapabilities);
+        if (null != differences) {
+            Log.i(TAG, "Update capabilities for net " + nai.network + " : " + differences);
+        }
         updateNetworkPermissions(nai, newNc);
         final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc);
 
diff --git a/service/src/com/android/server/connectivity/FullScore.java b/service/src/com/android/server/connectivity/FullScore.java
index aec4a71..2303894 100644
--- a/service/src/com/android/server/connectivity/FullScore.java
+++ b/service/src/com/android/server/connectivity/FullScore.java
@@ -23,7 +23,10 @@
 import static android.net.NetworkScore.KEEP_CONNECTED_NONE;
 import static android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI;
 
+import static com.android.net.module.util.BitUtils.appendStringRepresentationOfBitMaskToStringBuilder;
+
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkScore;
@@ -333,6 +336,35 @@
                 + 5 * mKeepConnectedReason;
     }
 
+    /**
+     * Returns a short but human-readable string of updates from an older score.
+     * @param old the old capabilities to diff from
+     * @return a string fit for logging differences, or null if no differences.
+     *         this method cannot return the empty string.
+     */
+    @Nullable
+    public String describeDifferencesFrom(@Nullable final FullScore old) {
+        final long oldPolicies = null == old ? 0 : old.mPolicies;
+        final long changed = oldPolicies ^ mPolicies;
+        if (0 == changed) return null;
+        // If the control reaches here, there are changes (additions, removals, or both) so
+        // the code below is guaranteed to add something to the string and can't return "".
+        final long removed = oldPolicies & changed;
+        final long added = mPolicies & changed;
+        final StringBuilder sb = new StringBuilder();
+        if (0 != removed) {
+            sb.append("-");
+            appendStringRepresentationOfBitMaskToStringBuilder(sb, removed,
+                    FullScore::policyNameOf, "-");
+        }
+        if (0 != added) {
+            sb.append("+");
+            appendStringRepresentationOfBitMaskToStringBuilder(sb, added,
+                    FullScore::policyNameOf, "+");
+        }
+        return sb.toString();
+    }
+
     // Example output :
     // Score(Policies : EVER_USER_SELECTED&IS_VALIDATED ; KeepConnected : )
     @Override
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index 2e92d43..85282cb 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -1003,9 +1003,7 @@
             @NonNull final NetworkCapabilities nc) {
         final NetworkCapabilities oldNc = networkCapabilities;
         networkCapabilities = nc;
-        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, everValidated(),
-                0L != getAvoidUnvalidated(), yieldToBadWiFi(),
-                0L != mFirstEvaluationConcludedTime, isDestroyed());
+        updateScoreForNetworkAgentUpdate();
         final NetworkMonitorManager nm = mNetworkMonitor;
         if (nm != null) {
             nm.notifyNetworkCapabilitiesChanged(nc);
@@ -1207,9 +1205,11 @@
      * Mix-in the ConnectivityService-managed bits in the score.
      */
     public void setScore(final NetworkScore score) {
+        final FullScore oldScore = mScore;
         mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig,
                 everValidated(), 0L != getAvoidUnvalidated(), yieldToBadWiFi(),
                 0L != mFirstEvaluationConcludedTime, isDestroyed());
+        maybeLogDifferences(oldScore);
     }
 
     /**
@@ -1218,9 +1218,22 @@
      * Call this after changing any data that might affect the score (e.g., agent config).
      */
     public void updateScoreForNetworkAgentUpdate() {
+        final FullScore oldScore = mScore;
         mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig,
                 everValidated(), 0L != getAvoidUnvalidated(), yieldToBadWiFi(),
                 0L != mFirstEvaluationConcludedTime, isDestroyed());
+        maybeLogDifferences(oldScore);
+    }
+
+    /**
+     * Prints score differences to logcat, if any.
+     * @param oldScore the old score. Differences from |oldScore| to |this| are logged, if any.
+     */
+    public void maybeLogDifferences(final FullScore oldScore) {
+        final String differences = mScore.describeDifferencesFrom(oldScore);
+        if (null != differences) {
+            Log.i(TAG, "Update score for net " + network + " : " + differences);
+        }
     }
 
     /**
diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
index c30e1d3..7b374d2 100644
--- a/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -36,6 +36,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
@@ -1370,4 +1371,23 @@
 
         assertEquals(expectedNcBuilder.build(), restrictedNc);
     }
+
+    @Test
+    public void testDescribeCapsDifferences() throws Exception {
+        final NetworkCapabilities nc1 = new NetworkCapabilities.Builder()
+                .addCapability(NET_CAPABILITY_MMS)
+                .addCapability(NET_CAPABILITY_OEM_PAID)
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .build();
+        final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
+                .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL)
+                .addCapability(NET_CAPABILITY_SUPL)
+                .addCapability(NET_CAPABILITY_VALIDATED)
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .build();
+        assertEquals("-MMS-OEM_PAID+SUPL+VALIDATED+CAPTIVE_PORTAL",
+                nc2.describeCapsDifferencesFrom(nc1));
+        assertEquals("-SUPL-VALIDATED-CAPTIVE_PORTAL+MMS+OEM_PAID",
+                nc1.describeCapsDifferencesFrom(nc2));
+    }
 }
diff --git a/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java b/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
index 8a537be..679427a 100644
--- a/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
+++ b/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
@@ -16,7 +16,16 @@
 
 package android.app.usage;
 
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.METERED_NO;
 import static android.net.NetworkStats.METERED_YES;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.SET_ALL;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.MATCH_MOBILE;
 import static android.net.NetworkTemplate.MATCH_WIFI;
 
@@ -34,7 +43,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.net.ConnectivityManager;
 import android.net.INetworkStatsService;
 import android.net.INetworkStatsSession;
 import android.net.NetworkStats.Entry;
@@ -86,31 +94,17 @@
         final int uid2 = 10002;
         final int uid3 = 10003;
 
-        Entry uid1Entry1 = new Entry("if1", uid1,
-                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
-                android.net.NetworkStats.METERED_NO, android.net.NetworkStats.ROAMING_NO,
-                android.net.NetworkStats.DEFAULT_NETWORK_NO,
-                100, 10, 200, 20, 0);
+        Entry uid1Entry1 = new Entry("if1", uid1, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 100, 10, 200, 20, 0);
 
-        Entry uid1Entry2 = new Entry(
-                "if2", uid1,
-                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
-                android.net.NetworkStats.METERED_NO, android.net.NetworkStats.ROAMING_NO,
-                android.net.NetworkStats.DEFAULT_NETWORK_NO,
-                100, 10, 200, 20, 0);
+        Entry uid1Entry2 = new Entry("if2", uid1, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 100, 10, 200, 20, 0);
 
-        Entry uid2Entry1 = new Entry("if1", uid2,
-                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
-                android.net.NetworkStats.METERED_NO, android.net.NetworkStats.ROAMING_NO,
-                android.net.NetworkStats.DEFAULT_NETWORK_NO,
-                150, 10, 250, 20, 0);
+        Entry uid2Entry1 = new Entry("if1", uid2, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 150, 10, 250, 20, 0);
 
-        Entry uid2Entry2 = new Entry(
-                "if2", uid2,
-                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
-                android.net.NetworkStats.METERED_NO, android.net.NetworkStats.ROAMING_NO,
-                android.net.NetworkStats.DEFAULT_NETWORK_NO,
-                150, 10, 250, 20, 0);
+        Entry uid2Entry2 = new Entry("if2", uid2, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO, 150, 10, 250, 20, 0);
 
         NetworkStatsHistory history1 = new NetworkStatsHistory(10, 2);
         history1.recordData(10, 20, uid1Entry1);
@@ -125,9 +119,8 @@
         when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2, uid3 });
 
         when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
-                eq(uid1), eq(android.net.NetworkStats.SET_ALL),
-                eq(android.net.NetworkStats.TAG_NONE),
-                eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
+                eq(uid1), eq(SET_ALL), eq(TAG_NONE),
+                eq(FIELD_ALL), eq(startTime), eq(endTime)))
                 .then((InvocationOnMock inv) -> {
                     NetworkTemplate template = inv.getArgument(0);
                     assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
@@ -136,9 +129,8 @@
                 });
 
         when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
-                eq(uid2), eq(android.net.NetworkStats.SET_ALL),
-                eq(android.net.NetworkStats.TAG_NONE),
-                eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
+                eq(uid2), eq(SET_ALL), eq(TAG_NONE),
+                eq(FIELD_ALL), eq(startTime), eq(endTime)))
                 .then((InvocationOnMock inv) -> {
                     NetworkTemplate template = inv.getArgument(0);
                     assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
@@ -148,7 +140,7 @@
 
 
         NetworkStats stats = mManager.queryDetails(
-                ConnectivityManager.TYPE_MOBILE, TEST_SUBSCRIBER_ID, startTime, endTime);
+                TYPE_MOBILE, TEST_SUBSCRIBER_ID, startTime, endTime);
 
         NetworkStats.Bucket bucket = new NetworkStats.Bucket();
 
@@ -202,35 +194,34 @@
 
         verify(mStatsSession, times(1)).getHistoryIntervalForUid(
                 eq(expectedTemplate),
-                eq(uid1), eq(android.net.NetworkStats.SET_ALL),
-                eq(android.net.NetworkStats.TAG_NONE),
-                eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
+                eq(uid1), eq(SET_ALL),
+                eq(TAG_NONE),
+                eq(FIELD_ALL), eq(startTime), eq(endTime));
 
         verify(mStatsSession, times(1)).getHistoryIntervalForUid(
                 eq(expectedTemplate),
-                eq(uid2), eq(android.net.NetworkStats.SET_ALL),
-                eq(android.net.NetworkStats.TAG_NONE),
-                eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
+                eq(uid2), eq(SET_ALL),
+                eq(TAG_NONE),
+                eq(FIELD_ALL), eq(startTime), eq(endTime));
 
         assertFalse(stats.hasNextBucket());
     }
 
     @Test
     public void testNetworkTemplateWhenRunningQueryDetails_NoSubscriberId() throws RemoteException {
-        runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_MOBILE,
-                null /* subscriberId */, new NetworkTemplate.Builder(MATCH_MOBILE)
-                        .setMeteredness(METERED_YES).build());
-        runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI,
-                "" /* subscriberId */, new NetworkTemplate.Builder(MATCH_WIFI).build());
-        runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI,
-                null /* subscriberId */, new NetworkTemplate.Builder(MATCH_WIFI).build());
+        runQueryDetailsAndCheckTemplate(TYPE_MOBILE, null /* subscriberId */,
+                new NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES).build());
+        runQueryDetailsAndCheckTemplate(TYPE_WIFI, "" /* subscriberId */,
+                new NetworkTemplate.Builder(MATCH_WIFI).build());
+        runQueryDetailsAndCheckTemplate(TYPE_WIFI, null /* subscriberId */,
+                new NetworkTemplate.Builder(MATCH_WIFI).build());
     }
 
     @Test
     public void testNetworkTemplateWhenRunningQueryDetails_MergedCarrierWifi()
             throws RemoteException {
-        runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI,
-                TEST_SUBSCRIBER_ID, new NetworkTemplate.Builder(MATCH_WIFI)
+        runQueryDetailsAndCheckTemplate(TYPE_WIFI, TEST_SUBSCRIBER_ID,
+                new NetworkTemplate.Builder(MATCH_WIFI)
                         .setSubscriberIds(Set.of(TEST_SUBSCRIBER_ID)).build());
     }
 
@@ -244,7 +235,7 @@
         when(mStatsSession.getTaggedSummaryForAllUid(any(NetworkTemplate.class),
                 anyLong(), anyLong()))
                 .thenReturn(new android.net.NetworkStats(0, 0));
-        final NetworkTemplate template = new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
+        final NetworkTemplate template = new NetworkTemplate.Builder(MATCH_MOBILE)
                 .setMeteredness(NetworkStats.Bucket.METERED_YES).build();
         NetworkStats stats = mManager.queryTaggedSummary(template, startTime, endTime);
 
@@ -265,12 +256,12 @@
         when(mStatsSession.getHistoryIntervalForNetwork(any(NetworkTemplate.class),
                 anyInt(), anyLong(), anyLong()))
                 .thenReturn(new NetworkStatsHistory(10, 0));
-        final NetworkTemplate template = new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
+        final NetworkTemplate template = new NetworkTemplate.Builder(MATCH_MOBILE)
                 .setMeteredness(NetworkStats.Bucket.METERED_YES).build();
         NetworkStats stats = mManager.queryDetailsForDevice(template, startTime, endTime);
 
         verify(mStatsSession, times(1)).getHistoryIntervalForNetwork(
-                eq(template), eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
+                eq(template), eq(FIELD_ALL), eq(startTime), eq(endTime));
 
         assertFalse(stats.hasNextBucket());
     }
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index 0c00bc0..0e17cd7 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -1070,4 +1070,11 @@
         doTestDumpOwnerMatchConfig(DOZABLE_MATCH | invalid_match,
                 "DOZABLE_MATCH UNKNOWN_MATCH(" + invalid_match + ")");
     }
+
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+    public void testDumpCookieTagMap() throws Exception {
+        mCookieTagMap.updateEntry(new CookieTagMapKey(123), new CookieTagMapValue(456, 0x789));
+        assertDumpContains(getDump(), "cookie=123 tag=0x789 uid=456");
+    }
 }
diff --git a/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt b/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
index b39e960..3520c5b 100644
--- a/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
@@ -152,4 +152,16 @@
         assertNotEquals(ns3, ns1)
         assertFalse(ns1.equals(ns4))
     }
+
+    @Test
+    fun testDescribeDifferences() {
+        val ns1 = FullScore((1L shl POLICY_EVER_EVALUATED) or (1L shl POLICY_IS_VALIDATED),
+                KEEP_CONNECTED_NONE)
+        val ns2 = FullScore((1L shl POLICY_IS_VALIDATED) or (1L shl POLICY_IS_VPN) or
+                (1L shl POLICY_IS_DESTROYED), KEEP_CONNECTED_NONE)
+        assertEquals("-EVER_EVALUATED+IS_DESTROYED+IS_VPN",
+                ns2.describeDifferencesFrom(ns1))
+        assertEquals("-IS_DESTROYED-IS_VPN+EVER_EVALUATED",
+                ns1.describeDifferencesFrom(ns2))
+    }
 }
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 2ceb00a..e8f30d6 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -75,12 +75,14 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalMatchers.aryEq;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -393,6 +395,10 @@
         verify(mNetd).registerUnsolicitedEventListener(alertObserver.capture());
         mAlertObserver = alertObserver.getValue();
 
+        // Make augmentWithStackedInterfaces returns the interfaces that was passed to it.
+        doAnswer(inv -> ((String[]) inv.getArgument(0)).clone())
+                .when(mStatsFactory).augmentWithStackedInterfaces(any());
+
         // Catch TetheringEventCallback during systemReady().
         ArgumentCaptor<TetheringManager.TetheringEventCallback> tetheringEventCbCaptor =
                 ArgumentCaptor.forClass(TetheringManager.TetheringEventCallback.class);
@@ -1239,45 +1245,73 @@
 
     @Test
     public void testUidStatsForTransport() throws Exception {
-        // pretend that network comes online
+        // Setup both wifi and mobile networks, and set mobile network as the default interface.
         mockDefaultSettings();
-        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
-        mockNetworkStatsSummary(buildEmptyStats());
         mockNetworkStatsUidDetail(buildEmptyStats());
 
-        mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
+        final NetworkStateSnapshot mobileState = buildStateOfTransport(
+                NetworkCapabilities.TRANSPORT_CELLULAR, TYPE_MOBILE,
+                TEST_IFACE2, IMSI_1, null /* wifiNetworkKey */,
+                false /* isTemporarilyNotMetered */, false /* isRoaming */);
+
+        final NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {
+                mobileState, buildWifiState()};
+        mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
+        setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_LTE);
 
-        NetworkStats.Entry entry1 = new NetworkStats.Entry(
+        // Mock traffic on wifi network.
+        final NetworkStats.Entry entry1 = new NetworkStats.Entry(
                 TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
-                DEFAULT_NETWORK_NO, 50L, 5L, 50L, 5L, 0L);
-        NetworkStats.Entry entry2 = new NetworkStats.Entry(
+                DEFAULT_NETWORK_NO, 50L, 5L, 50L, 5L, 1L);
+        final NetworkStats.Entry entry2 = new NetworkStats.Entry(
                 TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
-                DEFAULT_NETWORK_NO, 50L, 5L, 50L, 5L, 0L);
-        NetworkStats.Entry entry3 = new NetworkStats.Entry(
+                DEFAULT_NETWORK_NO, 50L, 5L, 50L, 5L, 1L);
+        final NetworkStats.Entry entry3 = new NetworkStats.Entry(
                 TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xBEEF, METERED_NO, ROAMING_NO,
-                DEFAULT_NETWORK_NO, 1024L, 8L, 512L, 4L, 0L);
+                DEFAULT_NETWORK_NO, 1024L, 8L, 512L, 4L, 2L);
 
+        final TetherStatsParcel[] emptyTetherStats = {};
+        // The interfaces that expect to be used to query the stats.
+        final String[] wifiIfaces = {TEST_IFACE};
         incrementCurrentTime(HOUR_IN_MILLIS);
         mockDefaultSettings();
-        mockNetworkStatsSummary(buildEmptyStats());
         mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
                 .insertEntry(entry1)
                 .insertEntry(entry2)
-                .insertEntry(entry3));
+                .insertEntry(entry3), emptyTetherStats, wifiIfaces);
+
+        // getUidStatsForTransport (through getNetworkStatsUidDetail) adds all operation counts
+        // with active interface, and the interface here is mobile interface, so this test makes
+        // sure these operations are not surfaced in getUidStatsForTransport if the transport
+        // doesn't match them.
         mService.incrementOperationCount(UID_RED, 0xF00D, 1);
+        final NetworkStats wifiStats = mService.getUidStatsForTransport(
+                NetworkCapabilities.TRANSPORT_WIFI);
 
-        NetworkStats stats = mService.getUidStatsForTransport(NetworkCapabilities.TRANSPORT_WIFI);
+        assertEquals(3, wifiStats.size());
+        // The iface field of the returned stats should be null because getUidStatsForTransport
+        // clears the interface fields before it returns the result.
+        assertValues(wifiStats, null /* iface */, UID_RED, SET_DEFAULT, TAG_NONE,
+                METERED_NO, ROAMING_NO, METERED_NO, 50L, 5L, 50L, 5L, 1L);
+        assertValues(wifiStats, null /* iface */, UID_RED, SET_DEFAULT, 0xF00D,
+                METERED_NO, ROAMING_NO, METERED_NO, 50L, 5L, 50L, 5L, 1L);
+        assertValues(wifiStats, null /* iface */, UID_BLUE, SET_DEFAULT, 0xBEEF,
+                METERED_NO, ROAMING_NO, METERED_NO, 1024L, 8L, 512L, 4L, 2L);
 
-        assertEquals(3, stats.size());
-        entry1.operations = 1;
-        entry1.iface = null;
-        assertEquals(entry1, stats.getValues(0, null));
-        entry2.operations = 1;
-        entry2.iface = null;
-        assertEquals(entry2, stats.getValues(1, null));
-        entry3.iface = null;
-        assertEquals(entry3, stats.getValues(2, null));
+        final String[] mobileIfaces = {TEST_IFACE2};
+        mockNetworkStatsUidDetail(buildEmptyStats(), emptyTetherStats, mobileIfaces);
+        final NetworkStats mobileStats = mService.getUidStatsForTransport(
+                NetworkCapabilities.TRANSPORT_CELLULAR);
+
+        assertEquals(2, mobileStats.size());
+        // Verify the operation count stats that caused by incrementOperationCount only appears
+        // on the mobile interface since incrementOperationCount attributes them onto the active
+        // interface.
+        assertValues(mobileStats, null /* iface */, UID_RED, SET_DEFAULT, 0xF00D,
+                METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 1);
+        assertValues(mobileStats, null /* iface */, UID_RED, SET_DEFAULT, TAG_NONE,
+                METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 1);
     }
 
     @Test
@@ -1468,7 +1502,7 @@
                 {buildTetherStatsParcel(TEST_IFACE, 1408L, 10L, 256L, 1L, 0)};
 
         mockNetworkStatsSummary(swIfaceStats);
-        mockNetworkStatsUidDetail(localUidStats, tetherStatsParcels);
+        mockNetworkStatsUidDetail(localUidStats, tetherStatsParcels, INTERFACES_ALL);
         forcePollAndWaitForIdle();
 
         // verify service recorded history
@@ -2235,13 +2269,14 @@
 
     private void mockNetworkStatsUidDetail(NetworkStats detail) throws Exception {
         final TetherStatsParcel[] tetherStatsParcels = {};
-        mockNetworkStatsUidDetail(detail, tetherStatsParcels);
+        mockNetworkStatsUidDetail(detail, tetherStatsParcels, INTERFACES_ALL);
     }
 
     private void mockNetworkStatsUidDetail(NetworkStats detail,
-            TetherStatsParcel[] tetherStatsParcels) throws Exception {
+            TetherStatsParcel[] tetherStatsParcels, String[] ifaces) throws Exception {
+
         doReturn(detail).when(mStatsFactory)
-                .readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
+                .readNetworkStatsDetail(eq(UID_ALL), aryEq(ifaces), eq(TAG_ALL));
 
         // also include tethering details, since they are folded into UID
         doReturn(tetherStatsParcels).when(mNetd).tetherGetStats();