Snap for 8677156 from 3caf95c8fc136b2fdb135db5029119f62b053932 to tm-release
Change-Id: I9e2d6f75ada739322c635b0412f19db0386e4cd8
diff --git a/Tethering/jarjar-rules.txt b/Tethering/jarjar-rules.txt
index 40eed3f..904e491 100644
--- a/Tethering/jarjar-rules.txt
+++ b/Tethering/jarjar-rules.txt
@@ -4,6 +4,7 @@
# module will be overwritten by the ones in the framework.
rule com.android.internal.util.** com.android.networkstack.tethering.util.@1
rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1
+rule android.util.IndentingPrintWriter* com.android.networkstack.tethering.util.AndroidUtilIndentingPrintWriter@1
rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1
@@ -13,4 +14,7 @@
# Classes from net-utils-device-common
rule com.android.net.module.util.Struct* com.android.networkstack.tethering.util.Struct@1
-rule com.google.protobuf.** com.android.networkstack.tethering.protobuf@1
\ No newline at end of file
+rule com.google.protobuf.** com.android.networkstack.tethering.protobuf@1
+
+# Classes for hardware offload hidl interface
+rule android.hidl.base.V1_0.DebugInfo* com.android.networkstack.tethering.hidl.base.V1_0.DebugInfo@1
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 3699f7a..5869f2b 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -36,9 +36,11 @@
import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4;
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.testutils.DeviceInfoUtils.KVersion;
import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -1067,23 +1069,43 @@
false /* usingBpf */);
}
- private static boolean isUdpOffloadSupportedByKernel() {
- final String kVersionString = VintfRuntimeInfo.getKernelVersion();
- // Kernel version which is older than 4.14 doesn't support UDP offload absolutely. Kernel
- // version which is between 4.14 and 5.8 support UDP offload probably. Simply apply kernel
- // 4.14 to be threshold first and monitor on what devices tests fail for improving the
- // offload support checking.
- return DeviceInfoUtils.compareMajorMinorVersion(kVersionString, "4.14") >= 0;
+ private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
+ final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion);
+ return current.isInRange(new KVersion(4, 14, 222), new KVersion(4, 19, 0))
+ || current.isInRange(new KVersion(4, 19, 176), new KVersion(5, 4, 0))
+ || current.isAtLeast(new KVersion(5, 4, 98));
}
@Test
+ public void testIsUdpOffloadSupportedByKernel() throws Exception {
+ assertFalse(isUdpOffloadSupportedByKernel("4.14.221"));
+ assertTrue(isUdpOffloadSupportedByKernel("4.14.222"));
+ assertTrue(isUdpOffloadSupportedByKernel("4.16.0"));
+ assertTrue(isUdpOffloadSupportedByKernel("4.18.0"));
+ assertFalse(isUdpOffloadSupportedByKernel("4.19.0"));
+
+ assertFalse(isUdpOffloadSupportedByKernel("4.19.175"));
+ assertTrue(isUdpOffloadSupportedByKernel("4.19.176"));
+ assertTrue(isUdpOffloadSupportedByKernel("5.2.0"));
+ assertTrue(isUdpOffloadSupportedByKernel("5.3.0"));
+ assertFalse(isUdpOffloadSupportedByKernel("5.4.0"));
+
+ assertFalse(isUdpOffloadSupportedByKernel("5.4.97"));
+ assertTrue(isUdpOffloadSupportedByKernel("5.4.98"));
+ assertTrue(isUdpOffloadSupportedByKernel("5.10.0"));
+ }
+
+ // TODO: refactor test testTetherUdpV4* into IPv4 UDP non-offload and offload tests.
+ // That can be easier to know which feature is verified from test results.
+ @Test
@IgnoreUpTo(Build.VERSION_CODES.R)
public void testTetherUdpV4AfterR() throws Exception {
initializeTethering();
- boolean usingBpf = isUdpOffloadSupportedByKernel();
+ final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
+ boolean usingBpf = isUdpOffloadSupportedByKernel(kernelVersion);
if (!usingBpf) {
Log.i(TAG, "testTetherUdpV4AfterR will skip BPF offload test for kernel "
- + VintfRuntimeInfo.getKernelVersion());
+ + kernelVersion);
}
runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
usingBpf);
diff --git a/framework-t/src/android/net/nsd/NsdServiceInfo.java b/framework-t/src/android/net/nsd/NsdServiceInfo.java
index 2621594..200c808 100644
--- a/framework-t/src/android/net/nsd/NsdServiceInfo.java
+++ b/framework-t/src/android/net/nsd/NsdServiceInfo.java
@@ -53,6 +53,8 @@
@Nullable
private Network mNetwork;
+ private int mInterfaceIndex;
+
public NsdServiceInfo() {
}
@@ -312,8 +314,11 @@
/**
* Get the network where the service can be found.
*
- * This is never null if this {@link NsdServiceInfo} was obtained from
- * {@link NsdManager#discoverServices} or {@link NsdManager#resolveService}.
+ * This is set if this {@link NsdServiceInfo} was obtained from
+ * {@link NsdManager#discoverServices} or {@link NsdManager#resolveService}, unless the service
+ * was found on a network interface that does not have a {@link Network} (such as a tethering
+ * downstream, where services are advertised from devices connected to this device via
+ * tethering).
*/
@Nullable
public Network getNetwork() {
@@ -329,6 +334,26 @@
mNetwork = network;
}
+ /**
+ * Get the index of the network interface where the service was found.
+ *
+ * This is only set when the service was found on an interface that does not have a usable
+ * Network, in which case {@link #getNetwork()} returns null.
+ * @return The interface index as per {@link java.net.NetworkInterface#getIndex}, or 0 if unset.
+ * @hide
+ */
+ public int getInterfaceIndex() {
+ return mInterfaceIndex;
+ }
+
+ /**
+ * Set the index of the network interface where the service was found.
+ * @hide
+ */
+ public void setInterfaceIndex(int interfaceIndex) {
+ mInterfaceIndex = interfaceIndex;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -375,6 +400,7 @@
}
dest.writeParcelable(mNetwork, 0);
+ dest.writeInt(mInterfaceIndex);
}
/** Implement the Parcelable interface */
@@ -405,6 +431,7 @@
info.mTxtRecord.put(in.readString(), valueArray);
}
info.mNetwork = in.readParcelable(null, Network.class);
+ info.mInterfaceIndex = in.readInt();
return info;
}
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 6def44f..95e6114 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -23,6 +23,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
+import android.net.INetd;
import android.net.LinkProperties;
import android.net.Network;
import android.net.mdns.aidl.DiscoveryInfo;
@@ -466,7 +467,7 @@
// interfaces that do not have an associated Network.
break;
}
- servInfo.setNetwork(new Network(foundNetId));
+ setServiceNetworkForCallback(servInfo, info.netId, info.interfaceIdx);
clientInfo.onServiceFound(clientId, servInfo);
break;
}
@@ -476,10 +477,11 @@
final String type = info.registrationType;
final int lostNetId = info.netId;
servInfo = new NsdServiceInfo(name, type);
- // The network could be null if it was torn down when the service is lost
- // TODO: avoid returning null in that case, possibly by remembering found
- // services on the same interface index and their network at the time
- servInfo.setNetwork(lostNetId == 0 ? null : new Network(lostNetId));
+ // The network could be set to null (netId 0) if it was torn down when the
+ // service is lost
+ // TODO: avoid returning null in that case, possibly by remembering
+ // found services on the same interface index and their network at the time
+ setServiceNetworkForCallback(servInfo, lostNetId, info.interfaceIdx);
clientInfo.onServiceLost(clientId, servInfo);
break;
}
@@ -557,7 +559,6 @@
final GetAddressInfo info = (GetAddressInfo) obj;
final String address = info.address;
final int netId = info.netId;
- final Network network = netId == NETID_UNSET ? null : new Network(netId);
InetAddress serviceHost = null;
try {
serviceHost = InetAddress.getByName(address);
@@ -568,9 +569,10 @@
// If the resolved service is on an interface without a network, consider it
// as a failure: it would not be usable by apps as they would need
// privileged permissions.
- if (network != null && serviceHost != null) {
+ if (netId != NETID_UNSET && serviceHost != null) {
clientInfo.mResolvedService.setHost(serviceHost);
- clientInfo.mResolvedService.setNetwork(network);
+ setServiceNetworkForCallback(clientInfo.mResolvedService,
+ netId, info.interfaceIdx);
clientInfo.onResolveServiceSucceeded(
clientId, clientInfo.mResolvedService);
} else {
@@ -590,6 +592,26 @@
}
}
+ private static void setServiceNetworkForCallback(NsdServiceInfo info, int netId, int ifaceIdx) {
+ switch (netId) {
+ case NETID_UNSET:
+ info.setNetwork(null);
+ break;
+ case INetd.LOCAL_NET_ID:
+ // Special case for LOCAL_NET_ID: Networks on netId 99 are not generally
+ // visible / usable for apps, so do not return it. Store the interface
+ // index instead, so at least if the client tries to resolve the service
+ // with that NsdServiceInfo, it will be done on the same interface.
+ // If they recreate the NsdServiceInfo themselves, resolution would be
+ // done on all interfaces as before T, which should also work.
+ info.setNetwork(null);
+ info.setInterfaceIndex(ifaceIdx);
+ break;
+ default:
+ info.setNetwork(new Network(netId));
+ }
+ }
+
// The full service name is escaped from standard DNS rules on mdnsresponder, making it suitable
// for passing to standard system DNS APIs such as res_query() . Thus, make the service name
// unescape for getting right service address. See "Notes on DNS Name Escaping" on
@@ -767,9 +789,8 @@
String type = service.getServiceType();
int port = service.getPort();
byte[] textRecord = service.getTxtRecord();
- final Network network = service.getNetwork();
- final int registerInterface = getNetworkInterfaceIndex(network);
- if (network != null && registerInterface == IFACE_IDX_ANY) {
+ final int registerInterface = getNetworkInterfaceIndex(service);
+ if (service.getNetwork() != null && registerInterface == IFACE_IDX_ANY) {
Log.e(TAG, "Interface to register service on not found");
return false;
}
@@ -781,10 +802,9 @@
}
private boolean discoverServices(int discoveryId, NsdServiceInfo serviceInfo) {
- final Network network = serviceInfo.getNetwork();
final String type = serviceInfo.getServiceType();
- final int discoverInterface = getNetworkInterfaceIndex(network);
- if (network != null && discoverInterface == IFACE_IDX_ANY) {
+ final int discoverInterface = getNetworkInterfaceIndex(serviceInfo);
+ if (serviceInfo.getNetwork() != null && discoverInterface == IFACE_IDX_ANY) {
Log.e(TAG, "Interface to discover service on not found");
return false;
}
@@ -798,9 +818,8 @@
private boolean resolveService(int resolveId, NsdServiceInfo service) {
final String name = service.getServiceName();
final String type = service.getServiceType();
- final Network network = service.getNetwork();
- final int resolveInterface = getNetworkInterfaceIndex(network);
- if (network != null && resolveInterface == IFACE_IDX_ANY) {
+ final int resolveInterface = getNetworkInterfaceIndex(service);
+ if (service.getNetwork() != null && resolveInterface == IFACE_IDX_ANY) {
Log.e(TAG, "Interface to resolve service on not found");
return false;
}
@@ -816,8 +835,17 @@
* this is to support the legacy mdnsresponder implementation, which historically resolved
* services on an unspecified network.
*/
- private int getNetworkInterfaceIndex(Network network) {
- if (network == null) return IFACE_IDX_ANY;
+ private int getNetworkInterfaceIndex(NsdServiceInfo serviceInfo) {
+ final Network network = serviceInfo.getNetwork();
+ if (network == null) {
+ // Fallback to getInterfaceIndex if present (typically if the NsdServiceInfo was
+ // provided by NsdService from discovery results, and the service was found on an
+ // interface that has no app-usable Network).
+ if (serviceInfo.getInterfaceIndex() != 0) {
+ return serviceInfo.getInterfaceIndex();
+ }
+ return IFACE_IDX_ANY;
+ }
final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
if (cm == null) {
diff --git a/tests/common/Android.bp b/tests/common/Android.bp
index 509e881..58731e0 100644
--- a/tests/common/Android.bp
+++ b/tests/common/Android.bp
@@ -140,6 +140,30 @@
],
}
+// defaults for tests that need to build against framework-connectivity's @hide APIs, but also
+// using fully @hide classes that are jarjared (because they have no API member). Similar to
+// framework-connectivity-test-defaults above but uses pre-jarjar class names.
+// Only usable from targets that have visibility on framework-connectivity-pre-jarjar, and apply
+// connectivity jarjar rules so that references to jarjared classes still match: this is limited to
+// connectivity internal tests only.
+java_defaults {
+ name: "framework-connectivity-internal-test-defaults",
+ sdk_version: "core_platform", // tests can use @CorePlatformApi's
+ libs: [
+ // order matters: classes in framework-connectivity are resolved before framework,
+ // meaning @hide APIs in framework-connectivity are resolved before @SystemApi
+ // stubs in framework
+ "framework-connectivity-pre-jarjar",
+ "framework-connectivity-t-pre-jarjar",
+ "framework-tethering.impl",
+ "framework",
+
+ // if sdk_version="" this gets automatically included, but here we need to add manually.
+ "framework-res",
+ ],
+ defaults_visibility: ["//packages/modules/Connectivity/tests:__subpackages__"],
+}
+
// Defaults for tests that want to run in mainline-presubmit.
// Not widely used because many of our tests have AndroidTest.xml files and
// use the mainline-param config-descriptor metadata in AndroidTest.xml.
diff --git a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
index 7286bf6..2b1d173 100644
--- a/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
+++ b/tests/cts/net/src/android/net/cts/Ikev2VpnTest.java
@@ -22,6 +22,7 @@
import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
import static com.android.testutils.TestableNetworkCallbackKt.anyNetwork;
@@ -60,12 +61,7 @@
import com.android.internal.util.HexDump;
import com.android.networkstack.apishim.ConstantsShim;
-import com.android.networkstack.apishim.Ikev2VpnProfileBuilderShimImpl;
-import com.android.networkstack.apishim.Ikev2VpnProfileShimImpl;
import com.android.networkstack.apishim.VpnManagerShimImpl;
-import com.android.networkstack.apishim.common.Ikev2VpnProfileBuilderShim;
-import com.android.networkstack.apishim.common.Ikev2VpnProfileShim;
-import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
import com.android.networkstack.apishim.common.VpnManagerShim;
import com.android.networkstack.apishim.common.VpnProfileStateShim;
import com.android.testutils.DevSdkIgnoreRule;
@@ -228,22 +224,17 @@
}
private Ikev2VpnProfile buildIkev2VpnProfileCommon(
- @NonNull Ikev2VpnProfileBuilderShim builderShim, boolean isRestrictedToTestNetworks,
+ @NonNull Ikev2VpnProfile.Builder builder, boolean isRestrictedToTestNetworks,
boolean requiresValidation) throws Exception {
- builderShim.setBypassable(true)
+ builder.setBypassable(true)
.setAllowedAlgorithms(TEST_ALLOWED_ALGORITHMS)
.setProxy(TEST_PROXY_INFO)
.setMaxMtu(TEST_MTU)
.setMetered(false);
if (TestUtils.shouldTestTApis()) {
- builderShim.setRequiresInternetValidation(requiresValidation);
+ builder.setRequiresInternetValidation(requiresValidation);
}
-
- // Convert shim back to Ikev2VpnProfile.Builder since restrictToTestNetworks is a hidden
- // method and does not defined in shims.
- // TODO: replace it in alternative way to remove the hidden method usage
- final Ikev2VpnProfile.Builder builder = (Ikev2VpnProfile.Builder) builderShim.getBuilder();
if (isRestrictedToTestNetworks) {
builder.restrictToTestNetworks();
}
@@ -259,14 +250,13 @@
? IkeSessionTestUtils.IKE_PARAMS_V6 : IkeSessionTestUtils.IKE_PARAMS_V4,
IkeSessionTestUtils.CHILD_PARAMS);
- final Ikev2VpnProfileBuilderShim builderShim =
- Ikev2VpnProfileBuilderShimImpl.newInstance(null, null, params)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(params)
.setRequiresInternetValidation(requiresValidation)
.setProxy(TEST_PROXY_INFO)
.setMaxMtu(TEST_MTU)
.setMetered(false);
- final Ikev2VpnProfile.Builder builder = (Ikev2VpnProfile.Builder) builderShim.getBuilder();
if (isRestrictedToTestNetworks) {
builder.restrictToTestNetworks();
}
@@ -275,9 +265,8 @@
private Ikev2VpnProfile buildIkev2VpnProfilePsk(@NonNull String remote,
boolean isRestrictedToTestNetworks, boolean requiresValidation) throws Exception {
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(remote, TEST_IDENTITY, null)
- .setAuthPsk(TEST_PSK);
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(remote, TEST_IDENTITY).setAuthPsk(TEST_PSK);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
requiresValidation);
}
@@ -285,8 +274,8 @@
private Ikev2VpnProfile buildIkev2VpnProfileUsernamePassword(boolean isRestrictedToTestNetworks)
throws Exception {
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY, null)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthUsernamePassword(TEST_USER, TEST_PASSWORD, mServerRootCa);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
false /* requiresValidation */);
@@ -294,8 +283,8 @@
private Ikev2VpnProfile buildIkev2VpnProfileDigitalSignature(boolean isRestrictedToTestNetworks)
throws Exception {
- final Ikev2VpnProfileBuilderShim builder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(TEST_SERVER_ADDR_V6, TEST_IDENTITY, null)
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(TEST_SERVER_ADDR_V6, TEST_IDENTITY)
.setAuthDigitalSignature(
mUserCertKey.cert, mUserCertKey.key, mServerRootCa);
return buildIkev2VpnProfileCommon(builder, isRestrictedToTestNetworks,
@@ -328,15 +317,8 @@
assertNull(profile.getServerRootCaCert());
assertNull(profile.getRsaPrivateKey());
assertNull(profile.getUserCert());
- final Ikev2VpnProfileShim<Ikev2VpnProfile> shim = new Ikev2VpnProfileShimImpl(profile);
- if (TestUtils.shouldTestTApis()) {
- assertEquals(requiresValidation, shim.isInternetValidationRequired());
- } else {
- try {
- shim.isInternetValidationRequired();
- fail("Only supported from API level 33");
- } catch (UnsupportedApiLevelException expected) {
- }
+ if (isAtLeastT()) {
+ assertEquals(requiresValidation, profile.isInternetValidationRequired());
}
}
@@ -348,8 +330,8 @@
final IkeTunnelConnectionParams expectedParams = new IkeTunnelConnectionParams(
IkeSessionTestUtils.IKE_PARAMS_V6, IkeSessionTestUtils.CHILD_PARAMS);
- final Ikev2VpnProfileBuilderShim ikeProfileBuilder =
- Ikev2VpnProfileBuilderShimImpl.newInstance(null, null, expectedParams);
+ final Ikev2VpnProfile.Builder ikeProfileBuilder =
+ new Ikev2VpnProfile.Builder(expectedParams);
// Verify the other Ike options could not be set with IkeTunnelConnectionParams.
final Class<IllegalArgumentException> expected = IllegalArgumentException.class;
assertThrows(expected, () -> ikeProfileBuilder.setAuthPsk(TEST_PSK));
@@ -358,10 +340,9 @@
assertThrows(expected, () -> ikeProfileBuilder.setAuthDigitalSignature(
mUserCertKey.cert, mUserCertKey.key, mServerRootCa));
- final Ikev2VpnProfile profile = (Ikev2VpnProfile) ikeProfileBuilder.build().getProfile();
+ final Ikev2VpnProfile profile = ikeProfileBuilder.build();
- assertEquals(expectedParams,
- new Ikev2VpnProfileShimImpl(profile).getIkeTunnelConnectionParams());
+ assertEquals(expectedParams, profile.getIkeTunnelConnectionParams());
}
@Test
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index c9a41ba..18ace4e 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -112,7 +112,7 @@
name: "FrameworksNetTestsDefaults",
min_sdk_version: "30",
defaults: [
- "framework-connectivity-test-defaults",
+ "framework-connectivity-internal-test-defaults",
],
srcs: [
"java/**/*.java",
diff --git a/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java b/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java
index e5e7ebc..829b824 100644
--- a/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java
+++ b/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java
@@ -42,7 +42,9 @@
@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+// TODO(b/234099453): re-enable once a newer prebuilt is available
+// @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.CUR_DEVELOPMENT)
public class NsdServiceInfoTest {
public final static InetAddress LOCALHOST;
@@ -125,6 +127,7 @@
fullInfo.setPort(4242);
fullInfo.setHost(LOCALHOST);
fullInfo.setNetwork(new Network(123));
+ fullInfo.setInterfaceIndex(456);
checkParcelable(fullInfo);
NsdServiceInfo noHostInfo = new NsdServiceInfo();
@@ -175,6 +178,7 @@
assertEquals(original.getHost(), result.getHost());
assertTrue(original.getPort() == result.getPort());
assertEquals(original.getNetwork(), result.getNetwork());
+ assertEquals(original.getInterfaceIndex(), result.getInterfaceIndex());
// Assert equality of attribute map.
Map<String, byte[]> originalMap = original.getAttributes();
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index 3c228d0..d3cfb76 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -19,7 +19,9 @@
import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
@@ -36,6 +38,12 @@
import android.compat.testing.PlatformCompatChangeRule;
import android.content.ContentResolver;
import android.content.Context;
+import android.net.INetd;
+import android.net.InetAddresses;
+import android.net.mdns.aidl.DiscoveryInfo;
+import android.net.mdns.aidl.GetAddressInfo;
+import android.net.mdns.aidl.IMDnsEventListener;
+import android.net.mdns.aidl.ResolutionInfo;
import android.net.nsd.INsdManagerCallback;
import android.net.nsd.INsdServiceConnector;
import android.net.nsd.MDnsManager;
@@ -63,6 +71,7 @@
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.AdditionalAnswers;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -74,7 +83,9 @@
// - test NSD_ON ENABLE/DISABLED listening
@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+// TODO(b/234099453): re-enable once a newer prebuilt is available
+// @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.CUR_DEVELOPMENT)
public class NsdServiceTest {
static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
@@ -275,6 +286,105 @@
verify(mMockMDnsM, never()).stopDaemon();
}
+ @Test
+ public void testDiscoverOnTetheringDownstream() throws Exception {
+ NsdService service = makeService();
+ NsdManager client = connectClient(service);
+
+ final String serviceType = "a_type";
+ final String serviceName = "a_name";
+ final String domainName = "mytestdevice.local";
+ final int interfaceIdx = 123;
+ final NsdManager.DiscoveryListener discListener = mock(NsdManager.DiscoveryListener.class);
+ client.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discListener);
+ waitForIdle();
+
+ final ArgumentCaptor<IMDnsEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(IMDnsEventListener.class);
+ verify(mMockMDnsM).registerEventListener(listenerCaptor.capture());
+ final ArgumentCaptor<Integer> discIdCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMockMDnsM).discover(discIdCaptor.capture(), eq(serviceType),
+ eq(0) /* interfaceIdx */);
+ // NsdManager uses a separate HandlerThread to dispatch callbacks (on ServiceHandler), so
+ // this needs to use a timeout
+ verify(discListener, timeout(TIMEOUT_MS)).onDiscoveryStarted(serviceType);
+
+ final DiscoveryInfo discoveryInfo = new DiscoveryInfo(
+ discIdCaptor.getValue(),
+ IMDnsEventListener.SERVICE_FOUND,
+ serviceName,
+ serviceType,
+ domainName,
+ interfaceIdx,
+ INetd.LOCAL_NET_ID); // LOCAL_NET_ID (99) used on tethering downstreams
+ final IMDnsEventListener eventListener = listenerCaptor.getValue();
+ eventListener.onServiceDiscoveryStatus(discoveryInfo);
+ waitForIdle();
+
+ final ArgumentCaptor<NsdServiceInfo> discoveredInfoCaptor =
+ ArgumentCaptor.forClass(NsdServiceInfo.class);
+ verify(discListener, timeout(TIMEOUT_MS)).onServiceFound(discoveredInfoCaptor.capture());
+ final NsdServiceInfo foundInfo = discoveredInfoCaptor.getValue();
+ assertEquals(serviceName, foundInfo.getServiceName());
+ assertEquals(serviceType, foundInfo.getServiceType());
+ assertNull(foundInfo.getHost());
+ assertNull(foundInfo.getNetwork());
+ assertEquals(interfaceIdx, foundInfo.getInterfaceIndex());
+
+ // After discovering the service, verify resolving it
+ final NsdManager.ResolveListener resolveListener = mock(NsdManager.ResolveListener.class);
+ client.resolveService(foundInfo, resolveListener);
+ waitForIdle();
+
+ final ArgumentCaptor<Integer> resolvIdCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMockMDnsM).resolve(resolvIdCaptor.capture(), eq(serviceName), eq(serviceType),
+ eq("local.") /* domain */, eq(interfaceIdx));
+
+ final int servicePort = 10123;
+ final String serviceFullName = serviceName + "." + serviceType;
+ final ResolutionInfo resolutionInfo = new ResolutionInfo(
+ resolvIdCaptor.getValue(),
+ IMDnsEventListener.SERVICE_RESOLVED,
+ null /* serviceName */,
+ null /* serviceType */,
+ null /* domain */,
+ serviceFullName,
+ domainName,
+ servicePort,
+ new byte[0] /* txtRecord */,
+ interfaceIdx);
+
+ doReturn(true).when(mMockMDnsM).getServiceAddress(anyInt(), any(), anyInt());
+ eventListener.onServiceResolutionStatus(resolutionInfo);
+ waitForIdle();
+
+ final ArgumentCaptor<Integer> getAddrIdCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMockMDnsM).getServiceAddress(getAddrIdCaptor.capture(), eq(domainName),
+ eq(interfaceIdx));
+
+ final String serviceAddress = "192.0.2.123";
+ final GetAddressInfo addressInfo = new GetAddressInfo(
+ getAddrIdCaptor.getValue(),
+ IMDnsEventListener.SERVICE_GET_ADDR_SUCCESS,
+ serviceFullName,
+ serviceAddress,
+ interfaceIdx,
+ INetd.LOCAL_NET_ID);
+ eventListener.onGettingServiceAddressStatus(addressInfo);
+ waitForIdle();
+
+ final ArgumentCaptor<NsdServiceInfo> resInfoCaptor =
+ ArgumentCaptor.forClass(NsdServiceInfo.class);
+ verify(resolveListener, timeout(TIMEOUT_MS)).onServiceResolved(resInfoCaptor.capture());
+ final NsdServiceInfo resolvedService = resInfoCaptor.getValue();
+ assertEquals(serviceName, resolvedService.getServiceName());
+ assertEquals("." + serviceType, resolvedService.getServiceType());
+ assertEquals(InetAddresses.parseNumericAddress(serviceAddress), resolvedService.getHost());
+ assertEquals(servicePort, resolvedService.getPort());
+ assertNull(resolvedService.getNetwork());
+ assertEquals(interfaceIdx, resolvedService.getInterfaceIndex());
+ }
+
private void waitForIdle() {
HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
}
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index bae0433..11fbcb9 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -100,7 +100,11 @@
import android.net.VpnService;
import android.net.VpnTransportInfo;
import android.net.ipsec.ike.IkeSessionCallback;
+import android.net.ipsec.ike.exceptions.IkeException;
+import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
+import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.ipsec.ike.exceptions.IkeTimeoutException;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.ConditionVariable;
@@ -149,6 +153,7 @@
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -1284,15 +1289,16 @@
config -> Arrays.asList(config.flags).contains(flag)));
}
- @Test
- public void testStartPlatformVpnAuthenticationFailed() throws Exception {
+ private void setupPlatformVpnWithSpecificExceptionAndItsErrorCode(IkeException exception,
+ String category, int errorType, int errorCode) throws Exception {
final ArgumentCaptor<IkeSessionCallback> captor =
ArgumentCaptor.forClass(IkeSessionCallback.class);
- final IkeProtocolException exception = mock(IkeProtocolException.class);
- when(exception.getErrorType())
- .thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
- final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+ .thenReturn(mVpnProfile.encode());
+
+ final String sessionKey = vpn.startVpnProfile(TEST_VPN_PKG);
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
@@ -1302,10 +1308,75 @@
verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
.createIkeSession(any(), any(), any(), any(), captor.capture(), any());
final IkeSessionCallback ikeCb = captor.getValue();
- ikeCb.onClosedExceptionally(exception);
+ ikeCb.onClosedWithException(exception);
- verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
+ verifyVpnManagerEvent(sessionKey, category, errorType, errorCode, null /* profileState */);
+ if (errorType == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) {
+ verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
+ .unregisterNetworkCallback(eq(cb));
+ }
+ }
+
+ @Test
+ public void testStartPlatformVpnAuthenticationFailed() throws Exception {
+ final IkeProtocolException exception = mock(IkeProtocolException.class);
+ final int errorCode = IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
+ when(exception.getErrorType()).thenReturn(errorCode);
+ setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception,
+ VpnManager.CATEGORY_EVENT_IKE_ERROR, VpnManager.ERROR_CLASS_NOT_RECOVERABLE,
+ errorCode);
+ }
+
+ @Test
+ public void testStartPlatformVpnFailedWithRecoverableError() throws Exception {
+ final IkeProtocolException exception = mock(IkeProtocolException.class);
+ final int errorCode = IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
+ when(exception.getErrorType()).thenReturn(errorCode);
+ setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception,
+ VpnManager.CATEGORY_EVENT_IKE_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE, errorCode);
+ }
+
+ @Test
+ public void testStartPlatformVpnFailedWithUnknownHostException() throws Exception {
+ final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
+ final UnknownHostException unknownHostException = new UnknownHostException();
+ final int errorCode = VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST;
+ when(exception.getCause()).thenReturn(unknownHostException);
+ setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception,
+ VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
+ errorCode);
+ }
+
+ @Test
+ public void testStartPlatformVpnFailedWithIkeTimeoutException() throws Exception {
+ final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
+ final IkeTimeoutException ikeTimeoutException =
+ new IkeTimeoutException("IkeTimeoutException");
+ final int errorCode = VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT;
+ when(exception.getCause()).thenReturn(ikeTimeoutException);
+ setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception,
+ VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
+ errorCode);
+ }
+
+ @Test
+ public void testStartPlatformVpnFailedWithIkeNetworkLostException() throws Exception {
+ final IkeNetworkLostException exception = new IkeNetworkLostException(
+ new Network(100));
+ setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception,
+ VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
+ VpnManager.ERROR_CODE_NETWORK_LOST);
+ }
+
+ @Test
+ public void testStartPlatformVpnFailedWithIOException() throws Exception {
+ final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
+ final IOException ioException = new IOException();
+ final int errorCode = VpnManager.ERROR_CODE_NETWORK_IO;
+ when(exception.getCause()).thenReturn(ioException);
+ setupPlatformVpnWithSpecificExceptionAndItsErrorCode(exception,
+ VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
+ errorCode);
}
@Test