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.server.connectivity.tethering; 18 19 import static android.net.NetworkStats.SET_DEFAULT; 20 import static android.net.NetworkStats.STATS_PER_IFACE; 21 import static android.net.NetworkStats.STATS_PER_UID; 22 import static android.net.NetworkStats.TAG_NONE; 23 import static android.net.NetworkStats.UID_ALL; 24 import static android.net.TrafficStats.UID_TETHERING; 25 import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; 26 27 import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; 28 29 import static org.junit.Assert.assertEquals; 30 import static org.junit.Assert.assertTrue; 31 import static org.junit.Assert.fail; 32 import static org.mockito.Matchers.any; 33 import static org.mockito.Matchers.anyLong; 34 import static org.mockito.Matchers.anyObject; 35 import static org.mockito.Matchers.anyString; 36 import static org.mockito.Matchers.eq; 37 import static org.mockito.Mockito.clearInvocations; 38 import static org.mockito.Mockito.inOrder; 39 import static org.mockito.Mockito.never; 40 import static org.mockito.Mockito.times; 41 import static org.mockito.Mockito.verify; 42 import static org.mockito.Mockito.verifyNoMoreInteractions; 43 import static org.mockito.Mockito.when; 44 45 import android.content.Context; 46 import android.content.pm.ApplicationInfo; 47 import android.net.ITetheringStatsProvider; 48 import android.net.IpPrefix; 49 import android.net.LinkAddress; 50 import android.net.LinkProperties; 51 import android.net.NetworkStats; 52 import android.net.RouteInfo; 53 import android.net.util.SharedLog; 54 import android.os.ConditionVariable; 55 import android.os.Handler; 56 import android.os.INetworkManagementService; 57 import android.os.Looper; 58 import android.provider.Settings; 59 import android.provider.Settings.SettingNotFoundException; 60 import android.test.mock.MockContentResolver; 61 62 import androidx.test.filters.SmallTest; 63 import androidx.test.runner.AndroidJUnit4; 64 65 import com.android.internal.util.test.FakeSettingsProvider; 66 67 import org.junit.After; 68 import org.junit.Before; 69 import org.junit.Test; 70 import org.junit.runner.RunWith; 71 import org.mockito.ArgumentCaptor; 72 import org.mockito.InOrder; 73 import org.mockito.Mock; 74 import org.mockito.MockitoAnnotations; 75 76 import java.net.InetAddress; 77 import java.util.ArrayList; 78 import java.util.HashSet; 79 import java.util.Set; 80 81 @RunWith(AndroidJUnit4.class) 82 @SmallTest 83 public class OffloadControllerTest { 84 private static final String RNDIS0 = "test_rndis0"; 85 private static final String RMNET0 = "test_rmnet_data0"; 86 private static final String WLAN0 = "test_wlan0"; 87 88 private static final String IPV6_LINKLOCAL = "fe80::/64"; 89 private static final String IPV6_DOC_PREFIX = "2001:db8::/64"; 90 private static final String IPV6_DISCARD_PREFIX = "100::/64"; 91 private static final String USB_PREFIX = "192.168.42.0/24"; 92 private static final String WIFI_PREFIX = "192.168.43.0/24"; 93 94 @Mock private OffloadHardwareInterface mHardware; 95 @Mock private ApplicationInfo mApplicationInfo; 96 @Mock private Context mContext; 97 @Mock private INetworkManagementService mNMService; 98 private final ArgumentCaptor<ArrayList> mStringArrayCaptor = 99 ArgumentCaptor.forClass(ArrayList.class); 100 private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor = 101 ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class); 102 private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor = 103 ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class); 104 private MockContentResolver mContentResolver; 105 setUp()106 @Before public void setUp() { 107 MockitoAnnotations.initMocks(this); 108 when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo); 109 when(mContext.getPackageName()).thenReturn("OffloadControllerTest"); 110 mContentResolver = new MockContentResolver(mContext); 111 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); 112 when(mContext.getContentResolver()).thenReturn(mContentResolver); 113 FakeSettingsProvider.clearSettingsProvider(); 114 } 115 tearDown()116 @After public void tearDown() throws Exception { 117 FakeSettingsProvider.clearSettingsProvider(); 118 } 119 setupFunctioningHardwareInterface()120 private void setupFunctioningHardwareInterface() { 121 when(mHardware.initOffloadConfig()).thenReturn(true); 122 when(mHardware.initOffloadControl(mControlCallbackCaptor.capture())) 123 .thenReturn(true); 124 when(mHardware.setUpstreamParameters(anyString(), any(), any(), any())).thenReturn(true); 125 when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats()); 126 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); 127 } 128 enableOffload()129 private void enableOffload() { 130 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0); 131 } 132 waitForIdle()133 private void waitForIdle() { 134 ConditionVariable cv = new ConditionVariable(); 135 new Handler(Looper.getMainLooper()).post(() -> { cv.open(); }); 136 cv.block(); 137 } 138 makeOffloadController()139 private OffloadController makeOffloadController() throws Exception { 140 OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()), 141 mHardware, mContentResolver, mNMService, new SharedLog("test")); 142 verify(mNMService).registerTetheringStatsProvider( 143 mTetherStatsProviderCaptor.capture(), anyString()); 144 return offload; 145 } 146 147 @Test testNoSettingsValueDefaultDisabledDoesNotStart()148 public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception { 149 setupFunctioningHardwareInterface(); 150 when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1); 151 try { 152 Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED); 153 fail(); 154 } catch (SettingNotFoundException expected) {} 155 156 final OffloadController offload = makeOffloadController(); 157 offload.start(); 158 159 final InOrder inOrder = inOrder(mHardware); 160 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled(); 161 inOrder.verify(mHardware, never()).initOffloadConfig(); 162 inOrder.verify(mHardware, never()).initOffloadControl( 163 any(OffloadHardwareInterface.ControlCallback.class)); 164 inOrder.verifyNoMoreInteractions(); 165 } 166 167 @Test testNoSettingsValueDefaultEnabledDoesStart()168 public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception { 169 setupFunctioningHardwareInterface(); 170 when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0); 171 try { 172 Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED); 173 fail(); 174 } catch (SettingNotFoundException expected) {} 175 176 final OffloadController offload = makeOffloadController(); 177 offload.start(); 178 179 final InOrder inOrder = inOrder(mHardware); 180 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled(); 181 inOrder.verify(mHardware, times(1)).initOffloadConfig(); 182 inOrder.verify(mHardware, times(1)).initOffloadControl( 183 any(OffloadHardwareInterface.ControlCallback.class)); 184 inOrder.verifyNoMoreInteractions(); 185 } 186 187 @Test testSettingsAllowsStart()188 public void testSettingsAllowsStart() throws Exception { 189 setupFunctioningHardwareInterface(); 190 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0); 191 192 final OffloadController offload = makeOffloadController(); 193 offload.start(); 194 195 final InOrder inOrder = inOrder(mHardware); 196 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled(); 197 inOrder.verify(mHardware, times(1)).initOffloadConfig(); 198 inOrder.verify(mHardware, times(1)).initOffloadControl( 199 any(OffloadHardwareInterface.ControlCallback.class)); 200 inOrder.verifyNoMoreInteractions(); 201 } 202 203 @Test testSettingsDisablesStart()204 public void testSettingsDisablesStart() throws Exception { 205 setupFunctioningHardwareInterface(); 206 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1); 207 208 final OffloadController offload = makeOffloadController(); 209 offload.start(); 210 211 final InOrder inOrder = inOrder(mHardware); 212 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled(); 213 inOrder.verify(mHardware, never()).initOffloadConfig(); 214 inOrder.verify(mHardware, never()).initOffloadControl(anyObject()); 215 inOrder.verifyNoMoreInteractions(); 216 } 217 218 @Test testSetUpstreamLinkPropertiesWorking()219 public void testSetUpstreamLinkPropertiesWorking() throws Exception { 220 setupFunctioningHardwareInterface(); 221 enableOffload(); 222 223 final OffloadController offload = makeOffloadController(); 224 offload.start(); 225 226 final InOrder inOrder = inOrder(mHardware); 227 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled(); 228 inOrder.verify(mHardware, times(1)).initOffloadConfig(); 229 inOrder.verify(mHardware, times(1)).initOffloadControl( 230 any(OffloadHardwareInterface.ControlCallback.class)); 231 inOrder.verifyNoMoreInteractions(); 232 233 // In reality, the UpstreamNetworkMonitor would have passed down to us 234 // a covering set of local prefixes representing a minimum essential 235 // set plus all the prefixes on networks with network agents. 236 // 237 // We simulate that there, and then add upstream elements one by one 238 // and watch what happens. 239 final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>(); 240 for (String s : new String[]{ 241 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) { 242 minimumLocalPrefixes.add(new IpPrefix(s)); 243 } 244 offload.setLocalPrefixes(minimumLocalPrefixes); 245 inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture()); 246 ArrayList<String> localPrefixes = mStringArrayCaptor.getValue(); 247 assertEquals(4, localPrefixes.size()); 248 assertArrayListContains(localPrefixes, 249 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"); 250 inOrder.verifyNoMoreInteractions(); 251 252 offload.setUpstreamLinkProperties(null); 253 // No change in local addresses means no call to setLocalPrefixes(). 254 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 255 // This LinkProperties value does not differ from the default upstream. 256 // There should be no extraneous call to setUpstreamParameters(). 257 inOrder.verify(mHardware, never()).setUpstreamParameters( 258 anyObject(), anyObject(), anyObject(), anyObject()); 259 inOrder.verifyNoMoreInteractions(); 260 261 final LinkProperties lp = new LinkProperties(); 262 263 final String testIfName = "rmnet_data17"; 264 lp.setInterfaceName(testIfName); 265 offload.setUpstreamLinkProperties(lp); 266 // No change in local addresses means no call to setLocalPrefixes(). 267 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 268 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 269 eq(testIfName), eq(null), eq(null), eq(null)); 270 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 271 inOrder.verifyNoMoreInteractions(); 272 273 final String ipv4Addr = "192.0.2.5"; 274 final String linkAddr = ipv4Addr + "/24"; 275 lp.addLinkAddress(new LinkAddress(linkAddr)); 276 lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"))); 277 offload.setUpstreamLinkProperties(lp); 278 // IPv4 prefixes and addresses on the upstream are simply left as whole 279 // prefixes (already passed in from UpstreamNetworkMonitor code). If a 280 // tethering client sends traffic to the IPv4 default router or other 281 // clients on the upstream this will not be hardware-forwarded, and that 282 // should be fine for now. Ergo: no change in local addresses, no call 283 // to setLocalPrefixes(). 284 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 285 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 286 eq(testIfName), eq(ipv4Addr), eq(null), eq(null)); 287 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 288 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 289 inOrder.verifyNoMoreInteractions(); 290 291 final String ipv4Gateway = "192.0.2.1"; 292 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway))); 293 offload.setUpstreamLinkProperties(lp); 294 // No change in local addresses means no call to setLocalPrefixes(). 295 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 296 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 297 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null)); 298 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 299 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 300 inOrder.verifyNoMoreInteractions(); 301 302 final String ipv6Gw1 = "fe80::cafe"; 303 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1))); 304 offload.setUpstreamLinkProperties(lp); 305 // No change in local addresses means no call to setLocalPrefixes(). 306 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 307 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 308 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture()); 309 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 310 ArrayList<String> v6gws = mStringArrayCaptor.getValue(); 311 assertEquals(1, v6gws.size()); 312 assertTrue(v6gws.contains(ipv6Gw1)); 313 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 314 inOrder.verifyNoMoreInteractions(); 315 316 final String ipv6Gw2 = "fe80::d00d"; 317 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2))); 318 offload.setUpstreamLinkProperties(lp); 319 // No change in local addresses means no call to setLocalPrefixes(). 320 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 321 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 322 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture()); 323 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 324 v6gws = mStringArrayCaptor.getValue(); 325 assertEquals(2, v6gws.size()); 326 assertTrue(v6gws.contains(ipv6Gw1)); 327 assertTrue(v6gws.contains(ipv6Gw2)); 328 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 329 inOrder.verifyNoMoreInteractions(); 330 331 final LinkProperties stacked = new LinkProperties(); 332 stacked.setInterfaceName("stacked"); 333 stacked.addLinkAddress(new LinkAddress("192.0.2.129/25")); 334 stacked.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254"))); 335 stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00"))); 336 assertTrue(lp.addStackedLink(stacked)); 337 offload.setUpstreamLinkProperties(lp); 338 // No change in local addresses means no call to setLocalPrefixes(). 339 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); 340 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 341 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture()); 342 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 343 v6gws = mStringArrayCaptor.getValue(); 344 assertEquals(2, v6gws.size()); 345 assertTrue(v6gws.contains(ipv6Gw1)); 346 assertTrue(v6gws.contains(ipv6Gw2)); 347 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 348 inOrder.verifyNoMoreInteractions(); 349 350 // Add in some IPv6 upstream info. When there is a tethered downstream 351 // making use of the IPv6 prefix we would expect to see the /64 route 352 // removed from "local prefixes" and /128s added for the upstream IPv6 353 // addresses. This is not yet implemented, and for now we simply 354 // expect to see these /128s. 355 lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64"))); 356 // "2001:db8::/64" plus "assigned" ASCII in hex 357 lp.addLinkAddress(new LinkAddress("2001:db8::6173:7369:676e:6564/64")); 358 // "2001:db8::/64" plus "random" ASCII in hex 359 lp.addLinkAddress(new LinkAddress("2001:db8::7261:6e64:6f6d/64")); 360 offload.setUpstreamLinkProperties(lp); 361 inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture()); 362 localPrefixes = mStringArrayCaptor.getValue(); 363 assertEquals(6, localPrefixes.size()); 364 assertArrayListContains(localPrefixes, 365 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64", 366 "2001:db8::6173:7369:676e:6564/128", "2001:db8::7261:6e64:6f6d/128"); 367 // The relevant parts of the LinkProperties have not changed, but at the 368 // moment we do not de-dup upstream LinkProperties this carefully. 369 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 370 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture()); 371 v6gws = mStringArrayCaptor.getValue(); 372 assertEquals(2, v6gws.size()); 373 assertTrue(v6gws.contains(ipv6Gw1)); 374 assertTrue(v6gws.contains(ipv6Gw2)); 375 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName)); 376 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE)); 377 inOrder.verifyNoMoreInteractions(); 378 379 // Completely identical LinkProperties updates are de-duped. 380 offload.setUpstreamLinkProperties(lp); 381 // This LinkProperties value does not differ from the default upstream. 382 // There should be no extraneous call to setUpstreamParameters(). 383 inOrder.verify(mHardware, never()).setUpstreamParameters( 384 anyObject(), anyObject(), anyObject(), anyObject()); 385 inOrder.verifyNoMoreInteractions(); 386 } 387 assertNetworkStats(String iface, ForwardedStats stats, NetworkStats.Entry entry)388 private void assertNetworkStats(String iface, ForwardedStats stats, NetworkStats.Entry entry) { 389 assertEquals(iface, entry.iface); 390 assertEquals(stats.rxBytes, entry.rxBytes); 391 assertEquals(stats.txBytes, entry.txBytes); 392 assertEquals(SET_DEFAULT, entry.set); 393 assertEquals(TAG_NONE, entry.tag); 394 } 395 396 @Test testGetForwardedStats()397 public void testGetForwardedStats() throws Exception { 398 setupFunctioningHardwareInterface(); 399 enableOffload(); 400 401 final OffloadController offload = makeOffloadController(); 402 offload.start(); 403 404 final String ethernetIface = "eth1"; 405 final String mobileIface = "rmnet_data0"; 406 407 ForwardedStats ethernetStats = new ForwardedStats(); 408 ethernetStats.rxBytes = 12345; 409 ethernetStats.txBytes = 54321; 410 411 ForwardedStats mobileStats = new ForwardedStats(); 412 mobileStats.rxBytes = 999; 413 mobileStats.txBytes = 99999; 414 415 when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats); 416 when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn(mobileStats); 417 418 InOrder inOrder = inOrder(mHardware); 419 420 final LinkProperties lp = new LinkProperties(); 421 lp.setInterfaceName(ethernetIface); 422 offload.setUpstreamLinkProperties(lp); 423 // Previous upstream was null, so no stats are fetched. 424 inOrder.verify(mHardware, never()).getForwardedStats(any()); 425 426 lp.setInterfaceName(mobileIface); 427 offload.setUpstreamLinkProperties(lp); 428 // Expect that we fetch stats from the previous upstream. 429 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(ethernetIface)); 430 431 lp.setInterfaceName(ethernetIface); 432 offload.setUpstreamLinkProperties(lp); 433 // Expect that we fetch stats from the previous upstream. 434 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(mobileIface)); 435 436 ethernetStats = new ForwardedStats(); 437 ethernetStats.rxBytes = 100000; 438 ethernetStats.txBytes = 100000; 439 when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats); 440 offload.setUpstreamLinkProperties(null); 441 // Expect that we first clear the HAL's upstream parameters. 442 inOrder.verify(mHardware, times(1)).setUpstreamParameters( 443 eq(""), eq("0.0.0.0"), eq("0.0.0.0"), eq(null)); 444 // Expect that we fetch stats from the previous upstream. 445 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(ethernetIface)); 446 447 ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue(); 448 NetworkStats stats = provider.getTetherStats(STATS_PER_IFACE); 449 NetworkStats perUidStats = provider.getTetherStats(STATS_PER_UID); 450 waitForIdle(); 451 // There is no current upstream, so no stats are fetched. 452 inOrder.verify(mHardware, never()).getForwardedStats(any()); 453 inOrder.verifyNoMoreInteractions(); 454 455 assertEquals(2, stats.size()); 456 assertEquals(2, perUidStats.size()); 457 458 NetworkStats.Entry entry = null; 459 for (int i = 0; i < stats.size(); i++) { 460 assertEquals(UID_ALL, stats.getValues(i, entry).uid); 461 assertEquals(UID_TETHERING, perUidStats.getValues(i, entry).uid); 462 } 463 464 int ethernetPosition = ethernetIface.equals(stats.getValues(0, entry).iface) ? 0 : 1; 465 int mobilePosition = 1 - ethernetPosition; 466 467 entry = stats.getValues(mobilePosition, entry); 468 assertNetworkStats(mobileIface, mobileStats, entry); 469 entry = perUidStats.getValues(mobilePosition, entry); 470 assertNetworkStats(mobileIface, mobileStats, entry); 471 472 ethernetStats.rxBytes = 12345 + 100000; 473 ethernetStats.txBytes = 54321 + 100000; 474 entry = stats.getValues(ethernetPosition, entry); 475 assertNetworkStats(ethernetIface, ethernetStats, entry); 476 entry = perUidStats.getValues(ethernetPosition, entry); 477 assertNetworkStats(ethernetIface, ethernetStats, entry); 478 } 479 480 @Test testSetInterfaceQuota()481 public void testSetInterfaceQuota() throws Exception { 482 setupFunctioningHardwareInterface(); 483 enableOffload(); 484 485 final OffloadController offload = makeOffloadController(); 486 offload.start(); 487 488 final String ethernetIface = "eth1"; 489 final String mobileIface = "rmnet_data0"; 490 final long ethernetLimit = 12345; 491 final long mobileLimit = 12345678; 492 493 final LinkProperties lp = new LinkProperties(); 494 lp.setInterfaceName(ethernetIface); 495 offload.setUpstreamLinkProperties(lp); 496 497 ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue(); 498 final InOrder inOrder = inOrder(mHardware); 499 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true); 500 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); 501 502 // Applying an interface quota to the current upstream immediately sends it to the hardware. 503 provider.setInterfaceQuota(ethernetIface, ethernetLimit); 504 waitForIdle(); 505 inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit); 506 inOrder.verifyNoMoreInteractions(); 507 508 // Applying an interface quota to another upstream does not take any immediate action. 509 provider.setInterfaceQuota(mobileIface, mobileLimit); 510 waitForIdle(); 511 inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); 512 513 // Switching to that upstream causes the quota to be applied if the parameters were applied 514 // correctly. 515 lp.setInterfaceName(mobileIface); 516 offload.setUpstreamLinkProperties(lp); 517 waitForIdle(); 518 inOrder.verify(mHardware).setDataLimit(mobileIface, mobileLimit); 519 520 // Setting a limit of ITetheringStatsProvider.QUOTA_UNLIMITED causes the limit to be set 521 // to Long.MAX_VALUE. 522 provider.setInterfaceQuota(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED); 523 waitForIdle(); 524 inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE); 525 526 // If setting upstream parameters fails, then the data limit is not set. 527 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false); 528 lp.setInterfaceName(ethernetIface); 529 offload.setUpstreamLinkProperties(lp); 530 provider.setInterfaceQuota(mobileIface, mobileLimit); 531 waitForIdle(); 532 inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); 533 534 // If setting the data limit fails while changing upstreams, offload is stopped. 535 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true); 536 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false); 537 lp.setInterfaceName(mobileIface); 538 offload.setUpstreamLinkProperties(lp); 539 provider.setInterfaceQuota(mobileIface, mobileLimit); 540 waitForIdle(); 541 inOrder.verify(mHardware).getForwardedStats(ethernetIface); 542 inOrder.verify(mHardware).stopOffloadControl(); 543 } 544 545 @Test testDataLimitCallback()546 public void testDataLimitCallback() throws Exception { 547 setupFunctioningHardwareInterface(); 548 enableOffload(); 549 550 final OffloadController offload = makeOffloadController(); 551 offload.start(); 552 553 OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); 554 callback.onStoppedLimitReached(); 555 verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue()); 556 } 557 558 @Test testAddRemoveDownstreams()559 public void testAddRemoveDownstreams() throws Exception { 560 setupFunctioningHardwareInterface(); 561 enableOffload(); 562 563 final OffloadController offload = makeOffloadController(); 564 offload.start(); 565 566 final InOrder inOrder = inOrder(mHardware); 567 inOrder.verify(mHardware, times(1)).initOffloadConfig(); 568 inOrder.verify(mHardware, times(1)).initOffloadControl( 569 any(OffloadHardwareInterface.ControlCallback.class)); 570 inOrder.verifyNoMoreInteractions(); 571 572 // Tethering makes several calls to setLocalPrefixes() before add/remove 573 // downstream calls are made. This is not tested here; only the behavior 574 // of notifyDownstreamLinkProperties() and removeDownstreamInterface() 575 // are tested. 576 577 // [1] USB tethering is started. 578 final LinkProperties usbLinkProperties = new LinkProperties(); 579 usbLinkProperties.setInterfaceName(RNDIS0); 580 usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24")); 581 usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX))); 582 offload.notifyDownstreamLinkProperties(usbLinkProperties); 583 inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, USB_PREFIX); 584 inOrder.verifyNoMoreInteractions(); 585 586 // [2] Routes for IPv6 link-local prefixes should never be added. 587 usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL))); 588 offload.notifyDownstreamLinkProperties(usbLinkProperties); 589 inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString()); 590 inOrder.verifyNoMoreInteractions(); 591 592 // [3] Add an IPv6 prefix for good measure. Only new offload-able 593 // prefixes should be passed to the HAL. 594 usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64")); 595 usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX))); 596 offload.notifyDownstreamLinkProperties(usbLinkProperties); 597 inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX); 598 inOrder.verifyNoMoreInteractions(); 599 600 // [4] Adding addresses doesn't affect notifyDownstreamLinkProperties(). 601 // The address is passed in by a separate setLocalPrefixes() invocation. 602 usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::2/64")); 603 offload.notifyDownstreamLinkProperties(usbLinkProperties); 604 inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString()); 605 606 // [5] Differences in local routes are converted into addDownstream() 607 // and removeDownstream() invocations accordingly. 608 usbLinkProperties.removeRoute(new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, RNDIS0)); 609 usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX))); 610 offload.notifyDownstreamLinkProperties(usbLinkProperties); 611 inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX); 612 inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX); 613 inOrder.verifyNoMoreInteractions(); 614 615 // [6] Removing a downstream interface which was never added causes no 616 // interactions with the HAL. 617 offload.removeDownstreamInterface(WLAN0); 618 inOrder.verifyNoMoreInteractions(); 619 620 // [7] Removing an active downstream removes all remaining prefixes. 621 offload.removeDownstreamInterface(RNDIS0); 622 inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, USB_PREFIX); 623 inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX); 624 inOrder.verifyNoMoreInteractions(); 625 } 626 627 @Test testControlCallbackOnStoppedUnsupportedFetchesAllStats()628 public void testControlCallbackOnStoppedUnsupportedFetchesAllStats() throws Exception { 629 setupFunctioningHardwareInterface(); 630 enableOffload(); 631 632 final OffloadController offload = makeOffloadController(); 633 offload.start(); 634 635 // Pretend to set a few different upstreams (only the interface name 636 // matters for this test; we're ignoring IP and route information). 637 final LinkProperties upstreamLp = new LinkProperties(); 638 for (String ifname : new String[]{RMNET0, WLAN0, RMNET0}) { 639 upstreamLp.setInterfaceName(ifname); 640 offload.setUpstreamLinkProperties(upstreamLp); 641 } 642 643 // Clear invocation history, especially the getForwardedStats() calls 644 // that happen with setUpstreamParameters(). 645 clearInvocations(mHardware); 646 647 OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); 648 callback.onStoppedUnsupported(); 649 650 // Verify forwarded stats behaviour. 651 verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); 652 verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); 653 verifyNoMoreInteractions(mHardware); 654 verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue()); 655 verifyNoMoreInteractions(mNMService); 656 } 657 658 @Test testControlCallbackOnSupportAvailableFetchesAllStatsAndPushesAllParameters()659 public void testControlCallbackOnSupportAvailableFetchesAllStatsAndPushesAllParameters() 660 throws Exception { 661 setupFunctioningHardwareInterface(); 662 enableOffload(); 663 664 final OffloadController offload = makeOffloadController(); 665 offload.start(); 666 667 // Pretend to set a few different upstreams (only the interface name 668 // matters for this test; we're ignoring IP and route information). 669 final LinkProperties upstreamLp = new LinkProperties(); 670 for (String ifname : new String[]{RMNET0, WLAN0, RMNET0}) { 671 upstreamLp.setInterfaceName(ifname); 672 offload.setUpstreamLinkProperties(upstreamLp); 673 } 674 675 // Pretend that some local prefixes and downstreams have been added 676 // (and removed, for good measure). 677 final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>(); 678 for (String s : new String[]{ 679 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) { 680 minimumLocalPrefixes.add(new IpPrefix(s)); 681 } 682 offload.setLocalPrefixes(minimumLocalPrefixes); 683 684 final LinkProperties usbLinkProperties = new LinkProperties(); 685 usbLinkProperties.setInterfaceName(RNDIS0); 686 usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24")); 687 usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX))); 688 offload.notifyDownstreamLinkProperties(usbLinkProperties); 689 690 final LinkProperties wifiLinkProperties = new LinkProperties(); 691 wifiLinkProperties.setInterfaceName(WLAN0); 692 wifiLinkProperties.addLinkAddress(new LinkAddress("192.168.43.1/24")); 693 wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(WIFI_PREFIX))); 694 wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL))); 695 // Use a benchmark prefix (RFC 5180 + erratum), since the documentation 696 // prefix is included in the excluded prefix list. 697 wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::1/64")); 698 wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::2/64")); 699 wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix("2001:2::/64"))); 700 offload.notifyDownstreamLinkProperties(wifiLinkProperties); 701 702 offload.removeDownstreamInterface(RNDIS0); 703 704 // Clear invocation history, especially the getForwardedStats() calls 705 // that happen with setUpstreamParameters(). 706 clearInvocations(mHardware); 707 708 OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); 709 callback.onSupportAvailable(); 710 711 // Verify forwarded stats behaviour. 712 verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); 713 verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); 714 verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue()); 715 verifyNoMoreInteractions(mNMService); 716 717 // TODO: verify local prefixes and downstreams are also pushed to the HAL. 718 verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture()); 719 ArrayList<String> localPrefixes = mStringArrayCaptor.getValue(); 720 assertEquals(4, localPrefixes.size()); 721 assertArrayListContains(localPrefixes, 722 // TODO: The logic to find and exclude downstream IP prefixes 723 // is currently in Tethering's OffloadWrapper but must be moved 724 // into OffloadController proper. After this, also check for: 725 // "192.168.43.1/32", "2001:2::1/128", "2001:2::2/128" 726 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"); 727 verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "192.168.43.0/24"); 728 verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "2001:2::/64"); 729 verify(mHardware, times(1)).setUpstreamParameters(eq(RMNET0), any(), any(), any()); 730 verify(mHardware, times(1)).setDataLimit(eq(RMNET0), anyLong()); 731 verifyNoMoreInteractions(mHardware); 732 } 733 assertArrayListContains(ArrayList<String> list, String... elems)734 private static void assertArrayListContains(ArrayList<String> list, String... elems) { 735 for (String element : elems) { 736 assertTrue(element + " not in list", list.contains(element)); 737 } 738 } 739 } 740