Merge "Support set test network to tethering upstream" am: 473d864d20
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1797991 Change-Id: Ifd5c76a943886dfe55e9b68eeb77931dae6fe204
This commit is contained in:
@@ -22,7 +22,19 @@ java_sdk_library {
|
|||||||
defaults: ["framework-module-defaults"],
|
defaults: ["framework-module-defaults"],
|
||||||
impl_library_visibility: [
|
impl_library_visibility: [
|
||||||
"//packages/modules/Connectivity/Tethering:__subpackages__",
|
"//packages/modules/Connectivity/Tethering:__subpackages__",
|
||||||
|
|
||||||
|
// Using for test only
|
||||||
|
"//cts/tests/netlegacy22.api",
|
||||||
|
"//external/sl4a:__subpackages__",
|
||||||
|
"//frameworks/base/packages/Connectivity/tests:__subpackages__",
|
||||||
|
"//frameworks/libs/net/common/testutils",
|
||||||
|
"//frameworks/libs/net/common/tests:__subpackages__",
|
||||||
|
"//frameworks/opt/telephony/tests/telephonytests",
|
||||||
|
"//packages/modules/CaptivePortalLogin/tests",
|
||||||
|
"//packages/modules/Connectivity/Tethering/tests:__subpackages__",
|
||||||
"//packages/modules/Connectivity/tests:__subpackages__",
|
"//packages/modules/Connectivity/tests:__subpackages__",
|
||||||
|
"//packages/modules/NetworkStack/tests:__subpackages__",
|
||||||
|
"//packages/modules/Wifi/service/tests/wifitests",
|
||||||
],
|
],
|
||||||
|
|
||||||
srcs: [":framework-tethering-srcs"],
|
srcs: [":framework-tethering-srcs"],
|
||||||
|
|||||||
@@ -49,4 +49,6 @@ oneway interface ITetheringConnector {
|
|||||||
|
|
||||||
void stopAllTethering(String callerPkg, String callingAttributionTag,
|
void stopAllTethering(String callerPkg, String callingAttributionTag,
|
||||||
IIntResultListener receiver);
|
IIntResultListener receiver);
|
||||||
|
|
||||||
|
void setPreferTestNetworks(boolean prefer, IIntResultListener listener);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1538,4 +1538,25 @@ public class TetheringManager {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to treat networks that have TRANSPORT_TEST as Tethering upstreams. The effects of
|
||||||
|
* this method apply to any test networks that are already present on the system.
|
||||||
|
*
|
||||||
|
* @throws SecurityException If the caller doesn't have the NETWORK_SETTINGS permission.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
|
||||||
|
public void setPreferTestNetworks(final boolean prefer) {
|
||||||
|
Log.i(TAG, "setPreferTestNetworks caller: " + mContext.getOpPackageName());
|
||||||
|
|
||||||
|
final RequestDispatcher dispatcher = new RequestDispatcher();
|
||||||
|
final int ret = dispatcher.waitForResult((connector, listener) -> {
|
||||||
|
try {
|
||||||
|
connector.setPreferTestNetworks(prefer, listener);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2601,4 +2601,13 @@ public class Tethering {
|
|||||||
private static String[] copy(String[] strarray) {
|
private static String[] copy(String[] strarray) {
|
||||||
return Arrays.copyOf(strarray, strarray.length);
|
return Arrays.copyOf(strarray, strarray.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPreferTestNetworks(final boolean prefer, IIntResultListener listener) {
|
||||||
|
mHandler.post(() -> {
|
||||||
|
mUpstreamNetworkMonitor.setPreferTestNetworks(prefer);
|
||||||
|
try {
|
||||||
|
listener.onResult(TETHER_ERROR_NO_ERROR);
|
||||||
|
} catch (RemoteException e) { }
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
package com.android.networkstack.tethering;
|
package com.android.networkstack.tethering;
|
||||||
|
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
@@ -78,13 +82,17 @@ public final class TetheringInterfaceUtils {
|
|||||||
// Minimal amount of IPv6 provisioning:
|
// Minimal amount of IPv6 provisioning:
|
||||||
&& ns.linkProperties.hasGlobalIpv6Address()
|
&& ns.linkProperties.hasGlobalIpv6Address()
|
||||||
// Temporary approximation of "dedicated prefix":
|
// Temporary approximation of "dedicated prefix":
|
||||||
&& ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
|
&& allowIpv6Tethering(ns.networkCapabilities);
|
||||||
|
|
||||||
return canTether
|
return canTether
|
||||||
? getInterfaceForDestination(ns.linkProperties, IN6ADDR_ANY)
|
? getInterfaceForDestination(ns.linkProperties, IN6ADDR_ANY)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean allowIpv6Tethering(@NonNull final NetworkCapabilities nc) {
|
||||||
|
return nc.hasTransport(TRANSPORT_CELLULAR) || nc.hasTransport(TRANSPORT_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
|
private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
|
||||||
final RouteInfo ri = (lp != null)
|
final RouteInfo ri = (lp != null)
|
||||||
? NetUtils.selectBestRoute(lp.getAllRoutes(), dst)
|
? NetUtils.selectBestRoute(lp.getAllRoutes(), dst)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.networkstack.tethering;
|
package com.android.networkstack.tethering;
|
||||||
|
|
||||||
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
|
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
|
||||||
|
import static android.Manifest.permission.NETWORK_SETTINGS;
|
||||||
import static android.Manifest.permission.NETWORK_STACK;
|
import static android.Manifest.permission.NETWORK_STACK;
|
||||||
import static android.Manifest.permission.TETHER_PRIVILEGED;
|
import static android.Manifest.permission.TETHER_PRIVILEGED;
|
||||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
@@ -203,6 +204,17 @@ public class TetheringService extends Service {
|
|||||||
} catch (RemoteException e) { }
|
} catch (RemoteException e) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPreferTestNetworks(boolean prefer, IIntResultListener listener) {
|
||||||
|
if (!checkCallingOrSelfPermission(NETWORK_SETTINGS)) {
|
||||||
|
try {
|
||||||
|
listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
|
||||||
|
} catch (RemoteException e) { }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTethering.setPreferTestNetworks(prefer, listener);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
|
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
|
||||||
@Nullable String[] args) {
|
@Nullable String[] args) {
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ public class UpstreamNetworkMonitor {
|
|||||||
private Network mDefaultInternetNetwork;
|
private Network mDefaultInternetNetwork;
|
||||||
// The current upstream network used for tethering.
|
// The current upstream network used for tethering.
|
||||||
private Network mTetheringUpstreamNetwork;
|
private Network mTetheringUpstreamNetwork;
|
||||||
|
private boolean mPreferTestNetworks;
|
||||||
|
|
||||||
public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) {
|
public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) {
|
||||||
mContext = ctx;
|
mContext = ctx;
|
||||||
@@ -325,6 +326,11 @@ public class UpstreamNetworkMonitor {
|
|||||||
final UpstreamNetworkState dfltState = (mDefaultInternetNetwork != null)
|
final UpstreamNetworkState dfltState = (mDefaultInternetNetwork != null)
|
||||||
? mNetworkMap.get(mDefaultInternetNetwork)
|
? mNetworkMap.get(mDefaultInternetNetwork)
|
||||||
: null;
|
: null;
|
||||||
|
if (mPreferTestNetworks) {
|
||||||
|
final UpstreamNetworkState testState = findFirstTestNetwork(mNetworkMap.values());
|
||||||
|
if (testState != null) return testState;
|
||||||
|
}
|
||||||
|
|
||||||
if (isNetworkUsableAndNotCellular(dfltState)) return dfltState;
|
if (isNetworkUsableAndNotCellular(dfltState)) return dfltState;
|
||||||
|
|
||||||
if (!isCellularUpstreamPermitted()) return null;
|
if (!isCellularUpstreamPermitted()) return null;
|
||||||
@@ -656,6 +662,20 @@ public class UpstreamNetworkMonitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isTestNetwork(UpstreamNetworkState ns) {
|
||||||
|
return ((ns != null) && (ns.networkCapabilities != null)
|
||||||
|
&& ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_TEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
private UpstreamNetworkState findFirstTestNetwork(
|
||||||
|
Iterable<UpstreamNetworkState> netStates) {
|
||||||
|
for (UpstreamNetworkState ns : netStates) {
|
||||||
|
if (isTestNetwork(ns)) return ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a legacy type (TYPE_WIFI, ...) returns the corresponding NetworkCapabilities instance.
|
* Given a legacy type (TYPE_WIFI, ...) returns the corresponding NetworkCapabilities instance.
|
||||||
* This function is used for deprecated legacy type and be disabled by default.
|
* This function is used for deprecated legacy type and be disabled by default.
|
||||||
@@ -681,4 +701,9 @@ public class UpstreamNetworkMonitor {
|
|||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Set test network as preferred upstream. */
|
||||||
|
public void setPreferTestNetworks(boolean prefer) {
|
||||||
|
mPreferTestNetworks = prefer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package {
|
|||||||
|
|
||||||
java_defaults {
|
java_defaults {
|
||||||
name: "TetheringIntegrationTestsDefaults",
|
name: "TetheringIntegrationTestsDefaults",
|
||||||
|
defaults: ["framework-connectivity-test-defaults"],
|
||||||
srcs: [
|
srcs: [
|
||||||
"src/**/*.java",
|
"src/**/*.java",
|
||||||
"src/**/*.kt",
|
"src/**/*.kt",
|
||||||
|
|||||||
@@ -17,6 +17,11 @@
|
|||||||
package="com.android.networkstack.tethering.tests.integration">
|
package="com.android.networkstack.tethering.tests.integration">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<!-- The test need CHANGE_NETWORK_STATE permission to use requestNetwork API to setup test
|
||||||
|
network. Since R shell application don't have such permission, grant permission to the test
|
||||||
|
here. TODO: Remove CHANGE_NETWORK_STATE permission here and use adopt shell perssion to
|
||||||
|
obtain CHANGE_NETWORK_STATE for testing once R device is no longer supported. -->
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
||||||
|
|
||||||
<application android:debuggable="true">
|
<application android:debuggable="true">
|
||||||
<uses-library android:name="android.test.runner" />
|
<uses-library android:name="android.test.runner" />
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
|
|||||||
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
|
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
|
||||||
import static android.Manifest.permission.NETWORK_SETTINGS;
|
import static android.Manifest.permission.NETWORK_SETTINGS;
|
||||||
import static android.Manifest.permission.TETHER_PRIVILEGED;
|
import static android.Manifest.permission.TETHER_PRIVILEGED;
|
||||||
|
import static android.net.InetAddresses.parseNumericAddress;
|
||||||
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
|
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
|
||||||
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
|
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
|
||||||
import static android.net.TetheringManager.TETHERING_ETHERNET;
|
import static android.net.TetheringManager.TETHERING_ETHERNET;
|
||||||
@@ -29,6 +30,7 @@ import static android.system.OsConstants.IPPROTO_ICMPV6;
|
|||||||
import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
|
import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
|
||||||
import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
|
import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
|
||||||
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
|
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
|
||||||
|
import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -65,6 +67,7 @@ import com.android.net.module.util.structs.Icmpv6Header;
|
|||||||
import com.android.net.module.util.structs.Ipv6Header;
|
import com.android.net.module.util.structs.Ipv6Header;
|
||||||
import com.android.testutils.HandlerUtils;
|
import com.android.testutils.HandlerUtils;
|
||||||
import com.android.testutils.TapPacketReader;
|
import com.android.testutils.TapPacketReader;
|
||||||
|
import com.android.testutils.TestNetworkTracker;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -78,6 +81,7 @@ import java.net.InterfaceAddress;
|
|||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@@ -102,12 +106,16 @@ public class EthernetTetheringTest {
|
|||||||
DhcpPacket.DHCP_LEASE_TIME,
|
DhcpPacket.DHCP_LEASE_TIME,
|
||||||
};
|
};
|
||||||
private static final String DHCP_HOSTNAME = "testhostname";
|
private static final String DHCP_HOSTNAME = "testhostname";
|
||||||
|
private static final LinkAddress TEST_IP4_ADDR = new LinkAddress("10.0.0.1/8");
|
||||||
|
private static final LinkAddress TEST_IP6_ADDR = new LinkAddress("2001:db8:1::101/64");
|
||||||
|
private static final InetAddress TEST_IP4_DNS = parseNumericAddress("8.8.8.8");
|
||||||
|
private static final InetAddress TEST_IP6_DNS = parseNumericAddress("2001:db8:1::888");
|
||||||
|
|
||||||
private final Context mContext = InstrumentationRegistry.getContext();
|
private final Context mContext = InstrumentationRegistry.getContext();
|
||||||
private final EthernetManager mEm = mContext.getSystemService(EthernetManager.class);
|
private final EthernetManager mEm = mContext.getSystemService(EthernetManager.class);
|
||||||
private final TetheringManager mTm = mContext.getSystemService(TetheringManager.class);
|
private final TetheringManager mTm = mContext.getSystemService(TetheringManager.class);
|
||||||
|
|
||||||
private TestNetworkInterface mTestIface;
|
private TestNetworkInterface mDownstreamIface;
|
||||||
private HandlerThread mHandlerThread;
|
private HandlerThread mHandlerThread;
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
private TapPacketReader mTapPacketReader;
|
private TapPacketReader mTapPacketReader;
|
||||||
@@ -119,6 +127,8 @@ public class EthernetTetheringTest {
|
|||||||
InstrumentationRegistry.getInstrumentation().getUiAutomation();
|
InstrumentationRegistry.getInstrumentation().getUiAutomation();
|
||||||
private boolean mRunTests;
|
private boolean mRunTests;
|
||||||
|
|
||||||
|
private TestNetworkTracker mUpstreamTracker;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
// Needed to create a TestNetworkInterface, to call requestTetheredInterface, and to receive
|
// Needed to create a TestNetworkInterface, to call requestTetheredInterface, and to receive
|
||||||
@@ -138,6 +148,13 @@ public class EthernetTetheringTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void cleanUp() throws Exception {
|
private void cleanUp() throws Exception {
|
||||||
|
mTm.setPreferTestNetworks(false);
|
||||||
|
|
||||||
|
if (mUpstreamTracker != null) {
|
||||||
|
mUpstreamTracker.teardown();
|
||||||
|
mUpstreamTracker = null;
|
||||||
|
}
|
||||||
|
|
||||||
mTm.stopTethering(TETHERING_ETHERNET);
|
mTm.stopTethering(TETHERING_ETHERNET);
|
||||||
if (mTetheringEventCallback != null) {
|
if (mTetheringEventCallback != null) {
|
||||||
mTetheringEventCallback.awaitInterfaceUntethered();
|
mTetheringEventCallback.awaitInterfaceUntethered();
|
||||||
@@ -169,21 +186,21 @@ public class EthernetTetheringTest {
|
|||||||
// This test requires manipulating packets. Skip if there is a physical Ethernet connected.
|
// This test requires manipulating packets. Skip if there is a physical Ethernet connected.
|
||||||
assumeFalse(mEm.isAvailable());
|
assumeFalse(mEm.isAvailable());
|
||||||
|
|
||||||
mTestIface = createTestInterface();
|
mDownstreamIface = createTestInterface();
|
||||||
// This must be done now because as soon as setIncludeTestInterfaces(true) is called, the
|
// This must be done now because as soon as setIncludeTestInterfaces(true) is called, the
|
||||||
// interface will be placed in client mode, which will delete the link-local address.
|
// interface will be placed in client mode, which will delete the link-local address.
|
||||||
// At that point NetworkInterface.getByName() will cease to work on the interface, because
|
// At that point NetworkInterface.getByName() will cease to work on the interface, because
|
||||||
// starting in R NetworkInterface can no longer see interfaces without IP addresses.
|
// starting in R NetworkInterface can no longer see interfaces without IP addresses.
|
||||||
int mtu = getMTU(mTestIface);
|
int mtu = getMTU(mDownstreamIface);
|
||||||
|
|
||||||
Log.d(TAG, "Including test interfaces");
|
Log.d(TAG, "Including test interfaces");
|
||||||
mEm.setIncludeTestInterfaces(true);
|
mEm.setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
final String iface = mTetheredInterfaceRequester.getInterface();
|
final String iface = mTetheredInterfaceRequester.getInterface();
|
||||||
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
mTestIface.getInterfaceName(), iface);
|
mDownstreamIface.getInterfaceName(), iface);
|
||||||
|
|
||||||
checkVirtualEthernet(mTestIface, mtu);
|
checkVirtualEthernet(mDownstreamIface, mtu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -195,13 +212,13 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
mEm.setIncludeTestInterfaces(true);
|
mEm.setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
mTestIface = createTestInterface();
|
mDownstreamIface = createTestInterface();
|
||||||
|
|
||||||
final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
mTestIface.getInterfaceName(), iface);
|
mDownstreamIface.getInterfaceName(), iface);
|
||||||
|
|
||||||
checkVirtualEthernet(mTestIface, getMTU(mTestIface));
|
checkVirtualEthernet(mDownstreamIface, getMTU(mDownstreamIface));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -210,11 +227,11 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
mEm.setIncludeTestInterfaces(true);
|
mEm.setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
mTestIface = createTestInterface();
|
mDownstreamIface = createTestInterface();
|
||||||
|
|
||||||
final String iface = mTetheredInterfaceRequester.getInterface();
|
final String iface = mTetheredInterfaceRequester.getInterface();
|
||||||
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
mTestIface.getInterfaceName(), iface);
|
mDownstreamIface.getInterfaceName(), iface);
|
||||||
|
|
||||||
assertInvalidStaticIpv4Request(iface, null, null);
|
assertInvalidStaticIpv4Request(iface, null, null);
|
||||||
assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
|
assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
|
||||||
@@ -235,8 +252,8 @@ public class EthernetTetheringTest {
|
|||||||
byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
|
byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
|
||||||
byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
|
byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
|
||||||
|
|
||||||
FileDescriptor fd = mTestIface.getFileDescriptor().getFileDescriptor();
|
FileDescriptor fd = mDownstreamIface.getFileDescriptor().getFileDescriptor();
|
||||||
mTapPacketReader = makePacketReader(fd, getMTU(mTestIface));
|
mTapPacketReader = makePacketReader(fd, getMTU(mDownstreamIface));
|
||||||
DhcpResults dhcpResults = runDhcp(fd, client1);
|
DhcpResults dhcpResults = runDhcp(fd, client1);
|
||||||
assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
|
assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
|
||||||
|
|
||||||
@@ -301,11 +318,11 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
mEm.setIncludeTestInterfaces(true);
|
mEm.setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
mTestIface = createTestInterface();
|
mDownstreamIface = createTestInterface();
|
||||||
|
|
||||||
final String iface = mTetheredInterfaceRequester.getInterface();
|
final String iface = mTetheredInterfaceRequester.getInterface();
|
||||||
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
mTestIface.getInterfaceName(), iface);
|
mDownstreamIface.getInterfaceName(), iface);
|
||||||
|
|
||||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET)
|
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET)
|
||||||
.setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build();
|
.setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build();
|
||||||
@@ -316,8 +333,7 @@ public class EthernetTetheringTest {
|
|||||||
// does not have an IP address, and unprivileged apps cannot see interfaces without IP
|
// does not have an IP address, and unprivileged apps cannot see interfaces without IP
|
||||||
// addresses. This shouldn't be flaky because the TAP interface will buffer all packets even
|
// addresses. This shouldn't be flaky because the TAP interface will buffer all packets even
|
||||||
// before the reader is started.
|
// before the reader is started.
|
||||||
FileDescriptor fd = mTestIface.getFileDescriptor().getFileDescriptor();
|
mTapPacketReader = makePacketReader(mDownstreamIface);
|
||||||
mTapPacketReader = makePacketReader(fd, getMTU(mTestIface));
|
|
||||||
|
|
||||||
expectRouterAdvertisement(mTapPacketReader, iface, 2000 /* timeoutMs */);
|
expectRouterAdvertisement(mTapPacketReader, iface, 2000 /* timeoutMs */);
|
||||||
expectLocalOnlyAddresses(iface);
|
expectLocalOnlyAddresses(iface);
|
||||||
@@ -354,12 +370,14 @@ public class EthernetTetheringTest {
|
|||||||
private final CountDownLatch mLocalOnlyStartedLatch = new CountDownLatch(1);
|
private final CountDownLatch mLocalOnlyStartedLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch mLocalOnlyStoppedLatch = new CountDownLatch(1);
|
private final CountDownLatch mLocalOnlyStoppedLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch mClientConnectedLatch = new CountDownLatch(1);
|
private final CountDownLatch mClientConnectedLatch = new CountDownLatch(1);
|
||||||
|
private final CountDownLatch mUpstreamConnectedLatch = new CountDownLatch(1);
|
||||||
private final TetheringInterface mIface;
|
private final TetheringInterface mIface;
|
||||||
|
|
||||||
private volatile boolean mInterfaceWasTethered = false;
|
private volatile boolean mInterfaceWasTethered = false;
|
||||||
private volatile boolean mInterfaceWasLocalOnly = false;
|
private volatile boolean mInterfaceWasLocalOnly = false;
|
||||||
private volatile boolean mUnregistered = false;
|
private volatile boolean mUnregistered = false;
|
||||||
private volatile Collection<TetheredClient> mClients = null;
|
private volatile Collection<TetheredClient> mClients = null;
|
||||||
|
private volatile Network mUpstream = null;
|
||||||
|
|
||||||
MyTetheringEventCallback(TetheringManager tm, String iface) {
|
MyTetheringEventCallback(TetheringManager tm, String iface) {
|
||||||
mTm = tm;
|
mTm = tm;
|
||||||
@@ -465,6 +483,22 @@ public class EthernetTetheringTest {
|
|||||||
mClientConnectedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
mClientConnectedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
return mClients;
|
return mClients;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpstreamChanged(Network network) {
|
||||||
|
// Ignore stale callbacks registered by previous test cases.
|
||||||
|
if (mUnregistered) return;
|
||||||
|
|
||||||
|
Log.d(TAG, "Got upstream changed: " + network);
|
||||||
|
mUpstream = network;
|
||||||
|
if (mUpstream != null) mUpstreamConnectedLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Network awaitFirstUpstreamConnected() throws Exception {
|
||||||
|
assertTrue("Did not receive upstream connected callback after " + TIMEOUT_MS + "ms",
|
||||||
|
mUpstreamConnectedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
|
return mUpstream;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MyTetheringEventCallback enableEthernetTethering(String iface,
|
private MyTetheringEventCallback enableEthernetTethering(String iface,
|
||||||
@@ -508,6 +542,11 @@ public class EthernetTetheringTest {
|
|||||||
return nif.getMTU();
|
return nif.getMTU();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TapPacketReader makePacketReader(final TestNetworkInterface iface) throws Exception {
|
||||||
|
FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
|
||||||
|
return makePacketReader(fd, getMTU(iface));
|
||||||
|
}
|
||||||
|
|
||||||
private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
|
private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
|
||||||
final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
|
final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
|
||||||
mHandler.post(() -> reader.start());
|
mHandler.post(() -> reader.start());
|
||||||
@@ -701,10 +740,45 @@ public class EthernetTetheringTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void maybeDeleteTestInterface() throws Exception {
|
private void maybeDeleteTestInterface() throws Exception {
|
||||||
if (mTestIface != null) {
|
if (mDownstreamIface != null) {
|
||||||
mTestIface.getFileDescriptor().close();
|
mDownstreamIface.getFileDescriptor().close();
|
||||||
Log.d(TAG, "Deleted test interface " + mTestIface.getInterfaceName());
|
Log.d(TAG, "Deleted test interface " + mDownstreamIface.getInterfaceName());
|
||||||
mTestIface = null;
|
mDownstreamIface = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TestNetworkTracker createTestUpstream(final List<LinkAddress> addresses)
|
||||||
|
throws Exception {
|
||||||
|
mTm.setPreferTestNetworks(true);
|
||||||
|
|
||||||
|
return initTestNetwork(mContext, addresses, TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTestNetworkUpstream() throws Exception {
|
||||||
|
assumeFalse(mEm.isAvailable());
|
||||||
|
|
||||||
|
// MyTetheringEventCallback currently only support await first available upstream. Tethering
|
||||||
|
// may select internet network as upstream if test network is not available and not be
|
||||||
|
// preferred yet. Create test upstream network before enable tethering.
|
||||||
|
mUpstreamTracker = createTestUpstream(toList(TEST_IP4_ADDR, TEST_IP6_ADDR));
|
||||||
|
|
||||||
|
mDownstreamIface = createTestInterface();
|
||||||
|
mEm.setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
|
final String iface = mTetheredInterfaceRequester.getInterface();
|
||||||
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
|
mDownstreamIface.getInterfaceName(), iface);
|
||||||
|
|
||||||
|
mTetheringEventCallback = enableEthernetTethering(mDownstreamIface.getInterfaceName());
|
||||||
|
assertEquals("onUpstreamChanged for unexpected network", mUpstreamTracker.getNetwork(),
|
||||||
|
mTetheringEventCallback.awaitFirstUpstreamConnected());
|
||||||
|
|
||||||
|
mTapPacketReader = makePacketReader(mDownstreamIface);
|
||||||
|
// TODO: do basic forwarding test here.
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> List<T> toList(T... array) {
|
||||||
|
return Arrays.asList(array);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ java_defaults {
|
|||||||
// meaning @hide APIs in framework-connectivity are resolved before @SystemApi
|
// meaning @hide APIs in framework-connectivity are resolved before @SystemApi
|
||||||
// stubs in framework
|
// stubs in framework
|
||||||
"framework-connectivity.impl",
|
"framework-connectivity.impl",
|
||||||
|
"framework-tethering.impl",
|
||||||
"framework",
|
"framework",
|
||||||
|
|
||||||
// if sdk_version="" this gets automatically included, but here we need to add manually.
|
// if sdk_version="" this gets automatically included, but here we need to add manually.
|
||||||
|
|||||||
Reference in New Issue
Block a user