blob: 2a8efc046ee3a189f9c3ee58a3ff5934822e29de [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;
Lorenzo Colittif1912ca2017-08-17 19:23:08 +090020import static android.net.NetworkStats.STATS_PER_IFACE;
21import static android.net.NetworkStats.STATS_PER_UID;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090022import static android.net.NetworkStats.TAG_NONE;
Lorenzo Colittif1912ca2017-08-17 19:23:08 +090023import static android.net.NetworkStats.UID_ALL;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090024import static android.net.TrafficStats.UID_TETHERING;
Erik Kline92c4db02017-05-31 10:21:32 +090025import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090026import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats;
Erik Kline7990aef2017-06-01 20:11:25 +090027import static org.junit.Assert.assertEquals;
28import static org.junit.Assert.assertTrue;
Erik Kline92c4db02017-05-31 10:21:32 +090029import static org.junit.Assert.fail;
30import static org.mockito.Matchers.any;
Lorenzo Colitti50b60fc2017-08-11 13:47:49 +090031import static org.mockito.Matchers.anyLong;
Erik Kline92c4db02017-05-31 10:21:32 +090032import static org.mockito.Matchers.anyObject;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090033import static org.mockito.Matchers.anyString;
Erik Kline7990aef2017-06-01 20:11:25 +090034import static org.mockito.Matchers.eq;
Erik Klineaabdaa92017-08-31 21:09:45 +090035import static org.mockito.Mockito.clearInvocations;
Erik Kline92c4db02017-05-31 10:21:32 +090036import static org.mockito.Mockito.inOrder;
37import static org.mockito.Mockito.never;
Erik Kline7990aef2017-06-01 20:11:25 +090038import static org.mockito.Mockito.reset;
Erik Kline92c4db02017-05-31 10:21:32 +090039import static org.mockito.Mockito.times;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090040import static org.mockito.Mockito.verify;
Erik Klineaabdaa92017-08-31 21:09:45 +090041import static org.mockito.Mockito.verifyNoMoreInteractions;
Erik Kline92c4db02017-05-31 10:21:32 +090042import static org.mockito.Mockito.when;
43
44import android.content.Context;
Erik Klineec372752017-06-07 16:33:19 +090045import android.content.pm.ApplicationInfo;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090046import android.net.ITetheringStatsProvider;
Erik Kline5acb4e32017-07-04 18:28:11 +090047import android.net.IpPrefix;
Erik Kline7990aef2017-06-01 20:11:25 +090048import android.net.LinkAddress;
49import android.net.LinkProperties;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090050import android.net.NetworkStats;
Erik Kline7990aef2017-06-01 20:11:25 +090051import android.net.RouteInfo;
Erik Kline92c4db02017-05-31 10:21:32 +090052import android.net.util.SharedLog;
Lorenzo Colitti50b60fc2017-08-11 13:47:49 +090053import android.os.ConditionVariable;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090054import android.os.Handler;
55import android.os.Looper;
56import android.os.INetworkManagementService;
Erik Kline92c4db02017-05-31 10:21:32 +090057import android.provider.Settings;
58import android.provider.Settings.SettingNotFoundException;
59
60import android.support.test.filters.SmallTest;
61import android.support.test.runner.AndroidJUnit4;
62import android.test.mock.MockContentResolver;
63import com.android.internal.util.test.FakeSettingsProvider;
64
Erik Kline7990aef2017-06-01 20:11:25 +090065import java.net.InetAddress;
66import java.util.ArrayList;
Erik Kline5acb4e32017-07-04 18:28:11 +090067import java.util.HashSet;
68import java.util.Set;
Erik Kline7990aef2017-06-01 20:11:25 +090069
Erik Kline5eaa7ed2017-07-07 17:38:30 +090070import org.junit.After;
Erik Kline92c4db02017-05-31 10:21:32 +090071import org.junit.Before;
Colin Cross46a435a2017-08-29 12:18:55 -070072import org.junit.Ignore;
Erik Kline92c4db02017-05-31 10:21:32 +090073import org.junit.runner.RunWith;
74import org.junit.Test;
Erik Kline7990aef2017-06-01 20:11:25 +090075import org.mockito.ArgumentCaptor;
Erik Kline92c4db02017-05-31 10:21:32 +090076import org.mockito.InOrder;
77import org.mockito.Mock;
78import org.mockito.MockitoAnnotations;
79
80
81@RunWith(AndroidJUnit4.class)
82@SmallTest
83public class OffloadControllerTest {
Erik Klineb3bb26e2017-07-06 19:49:35 +090084 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";
Erik Kline92c4db02017-05-31 10:21:32 +090093
94 @Mock private OffloadHardwareInterface mHardware;
Erik Klineec372752017-06-07 16:33:19 +090095 @Mock private ApplicationInfo mApplicationInfo;
Erik Kline92c4db02017-05-31 10:21:32 +090096 @Mock private Context mContext;
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +090097 @Mock private INetworkManagementService mNMService;
Erik Klinedd4d5822017-06-12 18:20:08 +090098 private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
99 ArgumentCaptor.forClass(ArrayList.class);
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900100 private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor =
101 ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class);
Lorenzo Colitti9f0baa92017-08-15 19:25:51 +0900102 private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor =
103 ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class);
Erik Kline92c4db02017-05-31 10:21:32 +0900104 private MockContentResolver mContentResolver;
105
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900106 @Before public void setUp() {
Erik Kline92c4db02017-05-31 10:21:32 +0900107 MockitoAnnotations.initMocks(this);
Erik Klineec372752017-06-07 16:33:19 +0900108 when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
109 when(mContext.getPackageName()).thenReturn("OffloadControllerTest");
Erik Kline92c4db02017-05-31 10:21:32 +0900110 mContentResolver = new MockContentResolver(mContext);
111 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
Erik Kline92c4db02017-05-31 10:21:32 +0900112 when(mContext.getContentResolver()).thenReturn(mContentResolver);
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900113 // TODO: call this when available.
114 // FakeSettingsProvider.clearSettingsProvider();
115 }
116
117 @After public void tearDown() throws Exception {
118 // TODO: call this when available.
119 // FakeSettingsProvider.clearSettingsProvider();
Erik Kline92c4db02017-05-31 10:21:32 +0900120 }
121
122 private void setupFunctioningHardwareInterface() {
123 when(mHardware.initOffloadConfig()).thenReturn(true);
Lorenzo Colitti9f0baa92017-08-15 19:25:51 +0900124 when(mHardware.initOffloadControl(mControlCallbackCaptor.capture()))
Erik Kline92c4db02017-05-31 10:21:32 +0900125 .thenReturn(true);
Lorenzo Colittiddce7ee2017-08-21 12:34:50 +0900126 when(mHardware.setUpstreamParameters(anyString(), any(), any(), any())).thenReturn(true);
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900127 when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
Lorenzo Colittiddce7ee2017-08-21 12:34:50 +0900128 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true);
Erik Kline92c4db02017-05-31 10:21:32 +0900129 }
130
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900131 private void enableOffload() {
132 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
133 }
134
Lorenzo Colitti50b60fc2017-08-11 13:47:49 +0900135 private void waitForIdle() {
136 ConditionVariable cv = new ConditionVariable();
137 new Handler(Looper.getMainLooper()).post(() -> { cv.open(); });
138 cv.block();
139 }
140
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900141 private OffloadController makeOffloadController() throws Exception {
142 OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()),
143 mHardware, mContentResolver, mNMService, new SharedLog("test"));
144 verify(mNMService).registerTetheringStatsProvider(
145 mTetherStatsProviderCaptor.capture(), anyString());
146 return offload;
147 }
148
Colin Cross46a435a2017-08-29 12:18:55 -0700149 @Test
150 @Ignore("Restore when FakeSettingsProvider.clearSettingsProvider() is available.")
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900151 public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception {
Erik Kline92c4db02017-05-31 10:21:32 +0900152 setupFunctioningHardwareInterface();
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900153 when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
Erik Kline92c4db02017-05-31 10:21:32 +0900154 try {
155 Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED);
156 fail();
157 } catch (SettingNotFoundException expected) {}
158
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900159 final OffloadController offload = makeOffloadController();
Erik Kline92c4db02017-05-31 10:21:32 +0900160 offload.start();
161
162 final InOrder inOrder = inOrder(mHardware);
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900163 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
164 inOrder.verify(mHardware, never()).initOffloadConfig();
165 inOrder.verify(mHardware, never()).initOffloadControl(
166 any(OffloadHardwareInterface.ControlCallback.class));
167 inOrder.verifyNoMoreInteractions();
168 }
169
Colin Cross46a435a2017-08-29 12:18:55 -0700170 @Test
171 @Ignore("Restore when FakeSettingsProvider.clearSettingsProvider() is available.")
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900172 public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception {
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900173 setupFunctioningHardwareInterface();
174 when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
175 try {
176 Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED);
177 fail();
178 } catch (SettingNotFoundException expected) {}
179
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900180 final OffloadController offload = makeOffloadController();
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900181 offload.start();
182
183 final InOrder inOrder = inOrder(mHardware);
184 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 testSettingsAllowsStart() throws Exception {
Erik Kline92c4db02017-05-31 10:21:32 +0900193 setupFunctioningHardwareInterface();
194 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
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, times(1)).initOffloadConfig();
202 inOrder.verify(mHardware, times(1)).initOffloadControl(
203 any(OffloadHardwareInterface.ControlCallback.class));
204 inOrder.verifyNoMoreInteractions();
205 }
206
207 @Test
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900208 public void testSettingsDisablesStart() throws Exception {
Erik Kline92c4db02017-05-31 10:21:32 +0900209 setupFunctioningHardwareInterface();
210 Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1);
211
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900212 final OffloadController offload = makeOffloadController();
Erik Kline92c4db02017-05-31 10:21:32 +0900213 offload.start();
214
215 final InOrder inOrder = inOrder(mHardware);
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900216 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
Erik Kline92c4db02017-05-31 10:21:32 +0900217 inOrder.verify(mHardware, never()).initOffloadConfig();
218 inOrder.verify(mHardware, never()).initOffloadControl(anyObject());
219 inOrder.verifyNoMoreInteractions();
220 }
Erik Kline7990aef2017-06-01 20:11:25 +0900221
222 @Test
223 public void testSetUpstreamLinkPropertiesWorking() throws Exception {
224 setupFunctioningHardwareInterface();
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900225 enableOffload();
226
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900227 final OffloadController offload = makeOffloadController();
Erik Kline7990aef2017-06-01 20:11:25 +0900228 offload.start();
229
230 final InOrder inOrder = inOrder(mHardware);
Erik Kline5eaa7ed2017-07-07 17:38:30 +0900231 inOrder.verify(mHardware, times(1)).getDefaultTetherOffloadDisabled();
Erik Kline7990aef2017-06-01 20:11:25 +0900232 inOrder.verify(mHardware, times(1)).initOffloadConfig();
233 inOrder.verify(mHardware, times(1)).initOffloadControl(
234 any(OffloadHardwareInterface.ControlCallback.class));
235 inOrder.verifyNoMoreInteractions();
236
Erik Kline5acb4e32017-07-04 18:28:11 +0900237 // In reality, the UpstreamNetworkMonitor would have passed down to us
238 // a covering set of local prefixes representing a minimum essential
239 // set plus all the prefixes on networks with network agents.
240 //
241 // We simulate that there, and then add upstream elements one by one
242 // and watch what happens.
243 final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>();
244 for (String s : new String[]{
245 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) {
246 minimumLocalPrefixes.add(new IpPrefix(s));
247 }
248 offload.setLocalPrefixes(minimumLocalPrefixes);
249 inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
250 ArrayList<String> localPrefixes = mStringArrayCaptor.getValue();
251 assertEquals(4, localPrefixes.size());
Erik Klineb3bb26e2017-07-06 19:49:35 +0900252 assertArrayListContains(localPrefixes,
253 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64");
Erik Kline7990aef2017-06-01 20:11:25 +0900254 inOrder.verifyNoMoreInteractions();
Erik Kline5acb4e32017-07-04 18:28:11 +0900255
256 offload.setUpstreamLinkProperties(null);
257 // No change in local addresses means no call to setLocalPrefixes().
258 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
259 // This LinkProperties value does not differ from the default upstream.
260 // There should be no extraneous call to setUpstreamParameters().
261 inOrder.verify(mHardware, never()).setUpstreamParameters(
262 anyObject(), anyObject(), anyObject(), anyObject());
263 inOrder.verifyNoMoreInteractions();
Erik Kline7990aef2017-06-01 20:11:25 +0900264
265 final LinkProperties lp = new LinkProperties();
266
267 final String testIfName = "rmnet_data17";
268 lp.setInterfaceName(testIfName);
269 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900270 // No change in local addresses means no call to setLocalPrefixes().
271 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900272 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
Erik Kline664d2082017-06-15 18:06:34 +0900273 eq(testIfName), eq(null), eq(null), eq(null));
Lorenzo Colittiddce7ee2017-08-21 12:34:50 +0900274 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE));
Erik Kline7990aef2017-06-01 20:11:25 +0900275 inOrder.verifyNoMoreInteractions();
276
277 final String ipv4Addr = "192.0.2.5";
278 final String linkAddr = ipv4Addr + "/24";
279 lp.addLinkAddress(new LinkAddress(linkAddr));
Erik Kline5acb4e32017-07-04 18:28:11 +0900280 lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24")));
Erik Kline7990aef2017-06-01 20:11:25 +0900281 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900282 // IPv4 prefixes and addresses on the upstream are simply left as whole
283 // prefixes (already passed in from UpstreamNetworkMonitor code). If a
284 // tethering client sends traffic to the IPv4 default router or other
285 // clients on the upstream this will not be hardware-forwarded, and that
286 // should be fine for now. Ergo: no change in local addresses, no call
287 // to setLocalPrefixes().
288 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900289 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
Erik Kline664d2082017-06-15 18:06:34 +0900290 eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900291 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Lorenzo Colittiddce7ee2017-08-21 12:34:50 +0900292 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE));
Erik Kline7990aef2017-06-01 20:11:25 +0900293 inOrder.verifyNoMoreInteractions();
294
295 final String ipv4Gateway = "192.0.2.1";
296 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
297 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900298 // No change in local addresses means no call to setLocalPrefixes().
299 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900300 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
Erik Kline664d2082017-06-15 18:06:34 +0900301 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900302 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Lorenzo Colittiddce7ee2017-08-21 12:34:50 +0900303 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE));
Erik Kline7990aef2017-06-01 20:11:25 +0900304 inOrder.verifyNoMoreInteractions();
305
306 final String ipv6Gw1 = "fe80::cafe";
307 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1)));
308 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900309 // No change in local addresses means no call to setLocalPrefixes().
310 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900311 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
312 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900313 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Erik Kline7990aef2017-06-01 20:11:25 +0900314 ArrayList<String> v6gws = mStringArrayCaptor.getValue();
315 assertEquals(1, v6gws.size());
316 assertTrue(v6gws.contains(ipv6Gw1));
Lorenzo Colittiddce7ee2017-08-21 12:34:50 +0900317 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE));
Erik Kline7990aef2017-06-01 20:11:25 +0900318 inOrder.verifyNoMoreInteractions();
319
320 final String ipv6Gw2 = "fe80::d00d";
321 lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2)));
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));
Lorenzo Colittiddce7ee2017-08-21 12:34:50 +0900332 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE));
Erik Kline7990aef2017-06-01 20:11:25 +0900333 inOrder.verifyNoMoreInteractions();
334
335 final LinkProperties stacked = new LinkProperties();
336 stacked.setInterfaceName("stacked");
337 stacked.addLinkAddress(new LinkAddress("192.0.2.129/25"));
338 stacked.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
339 stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00")));
340 assertTrue(lp.addStackedLink(stacked));
341 offload.setUpstreamLinkProperties(lp);
Erik Kline5acb4e32017-07-04 18:28:11 +0900342 // No change in local addresses means no call to setLocalPrefixes().
343 inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
Erik Kline7990aef2017-06-01 20:11:25 +0900344 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
345 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900346 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Erik Kline7990aef2017-06-01 20:11:25 +0900347 v6gws = mStringArrayCaptor.getValue();
348 assertEquals(2, v6gws.size());
349 assertTrue(v6gws.contains(ipv6Gw1));
350 assertTrue(v6gws.contains(ipv6Gw2));
Lorenzo Colittiddce7ee2017-08-21 12:34:50 +0900351 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE));
Erik Kline7990aef2017-06-01 20:11:25 +0900352 inOrder.verifyNoMoreInteractions();
Erik Kline5acb4e32017-07-04 18:28:11 +0900353
354 // Add in some IPv6 upstream info. When there is a tethered downstream
355 // making use of the IPv6 prefix we would expect to see the /64 route
356 // removed from "local prefixes" and /128s added for the upstream IPv6
357 // addresses. This is not yet implemented, and for now we simply
358 // expect to see these /128s.
359 lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64")));
360 // "2001:db8::/64" plus "assigned" ASCII in hex
361 lp.addLinkAddress(new LinkAddress("2001:db8::6173:7369:676e:6564/64"));
362 // "2001:db8::/64" plus "random" ASCII in hex
363 lp.addLinkAddress(new LinkAddress("2001:db8::7261:6e64:6f6d/64"));
364 offload.setUpstreamLinkProperties(lp);
365 inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
366 localPrefixes = mStringArrayCaptor.getValue();
367 assertEquals(6, localPrefixes.size());
Erik Klineb3bb26e2017-07-06 19:49:35 +0900368 assertArrayListContains(localPrefixes,
369 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64",
370 "2001:db8::6173:7369:676e:6564/128", "2001:db8::7261:6e64:6f6d/128");
Erik Kline5acb4e32017-07-04 18:28:11 +0900371 // The relevant parts of the LinkProperties have not changed, but at the
372 // moment we do not de-dup upstream LinkProperties this carefully.
373 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
374 eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
375 v6gws = mStringArrayCaptor.getValue();
376 assertEquals(2, v6gws.size());
377 assertTrue(v6gws.contains(ipv6Gw1));
378 assertTrue(v6gws.contains(ipv6Gw2));
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900379 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
Lorenzo Colittiddce7ee2017-08-21 12:34:50 +0900380 inOrder.verify(mHardware, times(1)).setDataLimit(eq(testIfName), eq(Long.MAX_VALUE));
Erik Kline5acb4e32017-07-04 18:28:11 +0900381 inOrder.verifyNoMoreInteractions();
382
383 // Completely identical LinkProperties updates are de-duped.
384 offload.setUpstreamLinkProperties(lp);
385 // This LinkProperties value does not differ from the default upstream.
386 // There should be no extraneous call to setUpstreamParameters().
387 inOrder.verify(mHardware, never()).setUpstreamParameters(
388 anyObject(), anyObject(), anyObject(), anyObject());
389 inOrder.verifyNoMoreInteractions();
Erik Kline7990aef2017-06-01 20:11:25 +0900390 }
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900391
392 private void assertNetworkStats(String iface, ForwardedStats stats, NetworkStats.Entry entry) {
393 assertEquals(iface, entry.iface);
394 assertEquals(stats.rxBytes, entry.rxBytes);
395 assertEquals(stats.txBytes, entry.txBytes);
396 assertEquals(SET_DEFAULT, entry.set);
397 assertEquals(TAG_NONE, entry.tag);
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900398 }
399
400 @Test
401 public void testGetForwardedStats() throws Exception {
402 setupFunctioningHardwareInterface();
403 enableOffload();
404
405 final OffloadController offload = makeOffloadController();
406 offload.start();
407
408 final String ethernetIface = "eth1";
409 final String mobileIface = "rmnet_data0";
410
411 ForwardedStats ethernetStats = new ForwardedStats();
412 ethernetStats.rxBytes = 12345;
413 ethernetStats.txBytes = 54321;
414
415 ForwardedStats mobileStats = new ForwardedStats();
416 mobileStats.rxBytes = 999;
417 mobileStats.txBytes = 99999;
418
419 when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats);
420 when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn(mobileStats);
421
Hugo Benichi752c1282017-08-22 13:57:41 +0900422 InOrder inOrder = inOrder(mHardware);
423
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900424 final LinkProperties lp = new LinkProperties();
425 lp.setInterfaceName(ethernetIface);
426 offload.setUpstreamLinkProperties(lp);
Hugo Benichi752c1282017-08-22 13:57:41 +0900427 // Previous upstream was null, so no stats are fetched.
428 inOrder.verify(mHardware, never()).getForwardedStats(any());
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900429
430 lp.setInterfaceName(mobileIface);
431 offload.setUpstreamLinkProperties(lp);
Hugo Benichi752c1282017-08-22 13:57:41 +0900432 // Expect that we fetch stats from the previous upstream.
433 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(ethernetIface));
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900434
435 lp.setInterfaceName(ethernetIface);
436 offload.setUpstreamLinkProperties(lp);
Hugo Benichi752c1282017-08-22 13:57:41 +0900437 // Expect that we fetch stats from the previous upstream.
438 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(mobileIface));
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900439
Hugo Benichi752c1282017-08-22 13:57:41 +0900440 ethernetStats = new ForwardedStats();
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900441 ethernetStats.rxBytes = 100000;
442 ethernetStats.txBytes = 100000;
Hugo Benichi752c1282017-08-22 13:57:41 +0900443 when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats);
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900444 offload.setUpstreamLinkProperties(null);
Erik Klineaabdaa92017-08-31 21:09:45 +0900445 // Expect that we first clear the HAL's upstream parameters.
446 inOrder.verify(mHardware, times(1)).setUpstreamParameters(
447 eq(""), eq("0.0.0.0"), eq("0.0.0.0"), eq(null));
Hugo Benichi752c1282017-08-22 13:57:41 +0900448 // Expect that we fetch stats from the previous upstream.
449 inOrder.verify(mHardware, times(1)).getForwardedStats(eq(ethernetIface));
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900450
Lorenzo Colittif1912ca2017-08-17 19:23:08 +0900451 ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue();
452 NetworkStats stats = provider.getTetherStats(STATS_PER_IFACE);
453 NetworkStats perUidStats = provider.getTetherStats(STATS_PER_UID);
Hugo Benichi752c1282017-08-22 13:57:41 +0900454 waitForIdle();
455 // There is no current upstream, so no stats are fetched.
Lorenzo Colittif612b602017-08-24 12:40:07 +0900456 inOrder.verify(mHardware, never()).getForwardedStats(any());
Hugo Benichi752c1282017-08-22 13:57:41 +0900457 inOrder.verifyNoMoreInteractions();
Lorenzo Colittif1912ca2017-08-17 19:23:08 +0900458
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900459 assertEquals(2, stats.size());
Lorenzo Colittif1912ca2017-08-17 19:23:08 +0900460 assertEquals(2, perUidStats.size());
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900461
462 NetworkStats.Entry entry = null;
Lorenzo Colittif1912ca2017-08-17 19:23:08 +0900463 for (int i = 0; i < stats.size(); i++) {
464 assertEquals(UID_ALL, stats.getValues(i, entry).uid);
465 assertEquals(UID_TETHERING, perUidStats.getValues(i, entry).uid);
466 }
467
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900468 int ethernetPosition = ethernetIface.equals(stats.getValues(0, entry).iface) ? 0 : 1;
469 int mobilePosition = 1 - ethernetPosition;
470
471 entry = stats.getValues(mobilePosition, entry);
472 assertNetworkStats(mobileIface, mobileStats, entry);
Lorenzo Colittif1912ca2017-08-17 19:23:08 +0900473 entry = perUidStats.getValues(mobilePosition, entry);
474 assertNetworkStats(mobileIface, mobileStats, entry);
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900475
476 ethernetStats.rxBytes = 12345 + 100000;
477 ethernetStats.txBytes = 54321 + 100000;
478 entry = stats.getValues(ethernetPosition, entry);
479 assertNetworkStats(ethernetIface, ethernetStats, entry);
Lorenzo Colittif1912ca2017-08-17 19:23:08 +0900480 entry = perUidStats.getValues(ethernetPosition, entry);
481 assertNetworkStats(ethernetIface, ethernetStats, entry);
Lorenzo Colitti4ca0ba82017-07-12 15:48:07 +0900482 }
Lorenzo Colitti50b60fc2017-08-11 13:47:49 +0900483
484 @Test
485 public void testSetInterfaceQuota() throws Exception {
486 setupFunctioningHardwareInterface();
487 enableOffload();
488
489 final OffloadController offload = makeOffloadController();
490 offload.start();
491
492 final String ethernetIface = "eth1";
493 final String mobileIface = "rmnet_data0";
494 final long ethernetLimit = 12345;
495 final long mobileLimit = 12345678;
496
497 final LinkProperties lp = new LinkProperties();
498 lp.setInterfaceName(ethernetIface);
499 offload.setUpstreamLinkProperties(lp);
500
501 ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue();
502 final InOrder inOrder = inOrder(mHardware);
503 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true);
504 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true);
505
506 // Applying an interface quota to the current upstream immediately sends it to the hardware.
507 provider.setInterfaceQuota(ethernetIface, ethernetLimit);
508 waitForIdle();
509 inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit);
510 inOrder.verifyNoMoreInteractions();
511
512 // Applying an interface quota to another upstream does not take any immediate action.
513 provider.setInterfaceQuota(mobileIface, mobileLimit);
514 waitForIdle();
515 inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong());
516
517 // Switching to that upstream causes the quota to be applied if the parameters were applied
518 // correctly.
519 lp.setInterfaceName(mobileIface);
520 offload.setUpstreamLinkProperties(lp);
521 waitForIdle();
522 inOrder.verify(mHardware).setDataLimit(mobileIface, mobileLimit);
523
524 // Setting a limit of ITetheringStatsProvider.QUOTA_UNLIMITED causes the limit to be set
525 // to Long.MAX_VALUE.
526 provider.setInterfaceQuota(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED);
527 waitForIdle();
528 inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE);
529
530 // If setting upstream parameters fails, then the data limit is not set.
531 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false);
532 lp.setInterfaceName(ethernetIface);
533 offload.setUpstreamLinkProperties(lp);
534 provider.setInterfaceQuota(mobileIface, mobileLimit);
535 waitForIdle();
536 inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong());
537
538 // If setting the data limit fails while changing upstreams, offload is stopped.
539 when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true);
540 when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false);
541 lp.setInterfaceName(mobileIface);
542 offload.setUpstreamLinkProperties(lp);
543 provider.setInterfaceQuota(mobileIface, mobileLimit);
544 waitForIdle();
Lorenzo Colittiddce7ee2017-08-21 12:34:50 +0900545 inOrder.verify(mHardware).getForwardedStats(ethernetIface);
Lorenzo Colitti50b60fc2017-08-11 13:47:49 +0900546 inOrder.verify(mHardware).stopOffloadControl();
547 }
Lorenzo Colitti9f0baa92017-08-15 19:25:51 +0900548
549 @Test
550 public void testDataLimitCallback() throws Exception {
551 setupFunctioningHardwareInterface();
552 enableOffload();
553
554 final OffloadController offload = makeOffloadController();
555 offload.start();
556
557 OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
558 callback.onStoppedLimitReached();
559 verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
560 }
Erik Klineb3bb26e2017-07-06 19:49:35 +0900561
562 @Test
563 public void testAddRemoveDownstreams() throws Exception {
564 setupFunctioningHardwareInterface();
565 enableOffload();
566
567 final OffloadController offload = makeOffloadController();
568 offload.start();
569
570 final InOrder inOrder = inOrder(mHardware);
571 inOrder.verify(mHardware, times(1)).initOffloadConfig();
572 inOrder.verify(mHardware, times(1)).initOffloadControl(
573 any(OffloadHardwareInterface.ControlCallback.class));
574 inOrder.verifyNoMoreInteractions();
575
576 // Tethering makes several calls to setLocalPrefixes() before add/remove
577 // downstream calls are made. This is not tested here; only the behavior
578 // of notifyDownstreamLinkProperties() and removeDownstreamInterface()
579 // are tested.
580
581 // [1] USB tethering is started.
582 final LinkProperties usbLinkProperties = new LinkProperties();
583 usbLinkProperties.setInterfaceName(RNDIS0);
584 usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24"));
585 usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX)));
586 offload.notifyDownstreamLinkProperties(usbLinkProperties);
587 inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, USB_PREFIX);
588 inOrder.verifyNoMoreInteractions();
589
590 // [2] Routes for IPv6 link-local prefixes should never be added.
591 usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL)));
592 offload.notifyDownstreamLinkProperties(usbLinkProperties);
593 inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString());
594 inOrder.verifyNoMoreInteractions();
595
596 // [3] Add an IPv6 prefix for good measure. Only new offload-able
597 // prefixes should be passed to the HAL.
598 usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
599 usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX)));
600 offload.notifyDownstreamLinkProperties(usbLinkProperties);
601 inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX);
602 inOrder.verifyNoMoreInteractions();
603
604 // [4] Adding addresses doesn't affect notifyDownstreamLinkProperties().
605 // The address is passed in by a separate setLocalPrefixes() invocation.
606 usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::2/64"));
607 offload.notifyDownstreamLinkProperties(usbLinkProperties);
608 inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString());
609
610 // [5] Differences in local routes are converted into addDownstream()
611 // and removeDownstream() invocations accordingly.
612 usbLinkProperties.removeRoute(new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, RNDIS0));
613 usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX)));
614 offload.notifyDownstreamLinkProperties(usbLinkProperties);
615 inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX);
616 inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX);
617 inOrder.verifyNoMoreInteractions();
618
619 // [6] Removing a downstream interface which was never added causes no
620 // interactions with the HAL.
621 offload.removeDownstreamInterface(WLAN0);
622 inOrder.verifyNoMoreInteractions();
623
624 // [7] Removing an active downstream removes all remaining prefixes.
625 offload.removeDownstreamInterface(RNDIS0);
626 inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, USB_PREFIX);
627 inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX);
628 inOrder.verifyNoMoreInteractions();
629 }
630
Erik Klineaabdaa92017-08-31 21:09:45 +0900631 @Test
632 public void testControlCallbackOnStoppedUnsupportedFetchesAllStats() throws Exception {
633 setupFunctioningHardwareInterface();
634 enableOffload();
635
636 final OffloadController offload = makeOffloadController();
637 offload.start();
638
639 // Pretend to set a few different upstreams (only the interface name
640 // matters for this test; we're ignoring IP and route information).
641 final LinkProperties upstreamLp = new LinkProperties();
642 for (String ifname : new String[]{RMNET0, WLAN0, RMNET0}) {
643 upstreamLp.setInterfaceName(ifname);
644 offload.setUpstreamLinkProperties(upstreamLp);
645 }
646
647 // Clear invocation history, especially the getForwardedStats() calls
648 // that happen with setUpstreamParameters().
649 clearInvocations(mHardware);
650
651 OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
652 callback.onStoppedUnsupported();
653
654 // Verify forwarded stats behaviour.
655 verify(mHardware, times(1)).getForwardedStats(eq(RMNET0));
656 verify(mHardware, times(1)).getForwardedStats(eq(WLAN0));
657 verifyNoMoreInteractions(mHardware);
658 verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
659 verifyNoMoreInteractions(mNMService);
660 }
661
662 @Test
663 public void testControlCallbackOnSupportAvailableFetchesAllStatsAndPushesAllParameters()
664 throws Exception {
665 setupFunctioningHardwareInterface();
666 enableOffload();
667
668 final OffloadController offload = makeOffloadController();
669 offload.start();
670
671 // Pretend to set a few different upstreams (only the interface name
672 // matters for this test; we're ignoring IP and route information).
673 final LinkProperties upstreamLp = new LinkProperties();
674 for (String ifname : new String[]{RMNET0, WLAN0, RMNET0}) {
675 upstreamLp.setInterfaceName(ifname);
676 offload.setUpstreamLinkProperties(upstreamLp);
677 }
678
Erik Klinebc8b2ee2017-09-19 17:56:10 +0900679 // Pretend that some local prefixes and downstreams have been added
680 // (and removed, for good measure).
681 final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>();
682 for (String s : new String[]{
683 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) {
684 minimumLocalPrefixes.add(new IpPrefix(s));
685 }
686 offload.setLocalPrefixes(minimumLocalPrefixes);
687
688 final LinkProperties usbLinkProperties = new LinkProperties();
689 usbLinkProperties.setInterfaceName(RNDIS0);
690 usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24"));
691 usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX)));
692 offload.notifyDownstreamLinkProperties(usbLinkProperties);
693
694 final LinkProperties wifiLinkProperties = new LinkProperties();
695 wifiLinkProperties.setInterfaceName(WLAN0);
696 wifiLinkProperties.addLinkAddress(new LinkAddress("192.168.43.1/24"));
697 wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(WIFI_PREFIX)));
698 wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL)));
699 // Use a benchmark prefix (RFC 5180 + erratum), since the documentation
700 // prefix is included in the excluded prefix list.
701 wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::1/64"));
702 wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::2/64"));
703 wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix("2001:2::/64")));
704 offload.notifyDownstreamLinkProperties(wifiLinkProperties);
705
706 offload.removeDownstreamInterface(RNDIS0);
707
Erik Klineaabdaa92017-08-31 21:09:45 +0900708 // Clear invocation history, especially the getForwardedStats() calls
709 // that happen with setUpstreamParameters().
710 clearInvocations(mHardware);
711
712 OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
713 callback.onSupportAvailable();
714
715 // Verify forwarded stats behaviour.
716 verify(mHardware, times(1)).getForwardedStats(eq(RMNET0));
717 verify(mHardware, times(1)).getForwardedStats(eq(WLAN0));
718 verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
719 verifyNoMoreInteractions(mNMService);
720
721 // TODO: verify local prefixes and downstreams are also pushed to the HAL.
Erik Klinebc8b2ee2017-09-19 17:56:10 +0900722 verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
723 ArrayList<String> localPrefixes = mStringArrayCaptor.getValue();
724 assertEquals(4, localPrefixes.size());
725 assertArrayListContains(localPrefixes,
726 // TODO: The logic to find and exclude downstream IP prefixes
727 // is currently in Tethering's OffloadWrapper but must be moved
728 // into OffloadController proper. After this, also check for:
729 // "192.168.43.1/32", "2001:2::1/128", "2001:2::2/128"
730 "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64");
731 verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "192.168.43.0/24");
732 verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "2001:2::/64");
Erik Klineaabdaa92017-08-31 21:09:45 +0900733 verify(mHardware, times(1)).setUpstreamParameters(eq(RMNET0), any(), any(), any());
734 verify(mHardware, times(1)).setDataLimit(eq(RMNET0), anyLong());
735 verifyNoMoreInteractions(mHardware);
736 }
737
Erik Klineb3bb26e2017-07-06 19:49:35 +0900738 private static void assertArrayListContains(ArrayList<String> list, String... elems) {
739 for (String element : elems) {
Erik Klinebc8b2ee2017-09-19 17:56:10 +0900740 assertTrue(element + " not in list", list.contains(element));
Erik Klineb3bb26e2017-07-06 19:49:35 +0900741 }
742 }
Erik Kline92c4db02017-05-31 10:21:32 +0900743}