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

Commit 6bd13af4 authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN Committed by Gerrit Code Review
Browse files

Merge "Allow null subscriberId in NetworkStatsManager."

parents be04ebd7 489e8b02
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.IntArray;
import android.util.Log;

@@ -98,9 +97,8 @@ public final class NetworkStats implements AutoCloseable {

    /** @hide */
    NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp,
            long endTimestamp) throws RemoteException, SecurityException {
        final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
            long endTimestamp, INetworkStatsService statsService)
            throws RemoteException, SecurityException {
        // Open network stats session
        mSession = statsService.openSessionForUsageStats(flags, context.getOpPackageName());
        mCloseGuard.open("close");
+25 −15
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

/**
 * Provides access to network usage history and statistics. Usage data is collected in
 * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
@@ -107,9 +109,15 @@ public class NetworkStatsManager {
     * {@hide}
     */
    public NetworkStatsManager(Context context) throws ServiceNotFoundException {
        this(context, INetworkStatsService.Stub.asInterface(
                ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)));
    }

    /** @hide */
    @VisibleForTesting
    public NetworkStatsManager(Context context, INetworkStatsService service) {
        mContext = context;
        mService = INetworkStatsService.Stub.asInterface(
                ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE));
        mService = service;
        setPollOnOpen(true);
    }

@@ -135,7 +143,8 @@ public class NetworkStatsManager {
    public Bucket querySummaryForDevice(NetworkTemplate template,
            long startTime, long endTime) throws SecurityException, RemoteException {
        Bucket bucket = null;
        NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime);
        NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime,
                mService);
        bucket = stats.getDeviceSummaryForNetwork();

        stats.close();
@@ -208,7 +217,7 @@ public class NetworkStatsManager {
        }

        NetworkStats stats;
        stats = new NetworkStats(mContext, template, mFlags, startTime, endTime);
        stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
        stats.startSummaryEnumeration();

        stats.close();
@@ -245,7 +254,7 @@ public class NetworkStatsManager {
        }

        NetworkStats result;
        result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
        result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
        result.startSummaryEnumeration();

        return result;
@@ -295,7 +304,7 @@ public class NetworkStatsManager {

        NetworkStats result;
        try {
            result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
            result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
            result.startHistoryEnumeration(uid, tag);
        } catch (RemoteException e) {
            Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e);
@@ -341,7 +350,7 @@ public class NetworkStatsManager {
        }

        NetworkStats result;
        result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
        result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
        result.startUserUidEnumeration();
        return result;
    }
@@ -451,20 +460,21 @@ public class NetworkStatsManager {
    }

    private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
        NetworkTemplate template = null;
        final NetworkTemplate template;
        switch (networkType) {
            case ConnectivityManager.TYPE_MOBILE: {
                template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
                } break;
            case ConnectivityManager.TYPE_WIFI: {
            case ConnectivityManager.TYPE_MOBILE:
                template = subscriberId == null
                        ? NetworkTemplate.buildTemplateMobileWildcard()
                        : NetworkTemplate.buildTemplateMobileAll(subscriberId);
                break;
            case ConnectivityManager.TYPE_WIFI:
                template = NetworkTemplate.buildTemplateWifiWildcard();
                } break;
            default: {
                break;
            default:
                throw new IllegalArgumentException("Cannot create template for network type "
                        + networkType + ", subscriberId '"
                        + NetworkIdentity.scrubSubscriberId(subscriberId) + "'.");
        }
        }
        return template;
    }

