Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7df0c6b authored by Benedict Wong's avatar Benedict Wong Committed by android-build-merger
Browse files

Revert "NetworkStatsService: Fix getDetailedUidStats to take VPNs into account." am: 055992b1

am: 9b8282b7

Change-Id: I799bbaed92dfce20690ae5a8b59241d22e5dc6d6
parents 6129295e 9b8282b7
Loading
Loading
Loading
Loading
+9 −20
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import libcore.util.EmptyArray;
import java.io.CharArrayWriter;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.function.Predicate;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
@@ -995,33 +994,23 @@ public class NetworkStats implements Parcelable {
        if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) {
            return;
        }
        filter(e -> (limitUid == UID_ALL || limitUid == e.uid)
            && (limitTag == TAG_ALL || limitTag == e.tag)
            && (limitIfaces == INTERFACES_ALL
                    || ArrayUtils.contains(limitIfaces, e.iface)));
    }

    /**
     * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}.
     *
     * <p>This mutates the original structure in place.
     */
    public void filterDebugEntries() {
        filter(e -> e.set < SET_DEBUG_START);
    }

    private void filter(Predicate<Entry> predicate) {
        Entry entry = new Entry();
        int nextOutputEntry = 0;
        for (int i = 0; i < size; i++) {
            entry = getValues(i, entry);
            if (predicate.test(entry)) {
                if (nextOutputEntry != i) {
            final boolean matches =
                    (limitUid == UID_ALL || limitUid == entry.uid)
                    && (limitTag == TAG_ALL || limitTag == entry.tag)
                    && (limitIfaces == INTERFACES_ALL
                            || ArrayUtils.contains(limitIfaces, entry.iface));

            if (matches) {
                setValues(nextOutputEntry, entry);
                }
                nextOutputEntry++;
            }
        }

        size = nextOutputEntry;
    }

+0 −4
Original line number Diff line number Diff line
@@ -263,10 +263,6 @@ public class NetworkStatsFactory {
        return stats;
    }

    /**
     * @deprecated Use NetworkStatsService#getDetailedUidStats which also accounts for
     * VPN traffic
     */
    public NetworkStats readNetworkStatsDetail() throws IOException {
        return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
    }
+1 −69
Original line number Diff line number Diff line
@@ -293,22 +293,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
    /** Data layer operation counters for splicing into other structures. */
    private NetworkStats mUidOperations = new NetworkStats(0L, 10);

    /**
     * Snapshot containing most recent network stats for all UIDs across all interfaces and tags
     * since boot.
     *
     * <p>Maintains migrated VPN stats which are result of performing TUN migration on {@link
     * #mLastUidDetailSnapshot}.
     */
    @GuardedBy("mStatsLock")
    private NetworkStats mTunAdjustedStats;
    /**
     * Used by {@link #mTunAdjustedStats} to migrate VPN traffic over delta between this snapshot
     * and latest snapshot.
     */
    @GuardedBy("mStatsLock")
    private NetworkStats mLastUidDetailSnapshot;

    /** Must be set in factory by calling #setHandler. */
    private Handler mHandler;
    private Handler.Callback mHandlerCallback;
@@ -828,39 +812,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
    @Override
    public NetworkStats getDetailedUidStats(String[] requiredIfaces) {
        try {
            // Get the latest snapshot from NetworkStatsFactory.
            // TODO: Querying for INTERFACES_ALL may incur performance penalty. Consider restricting
            // this to limited set of ifaces.
            NetworkStats uidDetailStats = getNetworkStatsUidDetail(INTERFACES_ALL);

            // Migrate traffic from VPN UID over delta and update mTunAdjustedStats.
            NetworkStats result;
            synchronized (mStatsLock) {
                migrateTunTraffic(uidDetailStats, mVpnInfos);
                result = mTunAdjustedStats.clone();
            }

            // Apply filter based on ifacesToQuery.
            final String[] ifacesToQuery =
                    NetworkStatsFactory.augmentWithStackedInterfaces(requiredIfaces);
            result.filter(UID_ALL, ifacesToQuery, TAG_ALL);
            return result;
            return getNetworkStatsUidDetail(ifacesToQuery);
        } catch (RemoteException e) {
            Log.wtf(TAG, "Error compiling UID stats", e);
            return new NetworkStats(0L, 0);
        }
    }

    @VisibleForTesting
    NetworkStats getTunAdjustedStats() {
        synchronized (mStatsLock) {
            if (mTunAdjustedStats == null) {
                return null;
            }
            return mTunAdjustedStats.clone();
        }
    }

    @Override
    public String[] getMobileIfaces() {
        return mMobileIfaces;
@@ -1335,34 +1295,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
        // a race condition between the service handler thread and the observer's
        mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces),
                new ArrayMap<>(mActiveUidIfaces), vpnArray, currentTime);

        migrateTunTraffic(uidSnapshot, vpnArray);
    }

    /**
     * Updates {@link #mTunAdjustedStats} with the delta containing traffic migrated off of VPNs.
     */
    @GuardedBy("mStatsLock")
    private void migrateTunTraffic(NetworkStats uidDetailStats, VpnInfo[] vpnInfoArray) {
        if (mTunAdjustedStats == null) {
            // Either device booted or system server restarted, hence traffic cannot be migrated
            // correctly without knowing the past state of VPN's underlying networks.
            mTunAdjustedStats = uidDetailStats;
            mLastUidDetailSnapshot = uidDetailStats;
            return;
        }
        // Migrate delta traffic from VPN to other apps.
        NetworkStats delta = uidDetailStats.subtract(mLastUidDetailSnapshot);
        for (VpnInfo info : vpnInfoArray) {
            delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces);
        }
        // Filter out debug entries as that may lead to over counting.
        delta.filterDebugEntries();
        // Update #mTunAdjustedStats with migrated delta.
        mTunAdjustedStats.combineAllValues(delta);
        mTunAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime());
        // Update last snapshot.
        mLastUidDetailSnapshot = uidDetailStats;
    }

    /**
+0 −31
Original line number Diff line number Diff line
@@ -812,37 +812,6 @@ public class NetworkStatsTest {
        assertEquals(entry2, stats.getValues(1, null));
    }

    @Test
    public void testFilterDebugEntries() {
        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_DBG_VPN_IN, TAG_NONE, METERED_NO, ROAMING_NO,
                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);

        NetworkStats.Entry entry3 = new NetworkStats.Entry(
                "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
                DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);

        NetworkStats.Entry entry4 = new NetworkStats.Entry(
                "test2", 10101, SET_DBG_VPN_OUT, TAG_NONE, 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.filterDebugEntries();

        assertEquals(2, stats.size());
        assertEquals(entry1, stats.getValues(0, null));
        assertEquals(entry3, stats.getValues(1, null));
    }

    @Test
    public void testApply464xlatAdjustments() {
        final String v4Iface = "v4-wlan0";
+6 −142
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_PO

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -217,16 +216,11 @@ public class NetworkStatsServiceTest {
        expectNetworkStatsUidDetail(buildEmptyStats());
        expectSystemReady();

        assertNull(mService.getTunAdjustedStats());
        mService.systemReady();
        // Verify that system ready fetches realtime stats and initializes tun adjusted stats.
        verify(mNetManager).getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL);
        assertNotNull("failed to initialize TUN adjusted stats", mService.getTunAdjustedStats());
        assertEquals(0, mService.getTunAdjustedStats().size());

        mSession = mService.openSession();
        assertNotNull("openSession() failed", mSession);


        // catch INetworkManagementEventObserver during systemReady()
        ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
              ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
@@ -739,13 +733,11 @@ public class NetworkStatsServiceTest {

        NetworkStats stats = mService.getDetailedUidStats(ifaceFilter);

        // mNetManager#getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL) has following invocations:
        // 1) NetworkStatsService#systemReady from #setUp.
        // 2) mService#forceUpdateIfaces in the test above.
        // 3) Finally, mService#getDetailedUidStats.
        verify(mNetManager, times(3)).getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL);
        assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), TEST_IFACE));
        assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), stackedIface));
        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));
@@ -1165,134 +1157,6 @@ public class NetworkStatsServiceTest {
        assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1100L, 100L, 1100L, 100L, 1);
    }

    @Test
    public void recordSnapshot_migratesTunTrafficAndUpdatesTunAdjustedStats() throws Exception {
        assertEquals(0, mService.getTunAdjustedStats().size());
        // VPN using WiFi (TEST_IFACE).
        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
        expectBandwidthControlCheck();
        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
        // overhead per packet):
        // 1000 bytes (100 packets) were downloaded by UID_RED over VPN.
        // VPN received 1100 bytes (100 packets) over WiFi.
        incrementCurrentTime(HOUR_IN_MILLIS);
        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
              .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L)
              .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L));

        // this should lead to NSS#recordSnapshotLocked
        mService.forceUpdateIfaces(
                new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */);

        // Verify TUN adjusted stats have traffic migrated correctly.
        // Of 1100 bytes VPN received over WiFi, expect 1000 bytes attributed to UID_RED and 100
        // bytes attributed to UID_VPN.
        NetworkStats tunAdjStats = mService.getTunAdjustedStats();
        assertValues(
                tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0);
        assertValues(
                tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0);
    }

    @Test
    public void getDetailedUidStats_migratesTunTrafficAndUpdatesTunAdjustedStats()
            throws Exception {
        assertEquals(0, mService.getTunAdjustedStats().size());
        // VPN using WiFi (TEST_IFACE).
        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
        expectBandwidthControlCheck();
        mService.forceUpdateIfaces(
                new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */);
        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
        // overhead per packet):
        // 1000 bytes (100 packets) were downloaded by UID_RED over VPN.
        // VPN received 1100 bytes (100 packets) over WiFi.
        incrementCurrentTime(HOUR_IN_MILLIS);
        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
              .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L)
              .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L));

        mService.getDetailedUidStats(INTERFACES_ALL);

        // Verify internally maintained TUN adjusted stats
        NetworkStats tunAdjStats = mService.getTunAdjustedStats();
        // Verify stats for TEST_IFACE (WiFi):
        // Of 1100 bytes VPN received over WiFi, expect 1000 bytes attributed to UID_RED and 100
        // bytes attributed to UID_VPN.
        assertValues(
                tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0);
        assertValues(
                tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0);
        // Verify stats for TUN_IFACE; only UID_RED should have usage on it.
        assertValues(
                tunAdjStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0);
        assertValues(
                tunAdjStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 0L, 0L, 0L, 0L, 0);

        // lets assume that since last time, VPN received another 1100 bytes (same assumptions as
        // before i.e. UID_RED downloaded another 1000 bytes).
        incrementCurrentTime(HOUR_IN_MILLIS);
        // Note - NetworkStatsFactory returns counters that are monotonically increasing.
        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
              .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 0L, 0L, 0L)
              .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 2200L, 200L, 0L, 0L, 0L));

        mService.getDetailedUidStats(INTERFACES_ALL);

        tunAdjStats = mService.getTunAdjustedStats();
        // verify TEST_IFACE stats:
        assertValues(
                tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 2000L, 200L, 0L, 0L, 0);
        assertValues(
                tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 200L, 0L, 0L, 0L, 0);
        // verify TUN_IFACE stats:
        assertValues(
                tunAdjStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 2000L, 200L, 0L, 0L, 0);
        assertValues(
                tunAdjStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 0L, 0L, 0L, 0L, 0);
    }

    @Test
    public void getDetailedUidStats_returnsCorrectStatsWithVpnRunning() throws Exception {
        // VPN using WiFi (TEST_IFACE).
        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
        expectBandwidthControlCheck();
        mService.forceUpdateIfaces(
                new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */);
        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
        // overhead per packet):
        // 1000 bytes (100 packets) were downloaded by UID_RED over VPN.
        // VPN received 1100 bytes (100 packets) over WiFi.
        incrementCurrentTime(HOUR_IN_MILLIS);
        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
              .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L)
              .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L));

        // Query realtime stats for TEST_IFACE.
        NetworkStats queriedStats =
                mService.getDetailedUidStats(new String[] {TEST_IFACE});

        assertEquals(HOUR_IN_MILLIS, queriedStats.getElapsedRealtime());
        // verify that returned stats are only for TEST_IFACE and VPN traffic is migrated correctly.
        assertEquals(new String[] {TEST_IFACE}, queriedStats.getUniqueIfaces());
        assertValues(
                queriedStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0);
        assertValues(
                queriedStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
                DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0);
    }

    @Test
    public void testRegisterUsageCallback() throws Exception {
        // pretend that wifi network comes online; service should ask about full