1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.app.usage; 18 19 import static junit.framework.Assert.assertEquals; 20 import static junit.framework.Assert.assertFalse; 21 import static junit.framework.Assert.assertTrue; 22 23 import static org.mockito.ArgumentMatchers.any; 24 import static org.mockito.ArgumentMatchers.anyInt; 25 import static org.mockito.ArgumentMatchers.anyLong; 26 import static org.mockito.ArgumentMatchers.anyString; 27 import static org.mockito.ArgumentMatchers.eq; 28 import static org.mockito.Mockito.reset; 29 import static org.mockito.Mockito.times; 30 import static org.mockito.Mockito.verify; 31 import static org.mockito.Mockito.when; 32 33 import android.net.ConnectivityManager; 34 import android.net.INetworkStatsService; 35 import android.net.INetworkStatsSession; 36 import android.net.NetworkStats.Entry; 37 import android.net.NetworkStatsHistory; 38 import android.net.NetworkTemplate; 39 import android.os.Build; 40 import android.os.RemoteException; 41 42 import androidx.test.InstrumentationRegistry; 43 import androidx.test.filters.SmallTest; 44 45 import com.android.testutils.DevSdkIgnoreRule; 46 import com.android.testutils.DevSdkIgnoreRunner; 47 48 import org.junit.Before; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 import org.mockito.Mock; 52 import org.mockito.MockitoAnnotations; 53 import org.mockito.invocation.InvocationOnMock; 54 55 @RunWith(DevSdkIgnoreRunner.class) 56 @SmallTest 57 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) 58 public class NetworkStatsManagerTest { 59 private static final String TEST_SUBSCRIBER_ID = "subid"; 60 61 private @Mock INetworkStatsService mService; 62 private @Mock INetworkStatsSession mStatsSession; 63 64 private NetworkStatsManager mManager; 65 66 // TODO: change to NetworkTemplate.MATCH_MOBILE once internal constant rename is merged to aosp. 67 private static final int MATCH_MOBILE_ALL = 1; 68 69 @Before setUp()70 public void setUp() { 71 MockitoAnnotations.initMocks(this); 72 mManager = new NetworkStatsManager(InstrumentationRegistry.getContext(), mService); 73 } 74 75 @Test testQueryDetails()76 public void testQueryDetails() throws RemoteException { 77 final long startTime = 1; 78 final long endTime = 100; 79 final int uid1 = 10001; 80 final int uid2 = 10002; 81 final int uid3 = 10003; 82 83 Entry uid1Entry1 = new Entry("if1", uid1, 84 android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE, 85 100, 10, 200, 20, 0); 86 87 Entry uid1Entry2 = new Entry( 88 "if2", uid1, 89 android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE, 90 100, 10, 200, 20, 0); 91 92 Entry uid2Entry1 = new Entry("if1", uid2, 93 android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE, 94 150, 10, 250, 20, 0); 95 96 Entry uid2Entry2 = new Entry( 97 "if2", uid2, 98 android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE, 99 150, 10, 250, 20, 0); 100 101 NetworkStatsHistory history1 = new NetworkStatsHistory(10, 2); 102 history1.recordData(10, 20, uid1Entry1); 103 history1.recordData(20, 30, uid1Entry2); 104 105 NetworkStatsHistory history2 = new NetworkStatsHistory(10, 2); 106 history1.recordData(30, 40, uid2Entry1); 107 history1.recordData(35, 45, uid2Entry2); 108 109 110 when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession); 111 when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2, uid3 }); 112 113 when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class), 114 eq(uid1), eq(android.net.NetworkStats.SET_ALL), 115 eq(android.net.NetworkStats.TAG_NONE), 116 eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime))) 117 .then((InvocationOnMock inv) -> { 118 NetworkTemplate template = inv.getArgument(0); 119 assertEquals(MATCH_MOBILE_ALL, template.getMatchRule()); 120 assertEquals(TEST_SUBSCRIBER_ID, template.getSubscriberId()); 121 return history1; 122 }); 123 124 when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class), 125 eq(uid2), eq(android.net.NetworkStats.SET_ALL), 126 eq(android.net.NetworkStats.TAG_NONE), 127 eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime))) 128 .then((InvocationOnMock inv) -> { 129 NetworkTemplate template = inv.getArgument(0); 130 assertEquals(MATCH_MOBILE_ALL, template.getMatchRule()); 131 assertEquals(TEST_SUBSCRIBER_ID, template.getSubscriberId()); 132 return history2; 133 }); 134 135 136 NetworkStats stats = mManager.queryDetails( 137 ConnectivityManager.TYPE_MOBILE, TEST_SUBSCRIBER_ID, startTime, endTime); 138 139 NetworkStats.Bucket bucket = new NetworkStats.Bucket(); 140 141 // First 2 buckets exactly match entry timings 142 assertTrue(stats.getNextBucket(bucket)); 143 assertEquals(10, bucket.getStartTimeStamp()); 144 assertEquals(20, bucket.getEndTimeStamp()); 145 assertBucketMatches(uid1Entry1, bucket); 146 147 assertTrue(stats.getNextBucket(bucket)); 148 assertEquals(20, bucket.getStartTimeStamp()); 149 assertEquals(30, bucket.getEndTimeStamp()); 150 assertBucketMatches(uid1Entry2, bucket); 151 152 // 30 -> 40: contains uid2Entry1 and half of uid2Entry2 153 assertTrue(stats.getNextBucket(bucket)); 154 assertEquals(30, bucket.getStartTimeStamp()); 155 assertEquals(40, bucket.getEndTimeStamp()); 156 assertEquals(225, bucket.getRxBytes()); 157 assertEquals(15, bucket.getRxPackets()); 158 assertEquals(375, bucket.getTxBytes()); 159 assertEquals(30, bucket.getTxPackets()); 160 161 // 40 -> 50: contains half of uid2Entry2 162 assertTrue(stats.getNextBucket(bucket)); 163 assertEquals(40, bucket.getStartTimeStamp()); 164 assertEquals(50, bucket.getEndTimeStamp()); 165 assertEquals(75, bucket.getRxBytes()); 166 assertEquals(5, bucket.getRxPackets()); 167 assertEquals(125, bucket.getTxBytes()); 168 assertEquals(10, bucket.getTxPackets()); 169 170 assertFalse(stats.hasNextBucket()); 171 } 172 runQueryDetailsAndCheckTemplate(int networkType, String subscriberId, NetworkTemplate expectedTemplate)173 private void runQueryDetailsAndCheckTemplate(int networkType, String subscriberId, 174 NetworkTemplate expectedTemplate) throws RemoteException { 175 final long startTime = 1; 176 final long endTime = 100; 177 final int uid1 = 10001; 178 final int uid2 = 10002; 179 180 reset(mStatsSession); 181 when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession); 182 when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2 }); 183 when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class), 184 anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyLong())) 185 .thenReturn(new NetworkStatsHistory(10, 0)); 186 NetworkStats stats = mManager.queryDetails( 187 networkType, subscriberId, startTime, endTime); 188 189 verify(mStatsSession, times(1)).getHistoryIntervalForUid( 190 eq(expectedTemplate), 191 eq(uid1), eq(android.net.NetworkStats.SET_ALL), 192 eq(android.net.NetworkStats.TAG_NONE), 193 eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)); 194 195 verify(mStatsSession, times(1)).getHistoryIntervalForUid( 196 eq(expectedTemplate), 197 eq(uid2), eq(android.net.NetworkStats.SET_ALL), 198 eq(android.net.NetworkStats.TAG_NONE), 199 eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)); 200 201 assertFalse(stats.hasNextBucket()); 202 } 203 204 @Test testNetworkTemplateWhenRunningQueryDetails_NoSubscriberId()205 public void testNetworkTemplateWhenRunningQueryDetails_NoSubscriberId() throws RemoteException { 206 runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_MOBILE, 207 null /* subscriberId */, NetworkTemplate.buildTemplateMobileWildcard()); 208 runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI, 209 "" /* subscriberId */, NetworkTemplate.buildTemplateWifiWildcard()); 210 runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI, 211 null /* subscriberId */, NetworkTemplate.buildTemplateWifiWildcard()); 212 } 213 214 @Test testNetworkTemplateWhenRunningQueryDetails_MergedCarrierWifi()215 public void testNetworkTemplateWhenRunningQueryDetails_MergedCarrierWifi() 216 throws RemoteException { 217 runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI, 218 TEST_SUBSCRIBER_ID, 219 NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL, 220 TEST_SUBSCRIBER_ID)); 221 } 222 assertBucketMatches(Entry expected, NetworkStats.Bucket actual)223 private void assertBucketMatches(Entry expected, NetworkStats.Bucket actual) { 224 assertEquals(expected.uid, actual.getUid()); 225 assertEquals(expected.rxBytes, actual.getRxBytes()); 226 assertEquals(expected.rxPackets, actual.getRxPackets()); 227 assertEquals(expected.txBytes, actual.getTxBytes()); 228 assertEquals(expected.txPackets, actual.getTxPackets()); 229 } 230 } 231