1 /* 2 * Copyright (C) 2017 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 com.android.networkstack.tethering; 18 19 import static android.net.NetworkStats.DEFAULT_NETWORK_NO; 20 import static android.net.NetworkStats.METERED_NO; 21 import static android.net.NetworkStats.ROAMING_NO; 22 import static android.net.NetworkStats.SET_DEFAULT; 23 import static android.net.NetworkStats.TAG_NONE; 24 import static android.net.NetworkStats.UID_ALL; 25 import static android.net.NetworkStats.UID_TETHERING; 26 import static android.net.RouteInfo.RTN_UNICAST; 27 import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; 28 29 import static com.android.modules.utils.build.SdkLevel.isAtLeastS; 30 import static com.android.modules.utils.build.SdkLevel.isAtLeastT; 31 import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE; 32 import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID; 33 import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; 34 import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0; 35 import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_1; 36 import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; 37 import static com.android.testutils.MiscAsserts.assertContainsAll; 38 import static com.android.testutils.MiscAsserts.assertThrows; 39 import static com.android.testutils.NetworkStatsUtilsKt.assertNetworkStatsEquals; 40 41 import static junit.framework.Assert.assertNotNull; 42 43 import static org.junit.Assert.assertEquals; 44 import static org.junit.Assert.assertTrue; 45 import static org.mockito.Matchers.any; 46 import static org.mockito.Matchers.anyLong; 47 import static org.mockito.Matchers.anyObject; 48 import static org.mockito.Matchers.anyString; 49 import static org.mockito.Matchers.eq; 50 import static org.mockito.Mockito.clearInvocations; 51 import static org.mockito.Mockito.inOrder; 52 import static org.mockito.Mockito.never; 53 import static org.mockito.Mockito.reset; 54 import static org.mockito.Mockito.times; 55 import static org.mockito.Mockito.verify; 56 import static org.mockito.Mockito.verifyNoMoreInteractions; 57 import static org.mockito.Mockito.when; 58 59 import android.annotation.NonNull; 60 import android.app.usage.NetworkStatsManager; 61 import android.content.Context; 62 import android.content.pm.ApplicationInfo; 63 import android.net.IpPrefix; 64 import android.net.LinkAddress; 65 import android.net.LinkProperties; 66 import android.net.NetworkStats; 67 import android.net.NetworkStats.Entry; 68 import android.net.RouteInfo; 69 import android.net.netstats.provider.NetworkStatsProvider; 70 import android.os.Build; 71 import android.os.Handler; 72 import android.os.test.TestLooper; 73 import android.provider.Settings; 74 import android.provider.Settings.SettingNotFoundException; 75 import android.test.mock.MockContentResolver; 76 77 import androidx.test.filters.SmallTest; 78 import androidx.test.runner.AndroidJUnit4; 79 80 import com.android.internal.util.test.FakeSettingsProvider; 81 import com.android.net.module.util.SharedLog; 82 import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback; 83 import com.android.testutils.DevSdkIgnoreRule; 84 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; 85 import com.android.testutils.TestableNetworkStatsProviderCbBinder; 86 87 import org.junit.After; 88 import org.junit.Before; 89 import org.junit.Rule; 90 import org.junit.Test; 91 import org.junit.runner.RunWith; 92 import org.mockito.ArgumentCaptor; 93 import org.mockito.InOrder; 94 import org.mockito.Mock; 95 import org.mockito.MockitoAnnotations; 96 97 import java.net.InetAddress; 98 import java.util.ArrayList; 99 import java.util.HashSet; 100 import java.util.Set; 101 102 @RunWith(AndroidJUnit4.class) 103 @SmallTest 104 public class OffloadControllerTest { 105 @Rule 106 public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); 107 108 private static final String RNDIS0 = "test_rndis0"; 109 private static final String RMNET0 = "test_rmnet_data0"; 110 private static final String WLAN0 = "test_wlan0"; 111 112 private static final String IPV6_LINKLOCAL = "fe80::/64"; 113 private static final String IPV6_DOC_PREFIX = "2001:db8::/64"; 114 private static final String IPV6_DISCARD_PREFIX = "100::/64"; 115 private static final String USB_PREFIX = "192.168.42.0/24"; 116 private static final String WIFI_PREFIX = "192.168.43.0/24"; 117 private static final long WAIT_FOR_IDLE_TIMEOUT = 2 * 1000; 118 119 @Mock private OffloadHardwareInterface mHardware; 120 @Mock private ApplicationInfo mApplicationInfo; 121 @Mock private Context mContext; 122 @Mock private NetworkStatsManager mStatsManager; 123 @Mock private TetheringConfiguration mTetherConfig; 124 // Late init since methods must be called by the thread that created this object. 125 private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb; 126 private OffloadController.OffloadTetheringStatsProvider mTetherStatsProvider; 127 private final ArgumentCaptor<ArrayList> mStringArrayCaptor = 128 ArgumentCaptor.forClass(ArrayList.class); 129 private final ArgumentCaptor<OffloadHalCallback> mOffloadHalCallbackCaptor = 130 ArgumentCaptor.forClass(OffloadHalCallback.class); 131 private MockContentResolver mContentResolver; 132 private final TestLooper mTestLooper = new TestLooper(); 133 private OffloadController.Dependencies mDeps = new OffloadController.Dependencies() { 134 @Override 135 public TetheringConfiguration getTetherConfig() { 136 return mTetherConfig; 137 } 138 }; 139 setUp()140 @Before public void setUp() { 141 MockitoAnnotations.initMocks(this); 142 when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo); 143 when(mContext.getPackageName()).thenReturn("OffloadControllerTest"); 144 mContentResolver = new MockContentResolver(mContext); 145 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); 146 when(mContext.getContentResolver()).thenReturn(mContentResolver); 147 FakeSettingsProvider.clearSettingsProvider(); 148 when(mTetherConfig.getOffloadPollInterval()).thenReturn(-1); // Disabled. 149 } 150 tearDown()151 @After public void tearDown() throws Exception { 152 FakeSettingsProvider.clearSettingsProvider(); 153 } 154 setupFunctioningHardwareInterface(int offloadHalVersion)155 private void setupFunctioningHardwareInterface(int offloadHalVersion) { 156 when(mHardware.initOffload(mOffloadHalCallbackCaptor.capture())) 157 .thenReturn(offloadHalVersion); 158 when(mHardware.setUpstreamParameters(anyString(), any(), any(), any())).thenReturn(true); 159 when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats()); 160 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); 161 when(mHardware.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(true); 162 } 163 enableOffload()164 private void enableOffload() { 165 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0); 166 } 167 setOffloadPollInterval(int interval)168 private void setOffloadPollInterval(int interval) { 169 when(mTetherConfig.getOffloadPollInterval()).thenReturn(interval); 170 } 171 waitForIdle()172 private void waitForIdle() { 173 mTestLooper.dispatchAll(); 174 } 175 makeOffloadController()176 private OffloadController makeOffloadController() throws Exception { 177 OffloadController offload = new OffloadController(new Handler(mTestLooper.getLooper()), 178 mHardware, mContentResolver, mStatsManager, new SharedLog("test"), mDeps); 179 final ArgumentCaptor<OffloadController.OffloadTetheringStatsProvider> 180 tetherStatsProviderCaptor = 181 ArgumentCaptor.forClass(OffloadController.OffloadTetheringStatsProvider.class); 182 verify(mStatsManager).registerNetworkStatsProvider(anyString(), 183 tetherStatsProviderCaptor.capture()); 184 reset(mStatsManager); 185 mTetherStatsProvider = tetherStatsProviderCaptor.getValue(); 186 assertNotNull(mTetherStatsProvider); 187 mTetherStatsProviderCb = new TestableNetworkStatsProviderCbBinder(); 188 mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb); 189 return offload; 190 } 191 192 @Test testStartStop()193 public void testStartStop() throws Exception { 194 stopOffloadController( 195 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/)); 196 stopOffloadController( 197 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_1, true /*expectStart*/)); 198 } 199 200 @NonNull startOffloadController(int controlVersion, boolean expectStart)201 private OffloadController startOffloadController(int controlVersion, boolean expectStart) 202 throws Exception { 203 setupFunctioningHardwareInterface(controlVersion); 204 final OffloadController offload = makeOffloadController(); 205 offload.start(); 206 207 final InOrder inOrder = inOrder(mHardware); 208 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled(); 209 inOrder.verify(mHardware, times(expectStart ? 1 : 0)).initOffload( 210 any(OffloadHalCallback.class)); 211 inOrder.verifyNoMoreInteractions(); 212 // Clear counters only instead of whole mock to preserve the mocking setup. 213 clearInvocations(mHardware); 214 return offload; 215 } 216 stopOffloadController(final OffloadController offload)217 private void stopOffloadController(final OffloadController offload) throws Exception { 218 final InOrder inOrder = inOrder(mHardware); 219 offload.stop(); 220 inOrder.verify(mHardware, times(1)).stopOffload(); 221 inOrder.verifyNoMoreInteractions(); 222 reset(mHardware); 223 } 224 225 @Test testNoSettingsValueDefaultDisabledDoesNotStart()226 public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception { 227 when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1); 228 assertThrows(SettingNotFoundException.class, () -> 229 Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED)); 230 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, false /*expectStart*/); 231 } 232 233 @Test testNoSettingsValueDefaultEnabledDoesStart()234 public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception { 235 when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0); 236 assertThrows(SettingNotFoundException.class, () -> 237 Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED)); 238 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); 239 } 240 241 @Test testSettingsAllowsStart()242 public void testSettingsAllowsStart() throws Exception { 243 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0); 244 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); 245 } 246 247 @Test testSettingsDisablesStart()248 public void testSettingsDisablesStart() throws Exception { 249 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1); 250 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, false /*expectStart*/); 251 } 252 253 @Test testSetUpstreamLinkPropertiesWorking()254 public void testSetUpstreamLinkPropertiesWorking() throws Exception { 255 enableOffload(); 256 final OffloadController offload = 257 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); 258 259 // In reality, the UpstreamNetworkMonitor would have passed down to us 260 // a covering set of local prefixes representing a minimum essential 261 // set plus all the prefixes on networks with network agents. 262 // 263 // We simulate that there, and then add upstream elements one by one 264 // and watch what happens. 265 final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>(); 266 for (String s : new String[]{ 267 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) { 268 minimumLocalPrefixes.add(new IpPrefix(s)); 269 } 270 offload.setLocalPrefixes(minimumLocalPrefixes); 271 final InOrder inOrder = inOrder(mHardware); 272 inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture()); 273 ArrayList<String> localPrefixes = mStringArrayCaptor.getValue(); 274 assertEquals(4, localPrefixes.size()); 275 assertContainsAll(localPrefixes, 276 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"); 277 inOrder.verifyNoMoreInteractions(); 278 279 offload.setUpstreamLinkProperties(null); 280 // No change in local addresses means no call to setLocalPrefixes(). 281 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 282 // This LinkProperties value does not differ from the default upstream. 283 // There should be no extraneous call to setUpstreamParameters(). 284 inOrder.verify(mHardware, never()).setUpstreamParameters( 285 anyObject(), anyObject(), anyObject(), anyObject()); 286 inOrder.verifyNoMoreInteractions(); 287 288 final LinkProperties lp = new LinkProperties(); 289 290 final String testIfName = "rmnet_data17"; 291 lp.setInterfaceName(testIfName); 292 offload.setUpstreamLinkProperties(lp); 293 // No change in local addresses means no call to setLocalPrefixes(). 294 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 295 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 296 eq(testIfName), eq(null), eq(null), eq(null)); 297 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 298 inOrder.verifyNoMoreInteractions(); 299 300 final String ipv4Addr = "192.0.2.5"; 301 final String linkAddr = ipv4Addr + "/24"; 302 lp.addLinkAddress(new LinkAddress(linkAddr)); 303 lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, null, RTN_UNICAST)); 304 offload.setUpstreamLinkProperties(lp); 305 // IPv4 prefixes and addresses on the upstream are simply left as whole 306 // prefixes (already passed in from UpstreamNetworkMonitor code). If a 307 // tethering client sends traffic to the IPv4 default router or other 308 // clients on the upstream this will not be hardware-forwarded, and that 309 // should be fine for now. Ergo: no change in local addresses, no call 310 // to setLocalPrefixes(). 311 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 312 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 313 eq(testIfName), eq(ipv4Addr), eq(null), eq(null)); 314 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 315 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 316 inOrder.verifyNoMoreInteractions(); 317 318 final String ipv4Gateway = "192.0.2.1"; 319 lp.addRoute(new RouteInfo(null, InetAddress.getByName(ipv4Gateway), null, RTN_UNICAST)); 320 offload.setUpstreamLinkProperties(lp); 321 // No change in local addresses means no call to setLocalPrefixes(). 322 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 323 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 324 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null)); 325 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 326 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 327 inOrder.verifyNoMoreInteractions(); 328 329 final String ipv6Gw1 = "fe80::cafe"; 330 lp.addRoute(new RouteInfo(null, InetAddress.getByName(ipv6Gw1), null, RTN_UNICAST)); 331 offload.setUpstreamLinkProperties(lp); 332 // No change in local addresses means no call to setLocalPrefixes(). 333 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 334 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 335 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture()); 336 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 337 ArrayList<String> v6gws = mStringArrayCaptor.getValue(); 338 assertEquals(1, v6gws.size()); 339 assertTrue(v6gws.contains(ipv6Gw1)); 340 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 341 inOrder.verifyNoMoreInteractions(); 342 343 final String ipv6Gw2 = "fe80::d00d"; 344 lp.addRoute(new RouteInfo(null, InetAddress.getByName(ipv6Gw2), null, RTN_UNICAST)); 345 offload.setUpstreamLinkProperties(lp); 346 // No change in local addresses means no call to setLocalPrefixes(). 347 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 348 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 349 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture()); 350 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 351 v6gws = mStringArrayCaptor.getValue(); 352 assertEquals(2, v6gws.size()); 353 assertTrue(v6gws.contains(ipv6Gw1)); 354 assertTrue(v6gws.contains(ipv6Gw2)); 355 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 356 inOrder.verifyNoMoreInteractions(); 357 358 final LinkProperties stacked = new LinkProperties(); 359 stacked.setInterfaceName("stacked"); 360 stacked.addLinkAddress(new LinkAddress("192.0.2.129/25")); 361 stacked.addRoute(new RouteInfo(null, InetAddress.getByName("192.0.2.254"), null, 362 RTN_UNICAST)); 363 stacked.addRoute(new RouteInfo(null, InetAddress.getByName("fe80::bad:f00"), null, 364 RTN_UNICAST)); 365 assertTrue(lp.addStackedLink(stacked)); 366 offload.setUpstreamLinkProperties(lp); 367 // No change in local addresses means no call to setLocalPrefixes(). 368 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 369 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 370 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture()); 371 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 372 v6gws = mStringArrayCaptor.getValue(); 373 assertEquals(2, v6gws.size()); 374 assertTrue(v6gws.contains(ipv6Gw1)); 375 assertTrue(v6gws.contains(ipv6Gw2)); 376 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 377 inOrder.verifyNoMoreInteractions(); 378 379 // Add in some IPv6 upstream info. When there is a tethered downstream 380 // making use of the IPv6 prefix we would expect to see the /64 route 381 // removed from "local prefixes" and /128s added for the upstream IPv6 382 // addresses. This is not yet implemented, and for now we simply 383 // expect to see these /128s. 384 lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64"), null, null, RTN_UNICAST)); 385 // "2001:db8::/64" plus "assigned" ASCII in hex 386 lp.addLinkAddress(new LinkAddress("2001:db8::6173:7369:676e:6564/64")); 387 // "2001:db8::/64" plus "random" ASCII in hex 388 lp.addLinkAddress(new LinkAddress("2001:db8::7261:6e64:6f6d/64")); 389 offload.setUpstreamLinkProperties(lp); 390 inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture()); 391 localPrefixes = mStringArrayCaptor.getValue(); 392 assertEquals(6, localPrefixes.size()); 393 assertContainsAll(localPrefixes, 394 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64", 395 "2001:db8::6173:7369:676e:6564/128", "2001:db8::7261:6e64:6f6d/128"); 396 // The relevant parts of the LinkProperties have not changed, but at the 397 // moment we do not de-dup upstream LinkProperties this carefully. 398 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 399 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture()); 400 v6gws = mStringArrayCaptor.getValue(); 401 assertEquals(2, v6gws.size()); 402 assertTrue(v6gws.contains(ipv6Gw1)); 403 assertTrue(v6gws.contains(ipv6Gw2)); 404 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 405 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 406 inOrder.verifyNoMoreInteractions(); 407 408 // Completely identical LinkProperties updates are de-duped. 409 offload.setUpstreamLinkProperties(lp); 410 // This LinkProperties value does not differ from the default upstream. 411 // There should be no extraneous call to setUpstreamParameters(). 412 inOrder.verify(mHardware, never()).setUpstreamParameters( 413 anyObject(), anyObject(), anyObject(), anyObject()); 414 inOrder.verifyNoMoreInteractions(); 415 } 416 buildTestEntry(@onNull OffloadController.StatsType how, @NonNull String iface, long rxBytes, long txBytes)417 private static @NonNull Entry buildTestEntry(@NonNull OffloadController.StatsType how, 418 @NonNull String iface, long rxBytes, long txBytes) { 419 return new Entry(iface, how == STATS_PER_IFACE ? UID_ALL : UID_TETHERING, SET_DEFAULT, 420 TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, 0L, 421 txBytes, 0L, 0L); 422 } 423 424 @Test testGetForwardedStats()425 public void testGetForwardedStats() throws Exception { 426 enableOffload(); 427 final OffloadController offload = 428 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); 429 430 final String ethernetIface = "eth1"; 431 final String mobileIface = "rmnet_data0"; 432 433 when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( 434 new ForwardedStats(12345, 54321)); 435 when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn( 436 new ForwardedStats(999, 99999)); 437 438 final InOrder inOrder = inOrder(mHardware); 439 440 final LinkProperties lp = new LinkProperties(); 441 lp.setInterfaceName(ethernetIface); 442 offload.setUpstreamLinkProperties(lp); 443 // Previous upstream was null, so no stats are fetched. 444 inOrder.verify(mHardware, never()).getForwardedStats(any()); 445 446 lp.setInterfaceName(mobileIface); 447 offload.setUpstreamLinkProperties(lp); 448 // Expect that we fetch stats from the previous upstream. 449 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(ethernetIface)); 450 451 lp.setInterfaceName(ethernetIface); 452 offload.setUpstreamLinkProperties(lp); 453 // Expect that we fetch stats from the previous upstream. 454 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(mobileIface)); 455 456 // Verify that the fetched stats are stored. 457 final NetworkStats ifaceStats = mTetherStatsProvider.getTetherStats(STATS_PER_IFACE); 458 final NetworkStats uidStats = mTetherStatsProvider.getTetherStats(STATS_PER_UID); 459 final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2) 460 .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) 461 .addEntry(buildTestEntry(STATS_PER_IFACE, ethernetIface, 12345, 54321)); 462 463 final NetworkStats expectedUidStats = new NetworkStats(0L, 2) 464 .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) 465 .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321)); 466 467 assertNetworkStatsEquals(expectedIfaceStats, ifaceStats); 468 assertNetworkStatsEquals(expectedUidStats, uidStats); 469 470 // Force pushing stats update to verify the stats reported. 471 mTetherStatsProvider.pushTetherStats(); 472 mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStats, expectedUidStats); 473 474 when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( 475 new ForwardedStats(100000, 100000)); 476 offload.setUpstreamLinkProperties(null); 477 // Expect that we first clear the HAL's upstream parameters. 478 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 479 eq(""), eq("0.0.0.0"), eq("0.0.0.0"), eq(null)); 480 // Expect that we fetch stats from the previous upstream. 481 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(ethernetIface)); 482 483 // There is no current upstream, so no stats are fetched. 484 inOrder.verify(mHardware, never()).getForwardedStats(any()); 485 inOrder.verifyNoMoreInteractions(); 486 487 // Verify that the stored stats is accumulated. 488 final NetworkStats ifaceStatsAccu = mTetherStatsProvider.getTetherStats(STATS_PER_IFACE); 489 final NetworkStats uidStatsAccu = mTetherStatsProvider.getTetherStats(STATS_PER_UID); 490 final NetworkStats expectedIfaceStatsAccu = new NetworkStats(0L, 2) 491 .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) 492 .addEntry(buildTestEntry(STATS_PER_IFACE, ethernetIface, 112345, 154321)); 493 494 final NetworkStats expectedUidStatsAccu = new NetworkStats(0L, 2) 495 .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) 496 .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321)); 497 498 assertNetworkStatsEquals(expectedIfaceStatsAccu, ifaceStatsAccu); 499 assertNetworkStatsEquals(expectedUidStatsAccu, uidStatsAccu); 500 501 // Verify that only diff of stats is reported. 502 mTetherStatsProvider.pushTetherStats(); 503 final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2) 504 .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0)) 505 .addEntry(buildTestEntry(STATS_PER_IFACE, ethernetIface, 100000, 100000)); 506 507 final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2) 508 .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0)) 509 .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000)); 510 mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStatsDiff, 511 expectedUidStatsDiff); 512 } 513 514 /** 515 * Test OffloadController with different combinations of HAL and framework versions can set 516 * data warning and/or limit correctly. 517 */ 518 @Test testSetDataWarningAndLimit()519 public void testSetDataWarningAndLimit() throws Exception { 520 // Verify the OffloadController is called by R framework, where the framework doesn't send 521 // warning. 522 // R only uses HAL 1.0. 523 checkSetDataWarningAndLimit(false, OFFLOAD_HAL_VERSION_HIDL_1_0); 524 // Verify the OffloadController is called by S+ framework, where the framework sends 525 // warning along with limit. 526 checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_HIDL_1_0); 527 checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_HIDL_1_1); 528 } 529 checkSetDataWarningAndLimit(boolean isProviderSetWarning, int controlVersion)530 private void checkSetDataWarningAndLimit(boolean isProviderSetWarning, int controlVersion) 531 throws Exception { 532 enableOffload(); 533 final OffloadController offload = 534 startOffloadController(controlVersion, true /*expectStart*/); 535 536 final String ethernetIface = "eth1"; 537 final String mobileIface = "rmnet_data0"; 538 final long ethernetLimit = 12345; 539 final long mobileWarning = 123456; 540 final long mobileLimit = 12345678; 541 542 final LinkProperties lp = new LinkProperties(); 543 lp.setInterfaceName(ethernetIface); 544 545 final InOrder inOrder = inOrder(mHardware); 546 when(mHardware.setUpstreamParameters( 547 any(), any(), any(), any())).thenReturn(true); 548 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); 549 when(mHardware.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(true); 550 offload.setUpstreamLinkProperties(lp); 551 // Applying an interface sends the initial quota to the hardware. 552 if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { 553 inOrder.verify(mHardware).setDataWarningAndLimit(ethernetIface, Long.MAX_VALUE, 554 Long.MAX_VALUE); 555 } else { 556 inOrder.verify(mHardware).setDataLimit(ethernetIface, Long.MAX_VALUE); 557 } 558 inOrder.verifyNoMoreInteractions(); 559 560 // Verify that set to unlimited again won't cause duplicated calls to the hardware. 561 if (isProviderSetWarning) { 562 mTetherStatsProvider.onSetWarningAndLimit(ethernetIface, 563 NetworkStatsProvider.QUOTA_UNLIMITED, NetworkStatsProvider.QUOTA_UNLIMITED); 564 } else { 565 mTetherStatsProvider.onSetLimit(ethernetIface, NetworkStatsProvider.QUOTA_UNLIMITED); 566 } 567 waitForIdle(); 568 inOrder.verifyNoMoreInteractions(); 569 570 // Applying an interface quota to the current upstream immediately sends it to the hardware. 571 if (isProviderSetWarning) { 572 mTetherStatsProvider.onSetWarningAndLimit(ethernetIface, 573 NetworkStatsProvider.QUOTA_UNLIMITED, ethernetLimit); 574 } else { 575 mTetherStatsProvider.onSetLimit(ethernetIface, ethernetLimit); 576 } 577 waitForIdle(); 578 if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { 579 inOrder.verify(mHardware).setDataWarningAndLimit(ethernetIface, Long.MAX_VALUE, 580 ethernetLimit); 581 } else { 582 inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit); 583 } 584 inOrder.verifyNoMoreInteractions(); 585 586 // Applying an interface quota to another upstream does not take any immediate action. 587 if (isProviderSetWarning) { 588 mTetherStatsProvider.onSetWarningAndLimit(mobileIface, mobileWarning, mobileLimit); 589 } else { 590 mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); 591 } 592 waitForIdle(); 593 if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { 594 inOrder.verify(mHardware, never()).setDataWarningAndLimit(anyString(), anyLong(), 595 anyLong()); 596 } else { 597 inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); 598 } 599 600 // Switching to that upstream causes the quota to be applied if the parameters were applied 601 // correctly. 602 lp.setInterfaceName(mobileIface); 603 offload.setUpstreamLinkProperties(lp); 604 waitForIdle(); 605 if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { 606 inOrder.verify(mHardware).setDataWarningAndLimit(mobileIface, 607 isProviderSetWarning ? mobileWarning : Long.MAX_VALUE, 608 mobileLimit); 609 } else { 610 inOrder.verify(mHardware).setDataLimit(mobileIface, mobileLimit); 611 } 612 613 // Setting a limit of NetworkStatsProvider.QUOTA_UNLIMITED causes the limit to be set 614 // to Long.MAX_VALUE. 615 if (isProviderSetWarning) { 616 mTetherStatsProvider.onSetWarningAndLimit(mobileIface, 617 NetworkStatsProvider.QUOTA_UNLIMITED, NetworkStatsProvider.QUOTA_UNLIMITED); 618 } else { 619 mTetherStatsProvider.onSetLimit(mobileIface, NetworkStatsProvider.QUOTA_UNLIMITED); 620 } 621 waitForIdle(); 622 if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { 623 inOrder.verify(mHardware).setDataWarningAndLimit(mobileIface, Long.MAX_VALUE, 624 Long.MAX_VALUE); 625 } else { 626 inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE); 627 } 628 629 // If setting upstream parameters fails, then the data warning and limit is not set. 630 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false); 631 lp.setInterfaceName(ethernetIface); 632 offload.setUpstreamLinkProperties(lp); 633 if (isProviderSetWarning) { 634 mTetherStatsProvider.onSetWarningAndLimit(mobileIface, mobileWarning, mobileLimit); 635 } else { 636 mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); 637 } 638 waitForIdle(); 639 inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); 640 inOrder.verify(mHardware, never()).setDataWarningAndLimit(anyString(), anyLong(), 641 anyLong()); 642 643 // If setting the data warning and/or limit fails while changing upstreams, offload is 644 // stopped. 645 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true); 646 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false); 647 when(mHardware.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(false); 648 lp.setInterfaceName(mobileIface); 649 offload.setUpstreamLinkProperties(lp); 650 if (isProviderSetWarning) { 651 mTetherStatsProvider.onSetWarningAndLimit(mobileIface, mobileWarning, mobileLimit); 652 } else { 653 mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); 654 } 655 waitForIdle(); 656 inOrder.verify(mHardware).getForwardedStats(ethernetIface); 657 inOrder.verify(mHardware).stopOffload(); 658 } 659 660 @Test testDataWarningAndLimitCallback_LimitReached()661 public void testDataWarningAndLimitCallback_LimitReached() throws Exception { 662 enableOffload(); 663 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); 664 665 final OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue(); 666 callback.onStoppedLimitReached(); 667 mTetherStatsProviderCb.expectNotifyStatsUpdated(); 668 669 if (isAtLeastT()) { 670 mTetherStatsProviderCb.expectNotifyLimitReached(); 671 } else if (isAtLeastS()) { 672 mTetherStatsProviderCb.expectNotifyWarningOrLimitReached(); 673 } else { 674 mTetherStatsProviderCb.expectNotifyLimitReached(); 675 } 676 } 677 678 @Test 679 @IgnoreUpTo(Build.VERSION_CODES.R) // HAL 1.1 is only supported from S testDataWarningAndLimitCallback_WarningReached()680 public void testDataWarningAndLimitCallback_WarningReached() throws Exception { 681 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_1, true /*expectStart*/); 682 final OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue(); 683 callback.onWarningReached(); 684 mTetherStatsProviderCb.expectNotifyStatsUpdated(); 685 686 if (isAtLeastT()) { 687 mTetherStatsProviderCb.expectNotifyWarningReached(); 688 } else { 689 mTetherStatsProviderCb.expectNotifyWarningOrLimitReached(); 690 } 691 } 692 693 @Test testAddRemoveDownstreams()694 public void testAddRemoveDownstreams() throws Exception { 695 enableOffload(); 696 final OffloadController offload = 697 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); 698 final InOrder inOrder = inOrder(mHardware); 699 700 // Tethering makes several calls to setLocalPrefixes() before add/remove 701 // downstream calls are made. This is not tested here; only the behavior 702 // of notifyDownstreamLinkProperties() and removeDownstreamInterface() 703 // are tested. 704 705 // [1] USB tethering is started. 706 final LinkProperties usbLinkProperties = new LinkProperties(); 707 usbLinkProperties.setInterfaceName(RNDIS0); 708 usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24")); 709 usbLinkProperties.addRoute( 710 new RouteInfo(new IpPrefix(USB_PREFIX), null, null, RTN_UNICAST)); 711 offload.notifyDownstreamLinkProperties(usbLinkProperties); 712 inOrder.verify(mHardware, times(1)).addDownstream(RNDIS0, USB_PREFIX); 713 inOrder.verifyNoMoreInteractions(); 714 715 // [2] Routes for IPv6 link-local prefixes should never be added. 716 usbLinkProperties.addRoute( 717 new RouteInfo(new IpPrefix(IPV6_LINKLOCAL), null, null, RTN_UNICAST)); 718 offload.notifyDownstreamLinkProperties(usbLinkProperties); 719 inOrder.verify(mHardware, never()).addDownstream(eq(RNDIS0), anyString()); 720 inOrder.verifyNoMoreInteractions(); 721 722 // [3] Add an IPv6 prefix for good measure. Only new offload-able 723 // prefixes should be passed to the HAL. 724 usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64")); 725 usbLinkProperties.addRoute( 726 new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, null, RTN_UNICAST)); 727 offload.notifyDownstreamLinkProperties(usbLinkProperties); 728 inOrder.verify(mHardware, times(1)).addDownstream(RNDIS0, IPV6_DOC_PREFIX); 729 inOrder.verifyNoMoreInteractions(); 730 731 // [4] Adding addresses doesn't affect notifyDownstreamLinkProperties(). 732 // The address is passed in by a separate setLocalPrefixes() invocation. 733 usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::2/64")); 734 offload.notifyDownstreamLinkProperties(usbLinkProperties); 735 inOrder.verify(mHardware, never()).addDownstream(eq(RNDIS0), anyString()); 736 737 // [5] Differences in local routes are converted into addDownstream() 738 // and removeDownstream() invocations accordingly. 739 usbLinkProperties.removeRoute( 740 new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, RNDIS0, RTN_UNICAST)); 741 usbLinkProperties.addRoute( 742 new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX), null, null, RTN_UNICAST)); 743 offload.notifyDownstreamLinkProperties(usbLinkProperties); 744 inOrder.verify(mHardware, times(1)).removeDownstream(RNDIS0, IPV6_DOC_PREFIX); 745 inOrder.verify(mHardware, times(1)).addDownstream(RNDIS0, IPV6_DISCARD_PREFIX); 746 inOrder.verifyNoMoreInteractions(); 747 748 // [6] Removing a downstream interface which was never added causes no 749 // interactions with the HAL. 750 offload.removeDownstreamInterface(WLAN0); 751 inOrder.verifyNoMoreInteractions(); 752 753 // [7] Removing an active downstream removes all remaining prefixes. 754 offload.removeDownstreamInterface(RNDIS0); 755 inOrder.verify(mHardware, times(1)).removeDownstream(RNDIS0, USB_PREFIX); 756 inOrder.verify(mHardware, times(1)).removeDownstream(RNDIS0, IPV6_DISCARD_PREFIX); 757 inOrder.verifyNoMoreInteractions(); 758 } 759 760 @Test testControlCallbackOnStoppedUnsupportedFetchesAllStats()761 public void testControlCallbackOnStoppedUnsupportedFetchesAllStats() throws Exception { 762 enableOffload(); 763 final OffloadController offload = 764 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); 765 766 // Pretend to set a few different upstreams (only the interface name 767 // matters for this test; we're ignoring IP and route information). 768 final LinkProperties upstreamLp = new LinkProperties(); 769 for (String ifname : new String[]{RMNET0, WLAN0, RMNET0}) { 770 upstreamLp.setInterfaceName(ifname); 771 offload.setUpstreamLinkProperties(upstreamLp); 772 } 773 774 // Clear invocation history, especially the getForwardedStats() calls 775 // that happen with setUpstreamParameters(). 776 clearInvocations(mHardware); 777 778 OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue(); 779 callback.onStoppedUnsupported(); 780 781 // Verify forwarded stats behaviour. 782 verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); 783 verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); 784 // TODO: verify the exact stats reported. 785 mTetherStatsProviderCb.expectNotifyStatsUpdated(); 786 mTetherStatsProviderCb.assertNoCallback(); 787 verifyNoMoreInteractions(mHardware); 788 } 789 790 @Test testControlCallbackOnSupportAvailableFetchesAllStatsAndPushesAllParameters()791 public void testControlCallbackOnSupportAvailableFetchesAllStatsAndPushesAllParameters() 792 throws Exception { 793 enableOffload(); 794 final OffloadController offload = 795 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); 796 797 // Pretend to set a few different upstreams (only the interface name 798 // matters for this test; we're ignoring IP and route information). 799 final LinkProperties upstreamLp = new LinkProperties(); 800 for (String ifname : new String[]{RMNET0, WLAN0, RMNET0}) { 801 upstreamLp.setInterfaceName(ifname); 802 offload.setUpstreamLinkProperties(upstreamLp); 803 } 804 805 // Pretend that some local prefixes and downstreams have been added 806 // (and removed, for good measure). 807 final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>(); 808 for (String s : new String[]{ 809 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) { 810 minimumLocalPrefixes.add(new IpPrefix(s)); 811 } 812 offload.setLocalPrefixes(minimumLocalPrefixes); 813 814 final LinkProperties usbLinkProperties = new LinkProperties(); 815 usbLinkProperties.setInterfaceName(RNDIS0); 816 usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24")); 817 usbLinkProperties.addRoute( 818 new RouteInfo(new IpPrefix(USB_PREFIX), null, null, RTN_UNICAST)); 819 offload.notifyDownstreamLinkProperties(usbLinkProperties); 820 821 final LinkProperties wifiLinkProperties = new LinkProperties(); 822 wifiLinkProperties.setInterfaceName(WLAN0); 823 wifiLinkProperties.addLinkAddress(new LinkAddress("192.168.43.1/24")); 824 wifiLinkProperties.addRoute( 825 new RouteInfo(new IpPrefix(WIFI_PREFIX), null, null, RTN_UNICAST)); 826 wifiLinkProperties.addRoute( 827 new RouteInfo(new IpPrefix(IPV6_LINKLOCAL), null, null, RTN_UNICAST)); 828 // Use a benchmark prefix (RFC 5180 + erratum), since the documentation 829 // prefix is included in the excluded prefix list. 830 wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::1/64")); 831 wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::2/64")); 832 wifiLinkProperties.addRoute( 833 new RouteInfo(new IpPrefix("2001:2::/64"), null, null, RTN_UNICAST)); 834 offload.notifyDownstreamLinkProperties(wifiLinkProperties); 835 836 offload.removeDownstreamInterface(RNDIS0); 837 838 // Clear invocation history, especially the getForwardedStats() calls 839 // that happen with setUpstreamParameters(). 840 clearInvocations(mHardware); 841 842 OffloadHalCallback callback = mOffloadHalCallbackCaptor.getValue(); 843 callback.onSupportAvailable(); 844 845 // Verify forwarded stats behaviour. 846 verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); 847 verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); 848 mTetherStatsProviderCb.expectNotifyStatsUpdated(); 849 mTetherStatsProviderCb.assertNoCallback(); 850 851 // TODO: verify local prefixes and downstreams are also pushed to the HAL. 852 verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture()); 853 ArrayList<String> localPrefixes = mStringArrayCaptor.getValue(); 854 assertEquals(4, localPrefixes.size()); 855 assertContainsAll(localPrefixes, 856 // TODO: The logic to find and exclude downstream IP prefixes 857 // is currently in Tethering's OffloadWrapper but must be moved 858 // into OffloadController proper. After this, also check for: 859 // "192.168.43.1/32", "2001:2::1/128", "2001:2::2/128" 860 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"); 861 verify(mHardware, times(1)).addDownstream(WLAN0, "192.168.43.0/24"); 862 verify(mHardware, times(1)).addDownstream(WLAN0, "2001:2::/64"); 863 verify(mHardware, times(1)).setUpstreamParameters(eq(RMNET0), any(), any(), any()); 864 verify(mHardware, times(1)).setDataLimit(eq(RMNET0), anyLong()); 865 verifyNoMoreInteractions(mHardware); 866 } 867 868 @Test testOnSetAlert()869 public void testOnSetAlert() throws Exception { 870 enableOffload(); 871 setOffloadPollInterval(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); 872 final OffloadController offload = 873 startOffloadController(OFFLOAD_HAL_VERSION_HIDL_1_0, true /*expectStart*/); 874 875 // Initialize with fake eth upstream. 876 final String ethernetIface = "eth1"; 877 InOrder inOrder = inOrder(mHardware); 878 offload.setUpstreamLinkProperties(makeEthernetLinkProperties()); 879 // Previous upstream was null, so no stats are fetched. 880 inOrder.verify(mHardware, never()).getForwardedStats(any()); 881 882 // Verify that set quota to 0 will immediately triggers an callback. 883 mTetherStatsProvider.onSetAlert(0); 884 waitForIdle(); 885 mTetherStatsProviderCb.expectNotifyAlertReached(); 886 887 // Verify that notifyAlertReached never fired if quota is not yet reached. 888 when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( 889 new ForwardedStats(0, 0)); 890 mTetherStatsProvider.onSetAlert(100); 891 mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); 892 waitForIdle(); 893 mTetherStatsProviderCb.assertNoCallback(); 894 895 // Verify that notifyAlertReached fired when quota is reached. 896 when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( 897 new ForwardedStats(50, 50)); 898 mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); 899 waitForIdle(); 900 mTetherStatsProviderCb.expectNotifyAlertReached(); 901 902 // Verify that set quota with UNLIMITED won't trigger any callback, and won't fetch 903 // any stats since the polling is stopped. 904 reset(mHardware); 905 mTetherStatsProvider.onSetAlert(NetworkStatsProvider.QUOTA_UNLIMITED); 906 mTestLooper.moveTimeForward(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); 907 waitForIdle(); 908 mTetherStatsProviderCb.assertNoCallback(); 909 verify(mHardware, never()).getForwardedStats(any()); 910 } 911 makeEthernetLinkProperties()912 private static LinkProperties makeEthernetLinkProperties() { 913 final String ethernetIface = "eth1"; 914 final LinkProperties lp = new LinkProperties(); 915 lp.setInterfaceName(ethernetIface); 916 return lp; 917 } 918 checkSoftwarePollingUsed(int controlVersion)919 private void checkSoftwarePollingUsed(int controlVersion) throws Exception { 920 enableOffload(); 921 setOffloadPollInterval(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); 922 OffloadController offload = 923 startOffloadController(controlVersion, true /*expectStart*/); 924 offload.setUpstreamLinkProperties(makeEthernetLinkProperties()); 925 mTetherStatsProvider.onSetAlert(0); 926 waitForIdle(); 927 if (controlVersion >= OFFLOAD_HAL_VERSION_HIDL_1_1) { 928 mTetherStatsProviderCb.assertNoCallback(); 929 } else { 930 mTetherStatsProviderCb.expectNotifyAlertReached(); 931 } 932 verify(mHardware, never()).getForwardedStats(any()); 933 } 934 935 @Test testSoftwarePollingUsed()936 public void testSoftwarePollingUsed() throws Exception { 937 checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_HIDL_1_0); 938 checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_HIDL_1_1); 939 } 940 } 941