blob: 54addb15c246e05439a4ae4782ce885969fb3ab8 [file] [log] [blame]
Erik Kline92c4db02017-05-31 10:21:32 +09001/*
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
17package com.android.server.connectivity.tethering;
18
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090019import static android.net.NetworkStats.SET_DEFAULT;
20import static android.net.NetworkStats.TAG_NONE;
21import static android.net.TrafficStats.UID_TETHERING;
Erik Kline92c4db02017-05-31 10:21:32 +090022import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090023import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats;
Erik Kline7990aef2017-06-01 20:11:25 +090024import static org.junit.Assert.assertEquals;
25import static org.junit.Assert.assertTrue;
Erik Kline92c4db02017-05-31 10:21:32 +090026import static org.junit.Assert.fail;
27import static org.mockito.Matchers.any;
Lorenzo Colitti50b60fc2017-08-11 13:47:49 +090028import static org.mockito.Matchers.anyLong;
Erik Kline92c4db02017-05-31 10:21:32 +090029import static org.mockito.Matchers.anyObject;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090030import static org.mockito.Matchers.anyString;
Erik Kline7990aef2017-06-01 20:11:25 +090031import static org.mockito.Matchers.eq;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090032import static org.mockito.Mockito.doNothing;
Erik Kline92c4db02017-05-31 10:21:32 +090033import static org.mockito.Mockito.inOrder;
34import static org.mockito.Mockito.never;
Erik Kline7990aef2017-06-01 20:11:25 +090035import static org.mockito.Mockito.reset;
Erik Kline92c4db02017-05-31 10:21:32 +090036import static org.mockito.Mockito.times;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090037import static org.mockito.Mockito.verify;
Erik Kline92c4db02017-05-31 10:21:32 +090038import static org.mockito.Mockito.when;
39
40import android.content.Context;
Erik Klineec372752017-06-07 16:33:19 +090041import android.content.pm.ApplicationInfo;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090042import android.net.ITetheringStatsProvider;
Erik Kline5acb4e32017-07-04 18:28:11 +090043import android.net.IpPrefix;
Erik Kline7990aef2017-06-01 20:11:25 +090044import android.net.LinkAddress;
45import android.net.LinkProperties;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090046import android.net.NetworkStats;
Erik Kline7990aef2017-06-01 20:11:25 +090047import android.net.RouteInfo;
Erik Kline92c4db02017-05-31 10:21:32 +090048import android.net.util.SharedLog;
Lorenzo Colitti50b60fc2017-08-11 13:47:49 +090049import android.os.ConditionVariable;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090050import android.os.Handler;
51import android.os.Looper;
52import android.os.INetworkManagementService;
Erik Kline92c4db02017-05-31 10:21:32 +090053import android.provider.Settings;
54import android.provider.Settings.SettingNotFoundException;
55
56import android.support.test.filters.SmallTest;
57import android.support.test.runner.AndroidJUnit4;
58import android.test.mock.MockContentResolver;
59import com.android.internal.util.test.FakeSettingsProvider;
60
Erik Kline7990aef2017-06-01 20:11:25 +090061import java.net.InetAddress;
62import java.util.ArrayList;
Erik Kline5acb4e32017-07-04 18:28:11 +090063import java.util.HashSet;
64import java.util.Set;
Erik Kline7990aef2017-06-01 20:11:25 +090065
Erik Kline5eaa7ed2017-07-07 17:38:30 +090066import org.junit.After;
Erik Kline92c4db02017-05-31 10:21:32 +090067import org.junit.Before;
68import org.junit.runner.RunWith;
69import org.junit.Test;
Erik Kline7990aef2017-06-01 20:11:25 +090070import org.mockito.ArgumentCaptor;
Erik Kline92c4db02017-05-31 10:21:32 +090071import org.mockito.InOrder;
72import org.mockito.Mock;
73import org.mockito.MockitoAnnotations;
74
75
76@RunWith(AndroidJUnit4.class)
77@SmallTest
78public class OffloadControllerTest {
79
80 @Mock private OffloadHardwareInterface mHardware;
Erik Klineec372752017-06-07 16:33:19 +090081 @Mock private ApplicationInfo mApplicationInfo;
Erik Kline92c4db02017-05-31 10:21:32 +090082 @Mock private Context mContext;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090083 @Mock private INetworkManagementService mNMService;
Erik Klinedd4d5822017-06-12 18:20:08 +090084 private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
85 ArgumentCaptor.forClass(ArrayList.class);
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090086 private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor =
87 ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class);
Lorenzo Colitti9f0baa92017-08-15 19:25:51 +090088 private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor =
89 ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class);
Erik Kline92c4db02017-05-31 10:21:32 +090090 private MockContentResolver mContentResolver;
91
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090092 @Before public void setUp() {
Erik Kline92c4db02017-05-31 10:21:32 +090093 MockitoAnnotations.initMocks(this);
Erik Klineec372752017-06-07 16:33:19 +090094 when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
95 when(mContext.getPackageName()).thenReturn("OffloadControllerTest");
Erik Kline92c4db02017-05-31 10:21:32 +090096 mContentResolver = new MockContentResolver(mContext);
97 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
Erik Kline92c4db02017-05-31 10:21:32 +090098 when(mContext.getContentResolver()).thenReturn(mContentResolver);
Erik Kline5eaa7ed2017-07-07 17:38:30 +090099 // TODO: call this when available.
100 // FakeSettingsProvider.clearSettingsProvider();
101 }
102
103 @After public void tearDown() throws Exception {
104 // TODO: call this when available.
105 // FakeSettingsProvider.clearSettingsProvider();
Erik Kline92c4db02017-05-31 10:21:32 +0900106 }
107
108 private void setupFunctioningHardwareInterface() {
109 when(mHardware.initOffloadConfig()).thenReturn(true);
Lorenzo Colitti9f0baa92017-08-15 19:25:51 +0900110 when(mHardware.initOffloadControl(mControlCallbackCaptor.capture()))
Erik Kline92c4db02017-05-31 10:21:32 +0900111 .thenReturn(true);
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900112 when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
Erik Kline92c4db02017-05-31 10:21:32 +0900113 }
114
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900115 private void enableOffload() {
116 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
117 }
118
Lorenzo Colitti50b60fc2017-08-11 13:47:49 +0900119 private void waitForIdle() {
120 ConditionVariable cv = new ConditionVariable();
121 new Handler(Looper.getMainLooper()).post(() -> { cv.open(); });
122 cv.block();
123 }
124
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900125 private OffloadController makeOffloadController() throws Exception {
126 OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()),
127 mHardware, mContentResolver, mNMService, new SharedLog("test"));
128 verify(mNMService).registerTetheringStatsProvider(
129 mTetherStatsProviderCaptor.capture(), anyString());
130 return offload;
131 }
132
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900133 // TODO: Restore when FakeSettingsProvider.clearSettingsProvider() is available.
134 // @Test
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900135 public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception {
Erik Kline92c4db02017-05-31 10:21:32 +0900136 setupFunctioningHardwareInterface();
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900137 when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
Erik Kline92c4db02017-05-31 10:21:32 +0900138 try {
139 Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED);
140 fail();
141 } catch (SettingNotFoundException expected) {}
142
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900143 final OffloadController offload = makeOffloadController();
Erik Kline92c4db02017-05-31 10:21:32 +0900144 offload.start();
145
146 final InOrder inOrder = inOrder(mHardware);
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900147 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
148 inOrder.verify(mHardware, never()).initOffloadConfig();
149 inOrder.verify(mHardware, never()).initOffloadControl(
150 any(OffloadHardwareInterface.ControlCallback.class));
151 inOrder.verifyNoMoreInteractions();
152 }
153
154 // TODO: Restore when FakeSettingsProvider.clearSettingsProvider() is available.
155 // @Test
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900156 public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception {
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900157 setupFunctioningHardwareInterface();
158 when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
159 try {
160 Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED);
161 fail();
162 } catch (SettingNotFoundException expected) {}
163
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900164 final OffloadController offload = makeOffloadController();
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900165 offload.start();
166
167 final InOrder inOrder = inOrder(mHardware);
168 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
Erik Kline92c4db02017-05-31 10:21:32 +0900169 inOrder.verify(mHardware, times(1)).initOffloadConfig();
170 inOrder.verify(mHardware, times(1)).initOffloadControl(
171 any(OffloadHardwareInterface.ControlCallback.class));
172 inOrder.verifyNoMoreInteractions();
173 }
174
175 @Test
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900176 public void testSettingsAllowsStart() throws Exception {
Erik Kline92c4db02017-05-31 10:21:32 +0900177 setupFunctioningHardwareInterface();
178 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
179
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900180 final OffloadController offload = makeOffloadController();
Erik Kline92c4db02017-05-31 10:21:32 +0900181 offload.start();
182
183 final InOrder inOrder = inOrder(mHardware);
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900184 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
Erik Kline92c4db02017-05-31 10:21:32 +0900185 inOrder.verify(mHardware, times(1)).initOffloadConfig();
186 inOrder.verify(mHardware, times(1)).initOffloadControl(
187 any(OffloadHardwareInterface.ControlCallback.class));
188 inOrder.verifyNoMoreInteractions();
189 }
190
191 @Test
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900192 public void testSettingsDisablesStart() throws Exception {
Erik Kline92c4db02017-05-31 10:21:32 +0900193 setupFunctioningHardwareInterface();
194 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1);
195
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900196 final OffloadController offload = makeOffloadController();
Erik Kline92c4db02017-05-31 10:21:32 +0900197 offload.start();
198
199 final InOrder inOrder = inOrder(mHardware);
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900200 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
Erik Kline92c4db02017-05-31 10:21:32 +0900201 inOrder.verify(mHardware, never()).initOffloadConfig();
202 inOrder.verify(mHardware, never()).initOffloadControl(anyObject());
203 inOrder.verifyNoMoreInteractions();
204 }
Erik Kline7990aef2017-06-01 20:11:25 +0900205
206 @Test
207 public void testSetUpstreamLinkPropertiesWorking() throws Exception {
208 setupFunctioningHardwareInterface();
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900209 enableOffload();
210
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900211 final OffloadController offload = makeOffloadController();
Erik Kline7990aef2017-06-01 20:11:25 +0900212 offload.start();
213
214 final InOrder inOrder = inOrder(mHardware);
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900215 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
Erik Kline7990aef2017-06-01 20:11:25 +0900216 inOrder.verify(mHardware, times(1)).initOffloadConfig();
217 inOrder.verify(mHardware, times(1)).initOffloadControl(
218 any(OffloadHardwareInterface.ControlCallback.class));
219 inOrder.verifyNoMoreInteractions();
220
Erik Kline5acb4e32017-07-04 18:28:11 +0900221 // In reality, the UpstreamNetworkMonitor would have passed down to us
222 // a covering set of local prefixes representing a minimum essential
223 // set plus all the prefixes on networks with network agents.
224 //
225 // We simulate that there, and then add upstream elements one by one
226 // and watch what happens.
227 final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>();
228 for (String s : new String[]{
229 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) {
230 minimumLocalPrefixes.add(new IpPrefix(s));
231 }
232 offload.setLocalPrefixes(minimumLocalPrefixes);
233 inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
234 ArrayList<String> localPrefixes = mStringArrayCaptor.getValue();
235 assertEquals(4, localPrefixes.size());
236 assertTrue(localPrefixes.contains("127.0.0.0/8"));
237 assertTrue(localPrefixes.contains("192.0.2.0/24"));
238 assertTrue(localPrefixes.contains("fe80::/64"));
239 assertTrue(localPrefixes.contains("2001:db8::/64"));
Erik Kline7990aef2017-06-01 20:11:25 +0900240 inOrder.verifyNoMoreInteractions();
Erik Kline5acb4e32017-07-04 18:28:11 +0900241
242 offload.setUpstreamLinkProperties(null);
243 // No change in local addresses means no call to setLocalPrefixes().
244 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
245 // This LinkProperties value does not differ from the default upstream.
246 // There should be no extraneous call to setUpstreamParameters().
247 inOrder.verify(mHardware, never()).setUpstreamParameters(
248 anyObject(), anyObject(), anyObject(), anyObject());
249 inOrder.verifyNoMoreInteractions();
Erik Kline7990aef2017-06-01 20:11:25 +0900250
251 final LinkProperties lp = new LinkProperties();
252
253 final String testIfName = "rmnet_data17";
254 lp.setInterfaceName(testIfName);
255 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900256 // No change in local addresses means no call to setLocalPrefixes().
257 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900258 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
Erik Kline664d2082017-06-15 18:06:34 +0900259 eq(testIfName), eq(null), eq(null), eq(null));
Erik Kline7990aef2017-06-01 20:11:25 +0900260 inOrder.verifyNoMoreInteractions();
261
262 final String ipv4Addr = "192.0.2.5";
263 final String linkAddr = ipv4Addr + "/24";
264 lp.addLinkAddress(new LinkAddress(linkAddr));
Erik Kline5acb4e32017-07-04 18:28:11 +0900265 lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24")));
Erik Kline7990aef2017-06-01 20:11:25 +0900266 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900267 // IPv4 prefixes and addresses on the upstream are simply left as whole
268 // prefixes (already passed in from UpstreamNetworkMonitor code). If a
269 // tethering client sends traffic to the IPv4 default router or other
270 // clients on the upstream this will not be hardware-forwarded, and that
271 // should be fine for now. Ergo: no change in local addresses, no call
272 // to setLocalPrefixes().
273 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900274 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
Erik Kline664d2082017-06-15 18:06:34 +0900275 eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900276 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Erik Kline7990aef2017-06-01 20:11:25 +0900277 inOrder.verifyNoMoreInteractions();
278
279 final String ipv4Gateway = "192.0.2.1";
280 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
281 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900282 // No change in local addresses means no call to setLocalPrefixes().
283 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900284 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
Erik Kline664d2082017-06-15 18:06:34 +0900285 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900286 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Erik Kline7990aef2017-06-01 20:11:25 +0900287 inOrder.verifyNoMoreInteractions();
288
289 final String ipv6Gw1 = "fe80::cafe";
290 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1)));
291 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900292 // No change in local addresses means no call to setLocalPrefixes().
293 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900294 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
295 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900296 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Erik Kline7990aef2017-06-01 20:11:25 +0900297 ArrayList<String> v6gws = mStringArrayCaptor.getValue();
298 assertEquals(1, v6gws.size());
299 assertTrue(v6gws.contains(ipv6Gw1));
300 inOrder.verifyNoMoreInteractions();
301
302 final String ipv6Gw2 = "fe80::d00d";
303 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2)));
304 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900305 // No change in local addresses means no call to setLocalPrefixes().
306 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900307 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
308 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900309 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Erik Kline7990aef2017-06-01 20:11:25 +0900310 v6gws = mStringArrayCaptor.getValue();
311 assertEquals(2, v6gws.size());
312 assertTrue(v6gws.contains(ipv6Gw1));
313 assertTrue(v6gws.contains(ipv6Gw2));
314 inOrder.verifyNoMoreInteractions();
315
316 final LinkProperties stacked = new LinkProperties();
317 stacked.setInterfaceName("stacked");
318 stacked.addLinkAddress(new LinkAddress("192.0.2.129/25"));
319 stacked.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
320 stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00")));
321 assertTrue(lp.addStackedLink(stacked));
322 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900323 // No change in local addresses means no call to setLocalPrefixes().
324 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900325 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
326 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900327 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Erik Kline7990aef2017-06-01 20:11:25 +0900328 v6gws = mStringArrayCaptor.getValue();
329 assertEquals(2, v6gws.size());
330 assertTrue(v6gws.contains(ipv6Gw1));
331 assertTrue(v6gws.contains(ipv6Gw2));
332 inOrder.verifyNoMoreInteractions();
Erik Kline5acb4e32017-07-04 18:28:11 +0900333
334 // Add in some IPv6 upstream info. When there is a tethered downstream
335 // making use of the IPv6 prefix we would expect to see the /64 route
336 // removed from "local prefixes" and /128s added for the upstream IPv6
337 // addresses. This is not yet implemented, and for now we simply
338 // expect to see these /128s.
339 lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64")));
340 // "2001:db8::/64" plus "assigned" ASCII in hex
341 lp.addLinkAddress(new LinkAddress("2001:db8::6173:7369:676e:6564/64"));
342 // "2001:db8::/64" plus "random" ASCII in hex
343 lp.addLinkAddress(new LinkAddress("2001:db8::7261:6e64:6f6d/64"));
344 offload.setUpstreamLinkProperties(lp);
345 inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
346 localPrefixes = mStringArrayCaptor.getValue();
347 assertEquals(6, localPrefixes.size());
348 assertTrue(localPrefixes.contains("127.0.0.0/8"));
349 assertTrue(localPrefixes.contains("192.0.2.0/24"));
350 assertTrue(localPrefixes.contains("fe80::/64"));
351 assertTrue(localPrefixes.contains("2001:db8::/64"));
352 assertTrue(localPrefixes.contains("2001:db8::6173:7369:676e:6564/128"));
353 assertTrue(localPrefixes.contains("2001:db8::7261:6e64:6f6d/128"));
354 // The relevant parts of the LinkProperties have not changed, but at the
355 // moment we do not de-dup upstream LinkProperties this carefully.
356 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
357 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
358 v6gws = mStringArrayCaptor.getValue();
359 assertEquals(2, v6gws.size());
360 assertTrue(v6gws.contains(ipv6Gw1));
361 assertTrue(v6gws.contains(ipv6Gw2));
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900362 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Erik Kline5acb4e32017-07-04 18:28:11 +0900363 inOrder.verifyNoMoreInteractions();
364
365 // Completely identical LinkProperties updates are de-duped.
366 offload.setUpstreamLinkProperties(lp);
367 // This LinkProperties value does not differ from the default upstream.
368 // There should be no extraneous call to setUpstreamParameters().
369 inOrder.verify(mHardware, never()).setUpstreamParameters(
370 anyObject(), anyObject(), anyObject(), anyObject());
371 inOrder.verifyNoMoreInteractions();
Erik Kline7990aef2017-06-01 20:11:25 +0900372 }
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900373
374 private void assertNetworkStats(String iface, ForwardedStats stats, NetworkStats.Entry entry) {
375 assertEquals(iface, entry.iface);
376 assertEquals(stats.rxBytes, entry.rxBytes);
377 assertEquals(stats.txBytes, entry.txBytes);
378 assertEquals(SET_DEFAULT, entry.set);
379 assertEquals(TAG_NONE, entry.tag);
380 assertEquals(UID_TETHERING, entry.uid);
381 }
382
383 @Test
384 public void testGetForwardedStats() throws Exception {
385 setupFunctioningHardwareInterface();
386 enableOffload();
387
388 final OffloadController offload = makeOffloadController();
389 offload.start();
390
391 final String ethernetIface = "eth1";
392 final String mobileIface = "rmnet_data0";
393
394 ForwardedStats ethernetStats = new ForwardedStats();
395 ethernetStats.rxBytes = 12345;
396 ethernetStats.txBytes = 54321;
397
398 ForwardedStats mobileStats = new ForwardedStats();
399 mobileStats.rxBytes = 999;
400 mobileStats.txBytes = 99999;
401
402 when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats);
403 when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn(mobileStats);
404
405 final LinkProperties lp = new LinkProperties();
406 lp.setInterfaceName(ethernetIface);
407 offload.setUpstreamLinkProperties(lp);
408
409 lp.setInterfaceName(mobileIface);
410 offload.setUpstreamLinkProperties(lp);
411
412 lp.setInterfaceName(ethernetIface);
413 offload.setUpstreamLinkProperties(lp);
414
415 ethernetStats.rxBytes = 100000;
416 ethernetStats.txBytes = 100000;
417 offload.setUpstreamLinkProperties(null);
418
419 NetworkStats stats = mTetherStatsProviderCaptor.getValue().getTetherStats();
420 assertEquals(2, stats.size());
421
422 NetworkStats.Entry entry = null;
423 int ethernetPosition = ethernetIface.equals(stats.getValues(0, entry).iface) ? 0 : 1;
424 int mobilePosition = 1 - ethernetPosition;
425
426 entry = stats.getValues(mobilePosition, entry);
427 assertNetworkStats(mobileIface, mobileStats, entry);
428
429 ethernetStats.rxBytes = 12345 + 100000;
430 ethernetStats.txBytes = 54321 + 100000;
431 entry = stats.getValues(ethernetPosition, entry);
432 assertNetworkStats(ethernetIface, ethernetStats, entry);
433 }
Lorenzo Colitti50b60fc2017-08-11 13:47:49 +0900434
435 @Test
436 public void testSetInterfaceQuota() throws Exception {
437 setupFunctioningHardwareInterface();
438 enableOffload();
439
440 final OffloadController offload = makeOffloadController();
441 offload.start();
442
443 final String ethernetIface = "eth1";
444 final String mobileIface = "rmnet_data0";
445 final long ethernetLimit = 12345;
446 final long mobileLimit = 12345678;
447
448 final LinkProperties lp = new LinkProperties();
449 lp.setInterfaceName(ethernetIface);
450 offload.setUpstreamLinkProperties(lp);
451
452 ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue();
453 final InOrder inOrder = inOrder(mHardware);
454 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true);
455 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true);
456
457 // Applying an interface quota to the current upstream immediately sends it to the hardware.
458 provider.setInterfaceQuota(ethernetIface, ethernetLimit);
459 waitForIdle();
460 inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit);
461 inOrder.verifyNoMoreInteractions();
462
463 // Applying an interface quota to another upstream does not take any immediate action.
464 provider.setInterfaceQuota(mobileIface, mobileLimit);
465 waitForIdle();
466 inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong());
467
468 // Switching to that upstream causes the quota to be applied if the parameters were applied
469 // correctly.
470 lp.setInterfaceName(mobileIface);
471 offload.setUpstreamLinkProperties(lp);
472 waitForIdle();
473 inOrder.verify(mHardware).setDataLimit(mobileIface, mobileLimit);
474
475 // Setting a limit of ITetheringStatsProvider.QUOTA_UNLIMITED causes the limit to be set
476 // to Long.MAX_VALUE.
477 provider.setInterfaceQuota(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED);
478 waitForIdle();
479 inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE);
480
481 // If setting upstream parameters fails, then the data limit is not set.
482 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false);
483 lp.setInterfaceName(ethernetIface);
484 offload.setUpstreamLinkProperties(lp);
485 provider.setInterfaceQuota(mobileIface, mobileLimit);
486 waitForIdle();
487 inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong());
488
489 // If setting the data limit fails while changing upstreams, offload is stopped.
490 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true);
491 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false);
492 lp.setInterfaceName(mobileIface);
493 offload.setUpstreamLinkProperties(lp);
494 provider.setInterfaceQuota(mobileIface, mobileLimit);
495 waitForIdle();
496 inOrder.verify(mHardware).stopOffloadControl();
497 }
Lorenzo Colitti9f0baa92017-08-15 19:25:51 +0900498
499 @Test
500 public void testDataLimitCallback() throws Exception {
501 setupFunctioningHardwareInterface();
502 enableOffload();
503
504 final OffloadController offload = makeOffloadController();
505 offload.start();
506
507 OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
508 callback.onStoppedLimitReached();
509 verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
510 }
Erik Kline92c4db02017-05-31 10:21:32 +0900511}