+213 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.app.usage;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.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.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.times;
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;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.os.RemoteException;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkStatsManagerTest {

    private @Mock INetworkStatsService mService;
    private @Mock INetworkStatsSession mStatsSession;

    private NetworkStatsManager mManager;

    // TODO: change to NetworkTemplate.MATCH_MOBILE once internal constant rename is merged to aosp.
    private static final int MATCH_MOBILE_ALL = 1;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mManager = new NetworkStatsManager(InstrumentationRegistry.getContext(), mService);
    }

    @Test
    public void testQueryDetails() throws RemoteException {
        final String subscriberId = "subid";
        final long startTime = 1;
        final long endTime = 100;
        final int uid1 = 10001;
        final int uid2 = 10002;
        final int uid3 = 10003;

        Entry uid1Entry1 = new Entry("if1", uid1,
                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
                100, 10, 200, 20, 0);

        Entry uid1Entry2 = new Entry(
                "if2", uid1,
                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
                100, 10, 200, 20, 0);

        Entry uid2Entry1 = new Entry("if1", uid2,
                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
                150, 10, 250, 20, 0);

        Entry uid2Entry2 = new Entry(
                "if2", uid2,
                android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
                150, 10, 250, 20, 0);

        NetworkStatsHistory history1 = new NetworkStatsHistory(10, 2);
        history1.recordData(10, 20, uid1Entry1);
        history1.recordData(20, 30, uid1Entry2);

        NetworkStatsHistory history2 = new NetworkStatsHistory(10, 2);
        history1.recordData(30, 40, uid2Entry1);
        history1.recordData(35, 45, uid2Entry2);


        when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
        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)))
                .then((InvocationOnMock inv) -> {
                    NetworkTemplate template = inv.getArgument(0);
                    assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
                    assertEquals(subscriberId, template.getSubscriberId());
                    return history1;
                });

        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)))
                .then((InvocationOnMock inv) -> {
                    NetworkTemplate template = inv.getArgument(0);
                    assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
                    assertEquals(subscriberId, template.getSubscriberId());
                    return history2;
                });


        NetworkStats stats = mManager.queryDetails(
                ConnectivityManager.TYPE_MOBILE, subscriberId, startTime, endTime);

        NetworkStats.Bucket bucket = new NetworkStats.Bucket();

        // First 2 buckets exactly match entry timings
        assertTrue(stats.getNextBucket(bucket));
        assertEquals(10, bucket.getStartTimeStamp());
        assertEquals(20, bucket.getEndTimeStamp());
        assertBucketMatches(uid1Entry1, bucket);

        assertTrue(stats.getNextBucket(bucket));
        assertEquals(20, bucket.getStartTimeStamp());
        assertEquals(30, bucket.getEndTimeStamp());
        assertBucketMatches(uid1Entry2, bucket);

        // 30 -> 40: contains uid2Entry1 and half of uid2Entry2
        assertTrue(stats.getNextBucket(bucket));
        assertEquals(30, bucket.getStartTimeStamp());
        assertEquals(40, bucket.getEndTimeStamp());
        assertEquals(225, bucket.getRxBytes());
        assertEquals(15, bucket.getRxPackets());
        assertEquals(375, bucket.getTxBytes());
        assertEquals(30, bucket.getTxPackets());

        // 40 -> 50: contains half of uid2Entry2
        assertTrue(stats.getNextBucket(bucket));
        assertEquals(40, bucket.getStartTimeStamp());
        assertEquals(50, bucket.getEndTimeStamp());
        assertEquals(75, bucket.getRxBytes());
        assertEquals(5, bucket.getRxPackets());
        assertEquals(125, bucket.getTxBytes());
        assertEquals(10, bucket.getTxPackets());

        assertFalse(stats.hasNextBucket());
    }

    @Test
    public void testQueryDetails_NoSubscriberId() throws RemoteException {
        final long startTime = 1;
        final long endTime = 100;
        final int uid1 = 10001;
        final int uid2 = 10002;

        when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
        when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2 });

        NetworkStats stats = mManager.queryDetails(
                ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);

        when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
                anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()))
                .thenReturn(new NetworkStatsHistory(10, 0));

        verify(mStatsSession, times(1)).getHistoryIntervalForUid(
                argThat((NetworkTemplate t) ->
                        // No subscriberId: MATCH_MOBILE_WILDCARD template
                        t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
                eq(uid1), eq(android.net.NetworkStats.SET_ALL),
                eq(android.net.NetworkStats.TAG_NONE),
                eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));

        verify(mStatsSession, times(1)).getHistoryIntervalForUid(
                argThat((NetworkTemplate t) ->
                        // No subscriberId: MATCH_MOBILE_WILDCARD template
                        t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
                eq(uid2), eq(android.net.NetworkStats.SET_ALL),
                eq(android.net.NetworkStats.TAG_NONE),
                eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));

        assertFalse(stats.hasNextBucket());
    }

    private void assertBucketMatches(Entry expected,
            NetworkStats.Bucket actual) {
        assertEquals(expected.uid, actual.getUid());
        assertEquals(expected.rxBytes, actual.getRxBytes());
        assertEquals(expected.rxPackets, actual.getRxPackets());
        assertEquals(expected.txBytes, actual.getTxBytes());
        assertEquals(expected.txPackets, actual.getTxPackets());
    }
}