From 1cb92c713f5b007c54ddf18a617605108fb5ed04 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 6 Mar 2018 12:36:54 +0900 Subject: [PATCH] Add method to NetworkStatsService for UID stats. Useful for clients such as BatteryStats which currently rely on NetworkStatsFactory. Data at that stage is incomplete as it does not account for tethering, VT data and corresponding 464xlat corrections. Test: runtest frameworks-net, CTS tests pass. Change-Id: I763b77f601c827fd2963204694fb5b45425cc791 --- .../android/server/ConnectivityService.java | 1 - .../java/android/net/NetworkStatsTest.java | 132 ++++++++++++++++++ .../internal/net/NetworkStatsFactoryTest.java | 4 +- .../server/net/NetworkStatsServiceTest.java | 95 ++++++++++++- 4 files changed, 228 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6c24e947c9..c04424266e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5268,7 +5268,6 @@ public class ConnectivityService extends IConnectivityManager.Stub for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) { final String stackedIface = stacked.getInterfaceName(); bs.noteNetworkInterfaceType(stackedIface, type); - NetworkStatsFactory.noteStackedIface(stackedIface, baseIface); } } catch (RemoteException ignored) { } diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index 035a4cd760..0530a86f4e 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -19,6 +19,7 @@ package android.net; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; +import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.METERED_NO; import static android.net.NetworkStats.METERED_YES; @@ -31,6 +32,7 @@ import static android.net.NetworkStats.SET_DBG_VPN_IN; import static android.net.NetworkStats.SET_DBG_VPN_OUT; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static org.junit.Assert.assertEquals; @@ -641,6 +643,136 @@ public class NetworkStatsTest { ROAMING_ALL, DEFAULT_NETWORK_ALL, 50500L, 27L, 100200L, 55, 0); } + @Test + public void testFilter_NoFilter() { + NetworkStats.Entry entry1 = new NetworkStats.Entry( + "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry3 = new NetworkStats.Entry( + "test2", 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 3) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3); + + stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL); + assertEquals(3, stats.size()); + assertEquals(entry1, stats.getValues(0, null)); + assertEquals(entry2, stats.getValues(1, null)); + assertEquals(entry3, stats.getValues(2, null)); + } + + @Test + public void testFilter_UidFilter() { + final int testUid = 10101; + NetworkStats.Entry entry1 = new NetworkStats.Entry( + "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "test2", testUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry3 = new NetworkStats.Entry( + "test2", testUid, SET_DEFAULT, 123, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 3) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3); + + stats.filter(testUid, INTERFACES_ALL, TAG_ALL); + assertEquals(2, stats.size()); + assertEquals(entry2, stats.getValues(0, null)); + assertEquals(entry3, stats.getValues(1, null)); + } + + @Test + public void testFilter_InterfaceFilter() { + final String testIf1 = "testif1"; + final String testIf2 = "testif2"; + NetworkStats.Entry entry1 = new NetworkStats.Entry( + testIf1, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "otherif", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry3 = new NetworkStats.Entry( + testIf1, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry4 = new NetworkStats.Entry( + testIf2, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 4) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3) + .addValues(entry4); + + stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL); + assertEquals(3, stats.size()); + assertEquals(entry1, stats.getValues(0, null)); + assertEquals(entry3, stats.getValues(1, null)); + assertEquals(entry4, stats.getValues(2, null)); + } + + @Test + public void testFilter_EmptyInterfaceFilter() { + NetworkStats.Entry entry1 = new NetworkStats.Entry( + "if1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "if2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 3) + .addValues(entry1) + .addValues(entry2); + + stats.filter(UID_ALL, new String[] { }, TAG_ALL); + assertEquals(0, stats.size()); + } + + @Test + public void testFilter_TagFilter() { + final int testTag = 123; + final int otherTag = 456; + NetworkStats.Entry entry1 = new NetworkStats.Entry( + "test1", 10100, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "test2", 10101, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry3 = new NetworkStats.Entry( + "test2", 10101, SET_DEFAULT, otherTag, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 3) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3); + + stats.filter(UID_ALL, INTERFACES_ALL, testTag); + assertEquals(2, stats.size()); + assertEquals(entry1, stats.getValues(0, null)); + assertEquals(entry2, stats.getValues(1, null)); + } + private static void assertContains(NetworkStats stats, String iface, int uid, int set, int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java index b14f5509b7..fc46b9c859 100644 --- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java +++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java @@ -184,7 +184,7 @@ public class NetworkStatsFactoryTest { assertStatsEntry(stats, "dummy0", 0, SET_DEFAULT, 0x0, 0L, 168L); assertStatsEntry(stats, "lo", 0, SET_DEFAULT, 0x0, 1288L, 1288L); - NetworkStatsFactory.noteStackedIface("v4-wlan0", null); + NetworkStatsFactory.clearStackedIfaces(); } @Test @@ -212,7 +212,7 @@ public class NetworkStatsFactoryTest { assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L); assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 647587L); - NetworkStatsFactory.noteStackedIface("v4-wlan0", null); + NetworkStatsFactory.clearStackedIfaces(); } /** diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 47c3455409..17ca651b84 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -25,6 +25,7 @@ import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.METERED_NO; import static android.net.NetworkStats.METERED_YES; @@ -58,6 +59,9 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -95,6 +99,7 @@ import android.util.Log; import android.util.TrustedTime; import com.android.internal.net.VpnInfo; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.server.net.NetworkStatsService.NetworkStatsSettings; import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config; @@ -667,6 +672,94 @@ public class NetworkStatsServiceTest { DEFAULT_NETWORK_YES, 1024L, 8L, 512L, 4L, 0); } + @Test + public void testDetailedUidStats() throws Exception { + // pretend that network comes online + expectDefaultSettings(); + expectNetworkState(buildWifiState()); + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces(NETWORKS_WIFI); + + NetworkStats.Entry entry1 = new NetworkStats.Entry( + TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L); + NetworkStats.Entry entry2 = new NetworkStats.Entry( + TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 50L, 5L, 50L, 5L, 0L); + NetworkStats.Entry entry3 = new NetworkStats.Entry( + TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xBEEF, 1024L, 8L, 512L, 4L, 0L); + + incrementCurrentTime(HOUR_IN_MILLIS); + expectDefaultSettings(); + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3)); + mService.incrementOperationCount(UID_RED, 0xF00D, 1); + + NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL); + + assertEquals(3, stats.size()); + entry1.operations = 1; + assertEquals(entry1, stats.getValues(0, null)); + entry2.operations = 1; + assertEquals(entry2, stats.getValues(1, null)); + assertEquals(entry3, stats.getValues(2, null)); + } + + @Test + public void testDetailedUidStats_Filtered() throws Exception { + // pretend that network comes online + expectDefaultSettings(); + + final String stackedIface = "stacked-test0"; + final LinkProperties stackedProp = new LinkProperties(); + stackedProp.setInterfaceName(stackedIface); + final NetworkState wifiState = buildWifiState(); + wifiState.linkProperties.addStackedLink(stackedProp); + expectNetworkState(wifiState); + + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces(NETWORKS_WIFI); + + NetworkStats.Entry uidStats = new NetworkStats.Entry( + TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L); + // Stacked on matching interface + NetworkStats.Entry tetheredStats1 = new NetworkStats.Entry( + stackedIface, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L); + // Different interface + NetworkStats.Entry tetheredStats2 = new NetworkStats.Entry( + "otherif", UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L); + + final String[] ifaceFilter = new String[] { TEST_IFACE }; + incrementCurrentTime(HOUR_IN_MILLIS); + expectDefaultSettings(); + expectNetworkStatsSummary(buildEmptyStats()); + when(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL), any())) + .thenReturn(new NetworkStats(getElapsedRealtime(), 1) + .addValues(uidStats)); + when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)) + .thenReturn(new NetworkStats(getElapsedRealtime(), 2) + .addValues(tetheredStats1) + .addValues(tetheredStats2)); + + NetworkStats stats = mService.getDetailedUidStats(ifaceFilter); + + verify(mNetManager, times(1)).getNetworkStatsUidDetail(eq(UID_ALL), argThat(ifaces -> + ifaces != null && ifaces.length == 2 + && ArrayUtils.contains(ifaces, TEST_IFACE) + && ArrayUtils.contains(ifaces, stackedIface))); + + assertEquals(2, stats.size()); + assertEquals(uidStats, stats.getValues(0, null)); + assertEquals(tetheredStats1, stats.getValues(1, null)); + } + @Test public void testForegroundBackground() throws Exception { // pretend that network comes online @@ -1056,7 +1149,7 @@ public class NetworkStatsServiceTest { private void expectNetworkStatsUidDetail(NetworkStats detail, NetworkStats tetherStats) throws Exception { - when(mNetManager.getNetworkStatsUidDetail(UID_ALL)).thenReturn(detail); + when(mNetManager.getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL)).thenReturn(detail); // also include tethering details, since they are folded into UID when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)).thenReturn(tetherStats);