1497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley/*
2497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley * Copyright (C) 2016 The Android Open Source Project
3497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley *
4497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley * Licensed under the Apache License, Version 2.0 (the "License");
5497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley * you may not use this file except in compliance with the License.
6497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley * You may obtain a copy of the License at
7497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley *
8497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley *      http://www.apache.org/licenses/LICENSE-2.0
9497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley *
10497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley * Unless required by applicable law or agreed to in writing, software
11497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley * distributed under the License is distributed on an "AS IS" BASIS,
12497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley * See the License for the specific language governing permissions and
14497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley * limitations under the License.
15497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley */
16497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
17497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileypackage com.android.server.connectivity;
18497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
19c438e306cc69b9d4d62512030267e93011b29978Erik Klineimport static android.hardware.usb.UsbManager.USB_CONFIGURED;
20c438e306cc69b9d4d62512030267e93011b29978Erik Klineimport static android.hardware.usb.UsbManager.USB_CONNECTED;
21c438e306cc69b9d4d62512030267e93011b29978Erik Klineimport static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
227a26ba37f6a1205c8914c62c4756f24329317f6bErik Klineimport static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
237a26ba37f6a1205c8914c62c4756f24329317f6bErik Klineimport static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
247a26ba37f6a1205c8914c62c4756f24329317f6bErik Klineimport static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
257a26ba37f6a1205c8914c62c4756f24329317f6bErik Klineimport static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
267a26ba37f6a1205c8914c62c4756f24329317f6bErik Klineimport static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
27c438e306cc69b9d4d62512030267e93011b29978Erik Klineimport static android.net.ConnectivityManager.TETHERING_WIFI;
28c438e306cc69b9d4d62512030267e93011b29978Erik Klineimport static android.net.ConnectivityManager.TETHERING_USB;
297a26ba37f6a1205c8914c62c4756f24329317f6bErik Klineimport static android.net.ConnectivityManager.TYPE_MOBILE;
302efb827f61db989ab55792052c99713ef5f5eefaErik Klineimport static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
312efb827f61db989ab55792052c99713ef5f5eefaErik Klineimport static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
322efb827f61db989ab55792052c99713ef5f5eefaErik Klineimport static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
332efb827f61db989ab55792052c99713ef5f5eefaErik Klineimport static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
342efb827f61db989ab55792052c99713ef5f5eefaErik Klineimport static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
352efb827f61db989ab55792052c99713ef5f5eefaErik Klineimport static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
365d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
37ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport static org.junit.Assert.assertEquals;
38497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport static org.junit.Assert.assertTrue;
395d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport static org.mockito.ArgumentMatchers.argThat;
405d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport static org.mockito.ArgumentMatchers.notNull;
41497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport static org.mockito.Matchers.anyBoolean;
42ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport static org.mockito.Matchers.anyInt;
43ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport static org.mockito.Matchers.anyString;
44497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport static org.mockito.Matchers.eq;
451fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Klineimport static org.mockito.Mockito.any;
46ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport static org.mockito.Mockito.atLeastOnce;
471fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Klineimport static org.mockito.Mockito.doThrow;
485d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport static org.mockito.Mockito.never;
49ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport static org.mockito.Mockito.times;
50ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport static org.mockito.Mockito.verify;
51ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport static org.mockito.Mockito.verifyNoMoreInteractions;
52497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport static org.mockito.Mockito.when;
53fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaruimport static org.mockito.Mockito.mock;
54497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
558351faa900acdba1022f03bb3f18e26f539eadaeErik Klineimport android.content.BroadcastReceiver;
5692c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Klineimport android.content.ContentResolver;
57497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport android.content.Context;
58ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport android.content.Intent;
598351faa900acdba1022f03bb3f18e26f539eadaeErik Klineimport android.content.IntentFilter;
60f3a08b44ed5f3695720e92f7f51218f95018c12aErik Klineimport android.content.pm.ApplicationInfo;
61497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport android.content.res.Resources;
62ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport android.hardware.usb.UsbManager;
635d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.INetd;
64497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport android.net.INetworkPolicyManager;
65497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport android.net.INetworkStatsService;
66ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport android.net.InterfaceConfiguration;
675d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.IpPrefix;
685d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.LinkAddress;
695d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.LinkProperties;
705d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.MacAddress;
715d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.Network;
725d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.NetworkCapabilities;
735d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.NetworkInfo;
745d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.NetworkState;
755d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.NetworkUtils;
765d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.RouteInfo;
775d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.ip.RouterAdvertisementDaemon;
785d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.util.InterfaceParams;
795d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport android.net.util.NetworkConstants;
80f4b6e34fc093d0e493bc97e91b71d753720f7114Erik Klineimport android.net.util.SharedLog;
81ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport android.net.wifi.WifiConfiguration;
82ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport android.net.wifi.WifiManager;
83fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaruimport android.os.Bundle;
84ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport android.os.Handler;
85497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport android.os.INetworkManagementService;
86497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport android.os.PersistableBundle;
871fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Klineimport android.os.RemoteException;
88497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport android.os.test.TestLooper;
89ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport android.os.UserHandle;
90fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaruimport android.os.UserManager;
9192c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Klineimport android.provider.Settings;
92497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport android.support.test.filters.SmallTest;
93497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport android.support.test.runner.AndroidJUnit4;
94497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport android.telephony.CarrierConfigManager;
9592c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Klineimport android.test.mock.MockContentResolver;
96497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
975d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport com.android.internal.util.ArrayUtils;
985d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport com.android.internal.util.StateMachine;
99ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Klineimport com.android.internal.util.test.BroadcastInterceptingContext;
10092c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Klineimport com.android.internal.util.test.FakeSettingsProvider;
1015d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport com.android.server.connectivity.tethering.IControlsTethering;
1025d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
1035a7c8a0b24adc0f5d5ce3b98e995ef78096abf5bErik Klineimport com.android.server.connectivity.tethering.OffloadHardwareInterface;
1045d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
1055a7c8a0b24adc0f5d5ce3b98e995ef78096abf5bErik Klineimport com.android.server.connectivity.tethering.TetheringDependencies;
1065d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
107ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
1088351faa900acdba1022f03bb3f18e26f539eadaeErik Klineimport org.junit.After;
109497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport org.junit.Before;
110497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport org.junit.Test;
111497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport org.junit.runner.RunWith;
112497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport org.mockito.Mock;
113497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileyimport org.mockito.MockitoAnnotations;
114497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
1155d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport java.net.Inet4Address;
1165d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VANimport java.net.Inet6Address;
1178351faa900acdba1022f03bb3f18e26f539eadaeErik Klineimport java.util.ArrayList;
1188351faa900acdba1022f03bb3f18e26f539eadaeErik Klineimport java.util.Vector;
1198351faa900acdba1022f03bb3f18e26f539eadaeErik Kline
120497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley@RunWith(AndroidJUnit4.class)
121497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley@SmallTest
122497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wileypublic class TetheringTest {
1235d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private static final int IFINDEX_OFFSET = 100;
1245d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
125497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
1265d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
1275d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0";
1285d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private static final String TEST_USB_IFNAME = "test_rndis0";
1295d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private static final String TEST_WLAN_IFNAME = "test_wlan0";
130497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
131f3a08b44ed5f3695720e92f7f51218f95018c12aErik Kline    @Mock private ApplicationInfo mApplicationInfo;
132497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Mock private Context mContext;
133497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Mock private INetworkManagementService mNMService;
134497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Mock private INetworkStatsService mStatsService;
135497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Mock private INetworkPolicyManager mPolicyManager;
136497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Mock private MockableSystemProperties mSystemProperties;
1375a7c8a0b24adc0f5d5ce3b98e995ef78096abf5bErik Kline    @Mock private OffloadHardwareInterface mOffloadHardwareInterface;
138497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Mock private Resources mResources;
139ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    @Mock private UsbManager mUsbManager;
140ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    @Mock private WifiManager mWifiManager;
141497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Mock private CarrierConfigManager mCarrierConfigManager;
1425d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
1435d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
1445d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
1455d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    @Mock private INetd mNetd;
1465d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
1475d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private final MockTetheringDependencies mTetheringDependencies =
1485d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            new MockTetheringDependencies();
149497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
150497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    // Like so many Android system APIs, these cannot be mocked because it is marked final.
151497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    // We have to use the real versions.
152497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    private final PersistableBundle mCarrierConfig = new PersistableBundle();
153497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    private final TestLooper mLooper = new TestLooper();
154497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
1558351faa900acdba1022f03bb3f18e26f539eadaeErik Kline    private Vector<Intent> mIntents;
156ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    private BroadcastInterceptingContext mServiceContext;
15792c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Kline    private MockContentResolver mContentResolver;
1588351faa900acdba1022f03bb3f18e26f539eadaeErik Kline    private BroadcastReceiver mBroadcastReceiver;
159497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    private Tethering mTethering;
160497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
161ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    private class MockContext extends BroadcastInterceptingContext {
162ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        MockContext(Context base) {
163ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline            super(base);
164ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        }
165ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
166ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        @Override
167f3a08b44ed5f3695720e92f7f51218f95018c12aErik Kline        public ApplicationInfo getApplicationInfo() { return mApplicationInfo; }
168f3a08b44ed5f3695720e92f7f51218f95018c12aErik Kline
169f3a08b44ed5f3695720e92f7f51218f95018c12aErik Kline        @Override
17092c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Kline        public ContentResolver getContentResolver() { return mContentResolver; }
17192c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Kline
17292c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Kline        @Override
17392c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Kline        public String getPackageName() { return "TetheringTest"; }
17492c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Kline
17592c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Kline        @Override
176ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        public Resources getResources() { return mResources; }
177ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
178ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        @Override
179ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        public Object getSystemService(String name) {
180ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline            if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
181c438e306cc69b9d4d62512030267e93011b29978Erik Kline            if (Context.USB_SERVICE.equals(name)) return mUsbManager;
182ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline            return super.getSystemService(name);
183ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        }
184ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    }
185ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
1865d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    public class MockTetheringDependencies extends TetheringDependencies {
1877a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        StateMachine upstreamNetworkMonitorMasterSM;
1887a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
1897a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        int isTetheringSupportedCalls;
1907a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline
1917a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        public void reset() {
1927a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline            upstreamNetworkMonitorMasterSM = null;
1937a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline            ipv6CoordinatorNotifyList = null;
1947a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline            isTetheringSupportedCalls = 0;
1957a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        }
1965d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
1975d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        @Override
1985d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
1995d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            return mOffloadHardwareInterface;
2005d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        }
2015d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2025d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        @Override
2035d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
2045d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                StateMachine target, SharedLog log, int what) {
2055d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            upstreamNetworkMonitorMasterSM = target;
2065d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            return mUpstreamNetworkMonitor;
2075d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        }
2085d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2095d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        @Override
2105d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
2115d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
2125d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            ipv6CoordinatorNotifyList = notifyList;
2135d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            return mIPv6TetheringCoordinator;
2145d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        }
2155d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2165d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        @Override
2175d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
2185d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            return mRouterAdvertisementDaemon;
2195d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        }
2205d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2215d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        @Override
2225d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        public INetd getNetdService() {
2235d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            return mNetd;
2245d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        }
2255d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2265d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        @Override
2275d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        public InterfaceParams getInterfaceParams(String ifName) {
2285d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            final String[] ifaces = new String[] { TEST_USB_IFNAME, TEST_WLAN_IFNAME,
2295d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                    TEST_MOBILE_IFNAME };
2305d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            final int index = ArrayUtils.indexOf(ifaces, ifName);
2315d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            assertTrue("Non-mocked interface: " + ifName, index >= 0);
2325d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
2335d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                    MacAddress.ALL_ZEROS_ADDRESS);
2345d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        }
2357a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline
2367a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        @Override
2377a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        public boolean isTetheringSupported() {
2387a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline            isTetheringSupportedCalls++;
2397a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline            return true;
2407a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        }
2415d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    }
2425d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2436c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
2446c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN            boolean with464xlat) {
2457a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, 0, null, null);
2465d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        info.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
2475d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        final LinkProperties prop = new LinkProperties();
2485d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        prop.setInterfaceName(TEST_MOBILE_IFNAME);
2495d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2505d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        if (withIPv4) {
2515d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            prop.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
2525d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                    NetworkUtils.numericToInetAddress("10.0.0.1"), TEST_MOBILE_IFNAME));
2535d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        }
2545d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2555d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        if (withIPv6) {
2565d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            prop.addDnsServer(NetworkUtils.numericToInetAddress("2001:db8::2"));
2575d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            prop.addLinkAddress(
2585d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                    new LinkAddress(NetworkUtils.numericToInetAddress("2001:db8::"),
2595d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                            NetworkConstants.RFC7421_PREFIX_LENGTH));
2605d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            prop.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0),
2615d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                    NetworkUtils.numericToInetAddress("2001:db8::1"), TEST_MOBILE_IFNAME));
2625d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        }
2635d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2646c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        if (with464xlat) {
2656c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN            final LinkProperties stackedLink = new LinkProperties();
2666c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN            stackedLink.setInterfaceName(TEST_XLAT_MOBILE_IFNAME);
2676c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN            stackedLink.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
2686c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN                    NetworkUtils.numericToInetAddress("192.0.0.1"), TEST_XLAT_MOBILE_IFNAME));
2696c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
2706c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN            prop.addStackedLink(stackedLink);
2716c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        }
2726c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
2735d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2745d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        final NetworkCapabilities capabilities = new NetworkCapabilities()
2755d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);;
2765d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        return new NetworkState(info, prop, capabilities, new Network(100), null, "netid");
2775d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    }
2785d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2795d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private static NetworkState buildMobileIPv4UpstreamState() {
2806c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        return buildMobileUpstreamState(true, false, false);
2816c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    }
2826c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
2836c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    private static NetworkState buildMobileIPv6UpstreamState() {
2846c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        return buildMobileUpstreamState(false, true, false);
2855d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    }
2865d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2875d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private static NetworkState buildMobileDualStackUpstreamState() {
2886c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        return buildMobileUpstreamState(true, true, false);
2896c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    }
2906c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
2916c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    private static NetworkState buildMobile464xlatUpstreamState() {
2926c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        return buildMobileUpstreamState(false, true, true);
2935d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    }
2945d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
2958351faa900acdba1022f03bb3f18e26f539eadaeErik Kline    @Before
2968351faa900acdba1022f03bb3f18e26f539eadaeErik Kline    public void setUp() throws Exception {
297497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        MockitoAnnotations.initMocks(this);
298497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
299497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                .thenReturn(new String[0]);
300497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
3015d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                .thenReturn(new String[] { "test_rndis\\d" });
302497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
3035d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                .thenReturn(new String[]{ "test_wlan\\d" });
304497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
305497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                .thenReturn(new String[0]);
306497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
307497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                .thenReturn(new int[0]);
308ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        when(mNMService.listInterfaces())
3095d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                .thenReturn(new String[] {
3105d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                        TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME});
311ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        when(mNMService.getInterfaceConfig(anyString()))
312ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline                .thenReturn(new InterfaceConfiguration());
3135d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        when(mRouterAdvertisementDaemon.start())
3145d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                .thenReturn(true);
315ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
316ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        mServiceContext = new MockContext(mContext);
31792c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Kline        mContentResolver = new MockContentResolver(mServiceContext);
31892c4db04e54a7bb375df01ce6e3fd98d568c6990Erik Kline        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
3198351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        mIntents = new Vector<>();
3208351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        mBroadcastReceiver = new BroadcastReceiver() {
3218351faa900acdba1022f03bb3f18e26f539eadaeErik Kline            @Override
3228351faa900acdba1022f03bb3f18e26f539eadaeErik Kline            public void onReceive(Context context, Intent intent) {
3238351faa900acdba1022f03bb3f18e26f539eadaeErik Kline                mIntents.addElement(intent);
3248351faa900acdba1022f03bb3f18e26f539eadaeErik Kline            }
3258351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        };
3268351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        mServiceContext.registerReceiver(mBroadcastReceiver,
3277a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline                new IntentFilter(ACTION_TETHER_STATE_CHANGED));
3287a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        mTetheringDependencies.reset();
329ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
3305a7c8a0b24adc0f5d5ce3b98e995ef78096abf5bErik Kline                                   mLooper.getLooper(), mSystemProperties,
3315a7c8a0b24adc0f5d5ce3b98e995ef78096abf5bErik Kline                                   mTetheringDependencies);
3325a7dea1a8eb2cf53fc1d5a52004647de94150e62Lorenzo Colitti        verify(mNMService).registerTetheringStatsProvider(any(), anyString());
333497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    }
334497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
3358351faa900acdba1022f03bb3f18e26f539eadaeErik Kline    @After
3368351faa900acdba1022f03bb3f18e26f539eadaeErik Kline    public void tearDown() {
3378351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        mServiceContext.unregisterReceiver(mBroadcastReceiver);
3388351faa900acdba1022f03bb3f18e26f539eadaeErik Kline    }
3398351faa900acdba1022f03bb3f18e26f539eadaeErik Kline
340497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    private void setupForRequiredProvisioning() {
341497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        // Produce some acceptable looking provision app setting if requested.
342497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mResources.getStringArray(
343497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                com.android.internal.R.array.config_mobile_hotspot_provision_app))
344497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                .thenReturn(PROVISIONING_APP_NAME);
345497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        // Don't disable tethering provisioning unless requested.
346497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mSystemProperties.getBoolean(eq(Tethering.DISABLE_PROVISIONING_SYSPROP_KEY),
347497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                                          anyBoolean())).thenReturn(false);
348497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        // Act like the CarrierConfigManager is present and ready unless told otherwise.
349497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
350497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                .thenReturn(mCarrierConfigManager);
351497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
352497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
353497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    }
354497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
355497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Test
356497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    public void canRequireProvisioning() {
357497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        setupForRequiredProvisioning();
35880b7a9f1b5ba5a6117f6b020121f06a2d0cd1889Erik Kline        sendConfigurationChanged();
359497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        assertTrue(mTethering.isTetherProvisioningRequired());
360497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    }
361497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
362497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Test
363497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    public void toleratesCarrierConfigManagerMissing() {
364497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        setupForRequiredProvisioning();
365497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
366497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                .thenReturn(null);
36780b7a9f1b5ba5a6117f6b020121f06a2d0cd1889Erik Kline        sendConfigurationChanged();
368497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
369497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        // We therefore still require provisioning.
370497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        assertTrue(mTethering.isTetherProvisioningRequired());
371497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    }
372497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
373497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Test
374497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    public void toleratesCarrierConfigMissing() {
375497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        setupForRequiredProvisioning();
376497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mCarrierConfigManager.getConfig()).thenReturn(null);
37780b7a9f1b5ba5a6117f6b020121f06a2d0cd1889Erik Kline        sendConfigurationChanged();
378497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        // We still have a provisioning app configured, so still require provisioning.
379497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        assertTrue(mTethering.isTetherProvisioningRequired());
380497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    }
381497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley
382497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    @Test
383497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    public void provisioningNotRequiredWhenAppNotFound() {
384497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        setupForRequiredProvisioning();
385497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mResources.getStringArray(
386497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                com.android.internal.R.array.config_mobile_hotspot_provision_app))
387497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                .thenReturn(null);
388497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        assertTrue(!mTethering.isTetherProvisioningRequired());
389497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        when(mResources.getStringArray(
390497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                com.android.internal.R.array.config_mobile_hotspot_provision_app))
391497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley                .thenReturn(new String[] {"malformedApp"});
392497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley        assertTrue(!mTethering.isTetherProvisioningRequired());
393497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley    }
394ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
395ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    private void sendWifiApStateChanged(int state) {
396ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
3972efb827f61db989ab55792052c99713ef5f5eefaErik Kline        intent.putExtra(EXTRA_WIFI_AP_STATE, state);
398ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
399ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    }
400ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
4012efb827f61db989ab55792052c99713ef5f5eefaErik Kline    private void sendWifiApStateChanged(int state, String ifname, int ipmode) {
4022efb827f61db989ab55792052c99713ef5f5eefaErik Kline        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
4032efb827f61db989ab55792052c99713ef5f5eefaErik Kline        intent.putExtra(EXTRA_WIFI_AP_STATE, state);
4042efb827f61db989ab55792052c99713ef5f5eefaErik Kline        intent.putExtra(EXTRA_WIFI_AP_INTERFACE_NAME, ifname);
4052efb827f61db989ab55792052c99713ef5f5eefaErik Kline        intent.putExtra(EXTRA_WIFI_AP_MODE, ipmode);
4062efb827f61db989ab55792052c99713ef5f5eefaErik Kline        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4072efb827f61db989ab55792052c99713ef5f5eefaErik Kline    }
4082efb827f61db989ab55792052c99713ef5f5eefaErik Kline
409c438e306cc69b9d4d62512030267e93011b29978Erik Kline    private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
410c438e306cc69b9d4d62512030267e93011b29978Erik Kline        final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
411c438e306cc69b9d4d62512030267e93011b29978Erik Kline        intent.putExtra(USB_CONNECTED, connected);
412c438e306cc69b9d4d62512030267e93011b29978Erik Kline        intent.putExtra(USB_CONFIGURED, configured);
413c438e306cc69b9d4d62512030267e93011b29978Erik Kline        intent.putExtra(USB_FUNCTION_RNDIS, rndisFunction);
414c438e306cc69b9d4d62512030267e93011b29978Erik Kline        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
415c438e306cc69b9d4d62512030267e93011b29978Erik Kline    }
416c438e306cc69b9d4d62512030267e93011b29978Erik Kline
41780b7a9f1b5ba5a6117f6b020121f06a2d0cd1889Erik Kline    private void sendConfigurationChanged() {
41880b7a9f1b5ba5a6117f6b020121f06a2d0cd1889Erik Kline        final Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
41980b7a9f1b5ba5a6117f6b020121f06a2d0cd1889Erik Kline        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
42080b7a9f1b5ba5a6117f6b020121f06a2d0cd1889Erik Kline    }
42180b7a9f1b5ba5a6117f6b020121f06a2d0cd1889Erik Kline
4229e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline    private void verifyInterfaceServingModeStarted() throws Exception {
4235d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(1)).getInterfaceConfig(TEST_WLAN_IFNAME);
4248351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        verify(mNMService, times(1))
4255d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
4265d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
4278351faa900acdba1022f03bb3f18e26f539eadaeErik Kline    }
4288351faa900acdba1022f03bb3f18e26f539eadaeErik Kline
4298351faa900acdba1022f03bb3f18e26f539eadaeErik Kline    private void verifyTetheringBroadcast(String ifname, String whichExtra) {
4308351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
4318351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        final Intent bcast = mIntents.get(0);
4327a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        assertEquals(ACTION_TETHER_STATE_CHANGED, bcast.getAction());
4338351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
4348351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        assertTrue(ifnames.contains(ifname));
4358351faa900acdba1022f03bb3f18e26f539eadaeErik Kline        mIntents.remove(bcast);
4368351faa900acdba1022f03bb3f18e26f539eadaeErik Kline    }
4378351faa900acdba1022f03bb3f18e26f539eadaeErik Kline
438a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    public void failingLocalOnlyHotspotLegacyApBroadcast(
439a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline            boolean emulateInterfaceStatusChanged) throws Exception {
440ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // Emulate externally-visible WifiManager effects, causing the
441ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // per-interface state machine to start up, and telling us that
442ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // hotspot mode is to be started.
443a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        if (emulateInterfaceStatusChanged) {
4445d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
445a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        }
4469e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
447ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        mLooper.dispatchAll();
448ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
449a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        // If, and only if, Tethering received an interface status changed
450a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        // then it creates a TetherInterfaceStateMachine and sends out a
451a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        // broadcast indicating that the interface is "available".
452a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        if (emulateInterfaceStatusChanged) {
4537a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline            assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
4547a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline            verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
455a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        }
4569e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        verifyNoMoreInteractions(mNMService);
4579e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        verifyNoMoreInteractions(mWifiManager);
4589e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline    }
4599e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline
4605d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private void prepareUsbTethering(NetworkState upstreamState) {
4615d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
4625d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                .thenReturn(upstreamState);
463c438e306cc69b9d4d62512030267e93011b29978Erik Kline
464c438e306cc69b9d4d62512030267e93011b29978Erik Kline        // Emulate pressing the USB tethering button in Settings UI.
465c438e306cc69b9d4d62512030267e93011b29978Erik Kline        mTethering.startTethering(TETHERING_USB, null, false);
466c438e306cc69b9d4d62512030267e93011b29978Erik Kline        mLooper.dispatchAll();
467327b809ad11a5094248652014227470c4be329e6Jerry Zhang        verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
468c438e306cc69b9d4d62512030267e93011b29978Erik Kline
4695d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
4705d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    }
4715d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
4725d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    @Test
4735d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
4745d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        NetworkState upstreamState = buildMobileIPv4UpstreamState();
4755d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        prepareUsbTethering(upstreamState);
4765d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
477c438e306cc69b9d4d62512030267e93011b29978Erik Kline        // This should produce no activity of any kind.
478c438e306cc69b9d4d62512030267e93011b29978Erik Kline        verifyNoMoreInteractions(mNMService);
479c438e306cc69b9d4d62512030267e93011b29978Erik Kline
480c438e306cc69b9d4d62512030267e93011b29978Erik Kline        // Pretend we then receive USB configured broadcast.
481c438e306cc69b9d4d62512030267e93011b29978Erik Kline        sendUsbBroadcast(true, true, true);
482c438e306cc69b9d4d62512030267e93011b29978Erik Kline        mLooper.dispatchAll();
483c438e306cc69b9d4d62512030267e93011b29978Erik Kline        // Now we should see the start of tethering mechanics (in this case:
484c438e306cc69b9d4d62512030267e93011b29978Erik Kline        // tetherMatchingInterfaces() which starts by fetching all interfaces).
485c438e306cc69b9d4d62512030267e93011b29978Erik Kline        verify(mNMService, times(1)).listInterfaces();
4865d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
4875d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        // UpstreamNetworkMonitor should receive selected upstream
4885d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
4895d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
490c438e306cc69b9d4d62512030267e93011b29978Erik Kline    }
491c438e306cc69b9d4d62512030267e93011b29978Erik Kline
492c438e306cc69b9d4d62512030267e93011b29978Erik Kline    @Test
493a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    public void failingLocalOnlyHotspotLegacyApBroadcastWithIfaceStatusChanged() throws Exception {
494a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        failingLocalOnlyHotspotLegacyApBroadcast(true);
495a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    }
496a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline
497a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    @Test
498a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    public void failingLocalOnlyHotspotLegacyApBroadcastSansIfaceStatusChanged() throws Exception {
499a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        failingLocalOnlyHotspotLegacyApBroadcast(false);
500a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    }
501a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline
502a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    public void workingLocalOnlyHotspotEnrichedApBroadcast(
503a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline            boolean emulateInterfaceStatusChanged) throws Exception {
5049e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        // Emulate externally-visible WifiManager effects, causing the
5059e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        // per-interface state machine to start up, and telling us that
5069e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        // hotspot mode is to be started.
507a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        if (emulateInterfaceStatusChanged) {
5085d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
509a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        }
5105d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_LOCAL_ONLY);
5119e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        mLooper.dispatchAll();
5129e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline
5139e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        verifyInterfaceServingModeStarted();
5147a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
515ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verify(mNMService, times(1)).setIpForwardingEnabled(true);
516ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verify(mNMService, times(1)).startTethering(any(String[].class));
517ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verifyNoMoreInteractions(mNMService);
518216af6d3febb109628d9185ec1a619f0e003bcd1Erik Kline        verify(mWifiManager).updateInterfaceIpState(
5195d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
520216af6d3febb109628d9185ec1a619f0e003bcd1Erik Kline        verifyNoMoreInteractions(mWifiManager);
5217a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
5225d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mUpstreamNetworkMonitor, times(1)).start();
523ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
5247a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
525ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
526ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // Emulate externally-visible WifiManager effects, when hotspot mode
527ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // is being torn down.
528ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
5295d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
530ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        mLooper.dispatchAll();
531ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
5325d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
533ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // TODO: Why is {g,s}etInterfaceConfig() called more than once?
5345d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
535ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verify(mNMService, atLeastOnce())
5365d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
537ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verify(mNMService, times(1)).stopTethering();
538ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verify(mNMService, times(1)).setIpForwardingEnabled(false);
539ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verifyNoMoreInteractions(mNMService);
540216af6d3febb109628d9185ec1a619f0e003bcd1Erik Kline        verifyNoMoreInteractions(mWifiManager);
541ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // Asking for the last error after the per-interface state machine
542ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // has been reaped yields an unknown interface error.
5437a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
5445d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    }
5455d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
5465d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    /**
5475d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN     * Send CMD_IPV6_TETHER_UPDATE to TISMs as would be done by IPv6TetheringCoordinator.
5485d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN     */
5495d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private void sendIPv6TetherUpdates(NetworkState upstreamState) {
5505d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        // IPv6TetheringCoordinator must have been notified of downstream
5515d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
5525d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
5535d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                eq(IControlsTethering.STATE_TETHERED));
5545d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
5555d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        for (TetherInterfaceStateMachine tism :
5565d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                mTetheringDependencies.ipv6CoordinatorNotifyList) {
5576c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN            NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
5585d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN            tism.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0,
5595d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                    upstreamState.linkProperties.isIPv6Provisioned()
5605d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                            ? ipv6OnlyState.linkProperties
5615d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                            : null);
5625d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        }
5635d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        mLooper.dispatchAll();
5645d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    }
5655d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
5665d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    private void runUsbTethering(NetworkState upstreamState) {
5675d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        prepareUsbTethering(upstreamState);
5685d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        sendUsbBroadcast(true, true, true);
5695d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        mLooper.dispatchAll();
5705d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    }
5715d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
5725d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    @Test
5735d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    public void workingMobileUsbTethering_IPv4() throws Exception {
5745d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        NetworkState upstreamState = buildMobileIPv4UpstreamState();
5755d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        runUsbTethering(upstreamState);
5765d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
5775d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
5785d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
5795d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
5805d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        sendIPv6TetherUpdates(upstreamState);
5815d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
5825d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    }
5835d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
5845d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    @Test
5856c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    public void workingMobileUsbTethering_IPv6() throws Exception {
5866c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        NetworkState upstreamState = buildMobileIPv6UpstreamState();
5876c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        runUsbTethering(upstreamState);
5886c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
5896c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
5906c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
5916c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
5926c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        sendIPv6TetherUpdates(upstreamState);
5936c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
5946c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
5956c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    }
5966c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
5976c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    @Test
5985d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN    public void workingMobileUsbTethering_DualStack() throws Exception {
5995d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        NetworkState upstreamState = buildMobileDualStackUpstreamState();
6005d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        runUsbTethering(upstreamState);
6015d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
6025d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
6035d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
6045d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mRouterAdvertisementDaemon, times(1)).start();
6055d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
6065d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        sendIPv6TetherUpdates(upstreamState);
6075d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
6085d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
609ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    }
610ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
6116c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    @Test
6126c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    public void workingMobileUsbTethering_MultipleUpstreams() throws Exception {
6136c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        NetworkState upstreamState = buildMobile464xlatUpstreamState();
6146c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        runUsbTethering(upstreamState);
6156c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
6166c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
6176c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
6186c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
6196c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
6206c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN                TEST_XLAT_MOBILE_IFNAME);
6216c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
6226c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        sendIPv6TetherUpdates(upstreamState);
6236c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
6246c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
6256c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    }
6266c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
6276c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    @Test
6286c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    public void workingMobileUsbTethering_v6Then464xlat() throws Exception {
6296c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        // Setup IPv6
6306c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        NetworkState upstreamState = buildMobileIPv6UpstreamState();
6316c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        runUsbTethering(upstreamState);
6326c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
6336c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        // Then 464xlat comes up
6346c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        upstreamState = buildMobile464xlatUpstreamState();
6356c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
6366c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN                .thenReturn(upstreamState);
6376c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
6386c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
6396c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        mTetheringDependencies.upstreamNetworkMonitorMasterSM.sendMessage(
6406c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN                Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
6416c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN                UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
6426c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN                0,
6436c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN                upstreamState);
6446c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        mLooper.dispatchAll();
6456c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN
6466c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        // Forwarding is added for 464xlat, and was still added only once for v6
6476c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
6486c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
6496c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
6506c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
6516c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN                TEST_XLAT_MOBILE_IFNAME);
6526c02f9942aaf4f6665018e0c7f07aeceb5ae752eRemi NGUYEN VAN    }
6535d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN
654ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    @Test
655a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
656a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        workingLocalOnlyHotspotEnrichedApBroadcast(true);
657a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    }
658a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline
659a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    @Test
660a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    public void workingLocalOnlyHotspotEnrichedApBroadcastSansIfaceChanged() throws Exception {
661a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline        workingLocalOnlyHotspotEnrichedApBroadcast(false);
662a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    }
663a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline
664a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    // TODO: Test with and without interfaceStatusChanged().
665a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    @Test
6669e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline    public void failingWifiTetheringLegacyApBroadcast() throws Exception {
6679e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
6682efb827f61db989ab55792052c99713ef5f5eefaErik Kline
6699e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        // Emulate pressing the WiFi tethering button.
670c438e306cc69b9d4d62512030267e93011b29978Erik Kline        mTethering.startTethering(TETHERING_WIFI, null, false);
6719e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        mLooper.dispatchAll();
6729e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        verify(mWifiManager, times(1)).startSoftAp(null);
6739e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        verifyNoMoreInteractions(mWifiManager);
6749e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        verifyNoMoreInteractions(mNMService);
6759e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline
6769e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        // Emulate externally-visible WifiManager effects, causing the
6779e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        // per-interface state machine to start up, and telling us that
6789e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        // tethering mode is to be started.
6795d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
6809e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
6819e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        mLooper.dispatchAll();
6829e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline
6837a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
6847a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
6859e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        verifyNoMoreInteractions(mNMService);
6869e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        verifyNoMoreInteractions(mWifiManager);
6872efb827f61db989ab55792052c99713ef5f5eefaErik Kline    }
6882efb827f61db989ab55792052c99713ef5f5eefaErik Kline
689a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    // TODO: Test with and without interfaceStatusChanged().
6909e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline    @Test
6919e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline    public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
692ceb54c63dc7af8f11ec9eac4993a43b9e788ee2fErik Kline        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
693ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
694ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // Emulate pressing the WiFi tethering button.
695c438e306cc69b9d4d62512030267e93011b29978Erik Kline        mTethering.startTethering(TETHERING_WIFI, null, false);
696ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        mLooper.dispatchAll();
697ceb54c63dc7af8f11ec9eac4993a43b9e788ee2fErik Kline        verify(mWifiManager, times(1)).startSoftAp(null);
698ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verifyNoMoreInteractions(mWifiManager);
699ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verifyNoMoreInteractions(mNMService);
700ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
701ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // Emulate externally-visible WifiManager effects, causing the
702ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // per-interface state machine to start up, and telling us that
703ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // tethering mode is to be started.
7045d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
7055d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
706ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        mLooper.dispatchAll();
707ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
7089e225540687d5d4eb17bdfbe4f062c22ee22b560Erik Kline        verifyInterfaceServingModeStarted();
7097a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
710ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verify(mNMService, times(1)).setIpForwardingEnabled(true);
711ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verify(mNMService, times(1)).startTethering(any(String[].class));
712ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verifyNoMoreInteractions(mNMService);
713216af6d3febb109628d9185ec1a619f0e003bcd1Erik Kline        verify(mWifiManager).updateInterfaceIpState(
7145d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
715216af6d3febb109628d9185ec1a619f0e003bcd1Erik Kline        verifyNoMoreInteractions(mWifiManager);
7167a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
7175d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mUpstreamNetworkMonitor, times(1)).start();
718ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // In tethering mode, in the default configuration, an explicit request
719ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // for a mobile network is also made.
7205d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
721ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
7227a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
723ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
724ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        /////
725ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // We do not currently emulate any upstream being found.
726ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        //
727ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // This is why there are no calls to verify mNMService.enableNat() or
728ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // mNMService.startInterfaceForwarding().
729ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        /////
730ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
731ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // Emulate pressing the WiFi tethering button.
732c438e306cc69b9d4d62512030267e93011b29978Erik Kline        mTethering.stopTethering(TETHERING_WIFI);
733ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        mLooper.dispatchAll();
734ceb54c63dc7af8f11ec9eac4993a43b9e788ee2fErik Kline        verify(mWifiManager, times(1)).stopSoftAp();
735ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verifyNoMoreInteractions(mWifiManager);
736ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verifyNoMoreInteractions(mNMService);
737ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
738ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // Emulate externally-visible WifiManager effects, when tethering mode
739ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // is being torn down.
740ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
7415d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
742ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        mLooper.dispatchAll();
743ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
7445d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
745ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // TODO: Why is {g,s}etInterfaceConfig() called more than once?
7465d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
747ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verify(mNMService, atLeastOnce())
7485d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
749ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verify(mNMService, times(1)).stopTethering();
750ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verify(mNMService, times(1)).setIpForwardingEnabled(false);
751ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        verifyNoMoreInteractions(mNMService);
752216af6d3febb109628d9185ec1a619f0e003bcd1Erik Kline        verifyNoMoreInteractions(mWifiManager);
753ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // Asking for the last error after the per-interface state machine
754ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline        // has been reaped yields an unknown interface error.
7557a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
756ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    }
757ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline
758a9cde8b4fb26a963824f297e9b7489bfc35d1512Erik Kline    // TODO: Test with and without interfaceStatusChanged().
7591fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline    @Test
7601fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline    public void failureEnablingIpForwarding() throws Exception {
7611fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
7621fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
7631fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline
7641fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        // Emulate pressing the WiFi tethering button.
765c438e306cc69b9d4d62512030267e93011b29978Erik Kline        mTethering.startTethering(TETHERING_WIFI, null, false);
7661fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        mLooper.dispatchAll();
7671fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        verify(mWifiManager, times(1)).startSoftAp(null);
7681fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        verifyNoMoreInteractions(mWifiManager);
7691fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        verifyNoMoreInteractions(mNMService);
7701fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline
7711fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        // Emulate externally-visible WifiManager effects, causing the
7721fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        // per-interface state machine to start up, and telling us that
7731fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        // tethering mode is to be started.
7745d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
7755d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
7761fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        mLooper.dispatchAll();
7771fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline
778472276a874316b725027098b79e1c9f03c62cad2Erik Kline        // We verify get/set called thrice here: once for setup and twice during
7791fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        // teardown because all events happen over the course of the single
780472276a874316b725027098b79e1c9f03c62cad2Erik Kline        // dispatchAll() above. Note that once the TISM IPv4 address config
781472276a874316b725027098b79e1c9f03c62cad2Erik Kline        // code is refactored the two calls during shutdown will revert to one.
7825d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
783472276a874316b725027098b79e1c9f03c62cad2Erik Kline        verify(mNMService, times(3))
7845d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
7855d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
7861fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        verify(mWifiManager).updateInterfaceIpState(
7875d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
7887a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
7897a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
7907a26ba37f6a1205c8914c62c4756f24329317f6bErik Kline        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
7911fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        // This is called, but will throw.
7921fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        verify(mNMService, times(1)).setIpForwardingEnabled(true);
7931fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        // This never gets called because of the exception thrown above.
7941fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        verify(mNMService, times(0)).startTethering(any(String[].class));
7951fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        // When the master state machine transitions to an error state it tells
7961fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        // downstream interfaces, which causes us to tell Wi-Fi about the error
7971fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        // so it can take down AP mode.
7985d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
7991fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        verify(mWifiManager).updateInterfaceIpState(
8005d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
8011fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline
8021fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        verifyNoMoreInteractions(mWifiManager);
8031fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline        verifyNoMoreInteractions(mNMService);
8041fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline    }
8051fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline
806fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    private void userRestrictionsListenerBehaviour(
807fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList,
808fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        int expectedInteractionsWithShowNotification) throws  Exception {
809fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final int userId = 0;
810fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final Bundle currRestrictions = new Bundle();
811fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final Bundle newRestrictions = new Bundle();
812fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        Tethering tethering = mock(Tethering.class);
813fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        Tethering.TetheringUserRestrictionListener turl =
814fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru                new Tethering.TetheringUserRestrictionListener(tethering);
815fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
816fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        currRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, currentDisallow);
817fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow);
818fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        when(tethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList);
819fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
820fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        turl.onUserRestrictionsChanged(userId, newRestrictions, currRestrictions);
821fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
822fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        verify(tethering, times(expectedInteractionsWithShowNotification))
823fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru                .showTetheredNotification(anyInt(), eq(false));
824fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
825fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        verify(tethering, times(expectedInteractionsWithShowNotification)).untetherAll();
826fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    }
827fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
828fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    @Test
829fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    public void testDisallowTetheringWhenNoTetheringInterfaceIsActive() throws Exception {
830fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final String[] emptyActiveIfacesList = new String[]{};
831fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final boolean currDisallow = false;
832fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final boolean nextDisallow = true;
833fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final int expectedInteractionsWithShowNotification = 0;
834fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
835fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, emptyActiveIfacesList,
836fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru                expectedInteractionsWithShowNotification);
837fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    }
838fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
839fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    @Test
840fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    public void testDisallowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
8415d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
842fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final boolean currDisallow = false;
843fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final boolean nextDisallow = true;
844fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final int expectedInteractionsWithShowNotification = 1;
845fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
846fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
847fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru                expectedInteractionsWithShowNotification);
848fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    }
849fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
850fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    @Test
851fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    public void testAllowTetheringWhenNoTetheringInterfaceIsActive() throws Exception {
852fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final String[] nonEmptyActiveIfacesList = new String[]{};
853fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final boolean currDisallow = true;
854fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final boolean nextDisallow = false;
855fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final int expectedInteractionsWithShowNotification = 0;
856fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
857fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
858fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru                expectedInteractionsWithShowNotification);
859fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    }
860fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
861fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    @Test
862fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    public void testAllowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
8635d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
864fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final boolean currDisallow = true;
865fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final boolean nextDisallow = false;
866fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final int expectedInteractionsWithShowNotification = 0;
867fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
868fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
869fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru                expectedInteractionsWithShowNotification);
870fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    }
871fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
872fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    @Test
873fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    public void testDisallowTetheringUnchanged() throws Exception {
8745d0dc453e90554e739c5994a417e73a560edc547Remi NGUYEN VAN        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
875fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        final int expectedInteractionsWithShowNotification = 0;
876fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        boolean currDisallow = true;
877fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        boolean nextDisallow = true;
878fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
879fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
880fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru                expectedInteractionsWithShowNotification);
881fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
882fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        currDisallow = false;
883fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        nextDisallow = false;
884fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
885fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
886fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru                expectedInteractionsWithShowNotification);
887fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru    }
888fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
889fa6d5c5ca02f1bfc454bd3cd82e6c043661e7aa7Alexandru-Andrei Rotaru
8901fdc2e23b5d8136e06cafd7de896b49e5f929c7fErik Kline    // TODO: Test that a request for hotspot mode doesn't interfere with an
891ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline    // already operating tethering mode interface.
892497c147b821cf1c441f5047a5035281dc23e8bd9Christopher Wiley}
893