Merge "Add logs to NetworkCallbackTest to diagnose issues"
diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml
index baf914f..a7e2bd7 100644
--- a/tests/cts/net/AndroidManifest.xml
+++ b/tests/cts/net/AndroidManifest.xml
@@ -26,6 +26,7 @@
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java
index ed67dd1..661457f 100644
--- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java
+++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionPskTest.java
@@ -16,25 +16,17 @@
package android.net.ipsec.ike.cts;
-import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION;
import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import static com.android.internal.util.HexDump.hexStringToByteArray;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import android.net.ipsec.ike.ChildSessionConfiguration;
+import android.net.LinkAddress;
import android.net.ipsec.ike.IkeFqdnIdentification;
import android.net.ipsec.ike.IkeSession;
-import android.net.ipsec.ike.IkeSessionConfiguration;
-import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.IkeSessionParams;
-import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.platform.test.annotations.AppModeFull;
@@ -45,10 +37,11 @@
import org.junit.runner.RunWith;
import java.net.InetAddress;
+import java.util.ArrayList;
import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
-@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps")
+@AppModeFull(reason = "MANAGE_IPSEC_TUNNELS permission can't be granted to instant apps")
public class IkeSessionPskTest extends IkeSessionTestBase {
// Test vectors for success workflow
private static final String SUCCESS_IKE_INIT_RESP =
@@ -89,162 +82,117 @@
+ "9352D71100777B00ABCC6BD7DBEA697827FFAAA48DF9A54D1D68161939F5DC8"
+ "6743A7CEB2BE34AC00095A5B8";
- private static final long IKE_INIT_SPI = Long.parseLong("46B8ECA1E0D72A18", 16);
-
- private static final TunnelModeChildSessionParams CHILD_PARAMS =
- new TunnelModeChildSessionParams.Builder()
- .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
- .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
- .addInternalAddressRequest(AF_INET)
- .addInternalAddressRequest(AF_INET6)
- .build();
-
- private IkeSessionParams createIkeSessionParams(InetAddress mRemoteAddress) {
- return new IkeSessionParams.Builder(sContext)
- .setNetwork(mTunNetwork)
- .setServerHostname(mRemoteAddress.getHostAddress())
- .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher())
- .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher())
- .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME))
- .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME))
- .setAuthPsk(IKE_PSK)
- .build();
- }
-
- private IkeSession openIkeSession(IkeSessionParams ikeParams) {
+ private IkeSession openIkeSessionWithRemoteAddress(InetAddress remoteAddress) {
+ IkeSessionParams ikeParams =
+ new IkeSessionParams.Builder(sContext)
+ .setNetwork(mTunNetwork)
+ .setServerHostname(remoteAddress.getHostAddress())
+ .addSaProposal(SaProposalTest.buildIkeSaProposalWithNormalModeCipher())
+ .addSaProposal(SaProposalTest.buildIkeSaProposalWithCombinedModeCipher())
+ .setLocalIdentification(new IkeFqdnIdentification(LOCAL_HOSTNAME))
+ .setRemoteIdentification(new IkeFqdnIdentification(REMOTE_HOSTNAME))
+ .setAuthPsk(IKE_PSK)
+ .build();
return new IkeSession(
sContext,
ikeParams,
- CHILD_PARAMS,
+ buildTunnelModeChildSessionParams(),
mUserCbExecutor,
mIkeSessionCallback,
mFirstChildSessionCallback);
}
@Test
- public void testIkeSessionSetupAndManageChildSas() throws Exception {
+ public void testIkeSessionSetupAndChildSessionSetupWithTunnelMode() throws Exception {
+ if (!hasTunnelsFeature()) return;
+
// Open IKE Session
- IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress));
- int expectedMsgId = 0;
- mTunUtils.awaitReqAndInjectResp(
- IKE_INIT_SPI,
- expectedMsgId++,
- false /* expectedUseEncap */,
- hexStringToByteArray(SUCCESS_IKE_INIT_RESP));
+ IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
+ performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP);
- mTunUtils.awaitReqAndInjectResp(
- IKE_INIT_SPI,
- expectedMsgId++,
- true /* expectedUseEncap */,
- hexStringToByteArray(SUCCESS_IKE_AUTH_RESP));
+ // IKE INIT and IKE AUTH takes two exchanges. Message ID starts from 2
+ int expectedMsgId = 2;
- // Verify opening IKE Session
- IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig();
- assertNotNull(ikeConfig);
- assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion());
- assertTrue(ikeConfig.getRemoteVendorIds().isEmpty());
- assertTrue(ikeConfig.getPcscfServers().isEmpty());
- assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION));
+ verifyIkeSessionSetupBlocking();
+ verifyChildSessionSetupBlocking(
+ mFirstChildSessionCallback,
+ Arrays.asList(TUNNEL_MODE_INBOUND_TS),
+ Arrays.asList(TUNNEL_MODE_OUTBOUND_TS),
+ Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR));
- IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo();
- assertNotNull(ikeConnectInfo);
- assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress());
- assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress());
- assertEquals(mTunNetwork, ikeConnectInfo.getNetwork());
-
- // Verify opening first Child Session
- ChildSessionConfiguration firstChildConfig = mFirstChildSessionCallback.awaitChildConfig();
- assertNotNull(firstChildConfig);
- assertEquals(
- Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors());
- assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors());
- assertEquals(
- Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR),
- firstChildConfig.getInternalAddresses());
- assertTrue(firstChildConfig.getInternalSubnets().isEmpty());
- assertTrue(firstChildConfig.getInternalDnsServers().isEmpty());
- assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty());
+ IpSecTransformCallRecord firstTransformRecordA =
+ mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
+ IpSecTransformCallRecord firstTransformRecordB =
+ mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
+ verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
// Open additional Child Session
TestChildSessionCallback additionalChildCb = new TestChildSessionCallback();
- ikeSession.openChildSession(CHILD_PARAMS, additionalChildCb);
+ ikeSession.openChildSession(buildTunnelModeChildSessionParams(), additionalChildCb);
mTunUtils.awaitReqAndInjectResp(
- IKE_INIT_SPI,
+ IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
true /* expectedUseEncap */,
- hexStringToByteArray(SUCCESS_CREATE_CHILD_RESP));
+ SUCCESS_CREATE_CHILD_RESP);
// Verify opening additional Child Session
- ChildSessionConfiguration additionalChildConfig = additionalChildCb.awaitChildConfig();
- assertNotNull(additionalChildConfig);
- assertEquals(
- Arrays.asList(EXPECTED_INBOUND_TS), firstChildConfig.getInboundTrafficSelectors());
- assertEquals(Arrays.asList(DEFAULT_V4_TS), firstChildConfig.getOutboundTrafficSelectors());
- assertTrue(additionalChildConfig.getInternalAddresses().isEmpty());
- assertTrue(firstChildConfig.getInternalSubnets().isEmpty());
- assertTrue(firstChildConfig.getInternalDnsServers().isEmpty());
- assertTrue(firstChildConfig.getInternalDhcpServers().isEmpty());
+ verifyChildSessionSetupBlocking(
+ additionalChildCb,
+ Arrays.asList(TUNNEL_MODE_INBOUND_TS),
+ Arrays.asList(TUNNEL_MODE_OUTBOUND_TS),
+ new ArrayList<LinkAddress>());
+ IpSecTransformCallRecord additionalTransformRecordA =
+ additionalChildCb.awaitNextCreatedIpSecTransform();
+ IpSecTransformCallRecord additionalTransformRecordB =
+ additionalChildCb.awaitNextCreatedIpSecTransform();
+ verifyCreateIpSecTransformPair(additionalTransformRecordA, additionalTransformRecordB);
// Close additional Child Session
ikeSession.closeChildSession(additionalChildCb);
mTunUtils.awaitReqAndInjectResp(
- IKE_INIT_SPI,
+ IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
true /* expectedUseEncap */,
- hexStringToByteArray(SUCCESS_DELETE_CHILD_RESP));
+ SUCCESS_DELETE_CHILD_RESP);
+ verifyDeleteIpSecTransformPair(
+ additionalChildCb, additionalTransformRecordA, additionalTransformRecordB);
additionalChildCb.awaitOnClosed();
// Close IKE Session
ikeSession.close();
- mTunUtils.awaitReqAndInjectResp(
- IKE_INIT_SPI,
- expectedMsgId++,
- true /* expectedUseEncap */,
- hexStringToByteArray(SUCCESS_DELETE_IKE_RESP));
-
- mFirstChildSessionCallback.awaitOnClosed();
- mIkeSessionCallback.awaitOnClosed();
-
- // TODO: verify IpSecTransform pair is created and deleted
+ performCloseIkeBlocking(expectedMsgId++, SUCCESS_DELETE_IKE_RESP);
+ verifyCloseIkeAndChildBlocking(firstTransformRecordA, firstTransformRecordB);
}
@Test
- public void testIkeSessionKill() throws Exception {
- // Open IKE Session
- IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress));
- int expectedMsgId = 0;
- mTunUtils.awaitReqAndInjectResp(
- IKE_INIT_SPI,
- expectedMsgId++,
- false /* expectedUseEncap */,
- hexStringToByteArray(SUCCESS_IKE_INIT_RESP));
+ public void testIkeSessionKillWithTunnelMode() throws Exception {
+ if (!hasTunnelsFeature()) return;
- mTunUtils.awaitReqAndInjectResp(
- IKE_INIT_SPI,
- expectedMsgId++,
- true /* expectedUseEncap */,
- hexStringToByteArray(SUCCESS_IKE_AUTH_RESP));
+ // Open IKE Session
+ IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
+ performSetupIkeAndFirstChildBlocking(SUCCESS_IKE_INIT_RESP, SUCCESS_IKE_AUTH_RESP);
ikeSession.kill();
-
mFirstChildSessionCallback.awaitOnClosed();
mIkeSessionCallback.awaitOnClosed();
}
@Test
public void testIkeInitFail() throws Exception {
- String ikeInitFailRespHex =
+ final String ikeInitFailRespHex =
"46B8ECA1E0D72A180000000000000000292022200000000000000024000000080000000E";
// Open IKE Session
- IkeSession ikeSession = openIkeSession(createIkeSessionParams(mRemoteAddress));
+ IkeSession ikeSession = openIkeSessionWithRemoteAddress(mRemoteAddress);
int expectedMsgId = 0;
mTunUtils.awaitReqAndInjectResp(
- IKE_INIT_SPI,
+ IKE_DETERMINISTIC_INITIATOR_SPI,
expectedMsgId++,
false /* expectedUseEncap */,
- hexStringToByteArray(ikeInitFailRespHex));
+ ikeInitFailRespHex);
+
+ mFirstChildSessionCallback.awaitOnClosed();
IkeException exception = mIkeSessionCallback.awaitOnClosedException();
assertNotNull(exception);
@@ -254,5 +202,7 @@
assertArrayEquals(EXPECTED_PROTOCOL_ERROR_DATA_NONE, protocolException.getErrorData());
}
- // TODO(b/148689509): Verify rekey process and handling IKE_AUTH failure
+ // TODO(b/155821007): Verify rekey process and handling IKE_AUTH failure
+
+ // TODO(b/155821007): Test creating transport mode Child SA
}
diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java
index deba8fd..ade9813 100644
--- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java
+++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java
@@ -16,12 +16,21 @@
package android.net.ipsec.ike.cts;
import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS;
+import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.InetAddresses;
+import android.net.IpSecManager;
import android.net.IpSecTransform;
import android.net.LinkAddress;
import android.net.Network;
@@ -32,14 +41,15 @@
import android.net.ipsec.ike.ChildSessionConfiguration;
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.IkeSessionConfiguration;
+import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.IkeTrafficSelector;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.ipsec.ike.cts.TestNetworkUtils.TestNetworkCallback;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.AppModeFull;
-import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -55,6 +65,10 @@
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -65,6 +79,13 @@
*
* <p>Subclasses MUST explicitly call #setUpTestNetwork and #tearDownTestNetwork to be able to use
* the test network
+ *
+ * <p>All IKE Sessions running in test mode will generate SPIs deterministically. That is to say
+ * each IKE Session will always generate the same IKE INIT SPI and test vectors are generated based
+ * on this deterministic IKE SPI. Each test will use different local and remote addresses to avoid
+ * the case that the next test try to allocate the same SPI before the previous test has released
+ * it, since SPI resources are not released in testing thread. Similarly, each test MUST use
+ * different Network instances to avoid sharing the same IkeSocket and hitting IKE SPI collision.
*/
@RunWith(AndroidJUnit4.class)
@AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps")
@@ -76,9 +97,13 @@
InetAddresses.parseNumericAddress("198.51.100.10");
static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR =
new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN);
- static final IkeTrafficSelector EXPECTED_INBOUND_TS =
+
+ static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS =
new IkeTrafficSelector(
MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR);
+ static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS;
+
+ static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16);
// Static state to reduce setup/teardown
static Context sContext = InstrumentationRegistry.getContext();
@@ -116,7 +141,7 @@
InstrumentationRegistry.getInstrumentation()
.getUiAutomation()
.adoptShellPermissionIdentity();
- sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE);
+ sTNM = sContext.getSystemService(TestNetworkManager.class);
// Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and
// a standard permission is insufficient. So we shell out the appop, to give us the
@@ -149,10 +174,6 @@
@After
public void tearDown() throws Exception {
tearDownTestNetwork();
-
- resetNextAvailableAddress(NEXT_AVAILABLE_IP4_ADDR_LOCAL, INITIAL_AVAILABLE_IP4_ADDR_LOCAL);
- resetNextAvailableAddress(
- NEXT_AVAILABLE_IP4_ADDR_REMOTE, INITIAL_AVAILABLE_IP4_ADDR_REMOTE);
}
void setUpTestNetwork(InetAddress localAddr) throws Exception {
@@ -185,9 +206,8 @@
pkg, // Package name
opName, // Appop
(allow ? "allow" : "deny")); // Action
- Log.d("IKE", "CTS setAppOp cmd " + cmd);
- String result = SystemUtil.runShellCommand(cmd);
+ SystemUtil.runShellCommand(cmd);
}
}
@@ -229,6 +249,46 @@
}
}
+ TunnelModeChildSessionParams buildTunnelModeChildSessionParams() {
+ return new TunnelModeChildSessionParams.Builder()
+ .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
+ .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
+ .addInternalAddressRequest(AF_INET)
+ .addInternalAddressRequest(AF_INET6)
+ .build();
+ }
+
+ void performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String ikeAuthRespHex)
+ throws Exception {
+ mTunUtils.awaitReqAndInjectResp(
+ IKE_DETERMINISTIC_INITIATOR_SPI,
+ 0 /* expectedMsgId */,
+ false /* expectedUseEncap */,
+ ikeInitRespHex);
+
+ mTunUtils.awaitReqAndInjectResp(
+ IKE_DETERMINISTIC_INITIATOR_SPI,
+ 1 /* expectedMsgId */,
+ true /* expectedUseEncap */,
+ ikeAuthRespHex);
+ }
+
+ void performSetupIkeAndFirstChildBlocking(
+ String ikeInitRespHex, int expectedAuthReqPktCnt, String... ikeAuthRespPktHex)
+ throws Exception {
+ // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple IKE AUTH
+ // request fragments and injecting multiple IKE AUTH response fragments
+ }
+
+ void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception {
+ mTunUtils.awaitReqAndInjectResp(
+ IKE_DETERMINISTIC_INITIATOR_SPI,
+ expectedMsgId,
+ true /* expectedUseEncap */,
+ deleteIkeRespHex);
+ }
+
+ /** Testing callback that allows caller to block current thread until a method get called */
static class TestIkeSessionCallback implements IkeSessionCallback {
private CompletableFuture<IkeSessionConfiguration> mFutureIkeConfig =
new CompletableFuture<>();
@@ -282,6 +342,7 @@
}
}
+ /** Testing callback that allows caller to block current thread until a method get called */
static class TestChildSessionCallback implements ChildSessionCallback {
private CompletableFuture<ChildSessionConfiguration> mFutureChildConfig =
new CompletableFuture<>();
@@ -366,6 +427,99 @@
this.ipSecTransform = ipSecTransform;
this.direction = direction;
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ipSecTransform, direction);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof IpSecTransformCallRecord)) return false;
+
+ IpSecTransformCallRecord record = (IpSecTransformCallRecord) o;
+ return ipSecTransform.equals(record.ipSecTransform) && direction == record.direction;
+ }
+ }
+
+ void verifyIkeSessionSetupBlocking() throws Exception {
+ IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig();
+ assertNotNull(ikeConfig);
+ assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion());
+ assertTrue(ikeConfig.getRemoteVendorIds().isEmpty());
+ assertTrue(ikeConfig.getPcscfServers().isEmpty());
+ assertTrue(ikeConfig.isIkeExtensionEnabled(EXTENSION_TYPE_FRAGMENTATION));
+
+ IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo();
+ assertNotNull(ikeConnectInfo);
+ assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress());
+ assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress());
+ assertEquals(mTunNetwork, ikeConnectInfo.getNetwork());
+ }
+
+ void verifyChildSessionSetupBlocking(
+ TestChildSessionCallback childCallback,
+ List<IkeTrafficSelector> expectedInboundTs,
+ List<IkeTrafficSelector> expectedOutboundTs,
+ List<LinkAddress> expectedInternalAddresses)
+ throws Exception {
+ ChildSessionConfiguration childConfig = childCallback.awaitChildConfig();
+ assertNotNull(childConfig);
+ assertEquals(expectedInboundTs, childConfig.getInboundTrafficSelectors());
+ assertEquals(expectedOutboundTs, childConfig.getOutboundTrafficSelectors());
+ assertEquals(expectedInternalAddresses, childConfig.getInternalAddresses());
+ assertTrue(childConfig.getInternalSubnets().isEmpty());
+ assertTrue(childConfig.getInternalDnsServers().isEmpty());
+ assertTrue(childConfig.getInternalDhcpServers().isEmpty());
+ }
+
+ void verifyCloseIkeAndChildBlocking(
+ IpSecTransformCallRecord expectedTransformRecordA,
+ IpSecTransformCallRecord expectedTransformRecordB)
+ throws Exception {
+ verifyDeleteIpSecTransformPair(
+ mFirstChildSessionCallback, expectedTransformRecordA, expectedTransformRecordB);
+ mFirstChildSessionCallback.awaitOnClosed();
+ mIkeSessionCallback.awaitOnClosed();
+ }
+
+ static void verifyCreateIpSecTransformPair(
+ IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB) {
+ IpSecTransform transformA = transformRecordA.ipSecTransform;
+ IpSecTransform transformB = transformRecordB.ipSecTransform;
+
+ assertNotNull(transformA);
+ assertNotNull(transformB);
+
+ Set<Integer> expectedDirections = new HashSet<>();
+ expectedDirections.add(IpSecManager.DIRECTION_IN);
+ expectedDirections.add(IpSecManager.DIRECTION_OUT);
+
+ Set<Integer> resultDirections = new HashSet<>();
+ resultDirections.add(transformRecordA.direction);
+ resultDirections.add(transformRecordB.direction);
+
+ assertEquals(expectedDirections, resultDirections);
+ }
+
+ static void verifyDeleteIpSecTransformPair(
+ TestChildSessionCallback childCb,
+ IpSecTransformCallRecord expectedTransformRecordA,
+ IpSecTransformCallRecord expectedTransformRecordB) {
+ Set<IpSecTransformCallRecord> expectedTransforms = new HashSet<>();
+ expectedTransforms.add(expectedTransformRecordA);
+ expectedTransforms.add(expectedTransformRecordB);
+
+ Set<IpSecTransformCallRecord> resultTransforms = new HashSet<>();
+ resultTransforms.add(childCb.awaitNextDeletedIpSecTransform());
+ resultTransforms.add(childCb.awaitNextDeletedIpSecTransform());
+
+ assertEquals(expectedTransforms, resultTransforms);
+ }
+
+ /** Package private method to check if device has IPsec tunnels feature */
+ static boolean hasTunnelsFeature() {
+ return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS);
}
// TODO(b/148689509): Verify IKE Session setup using EAP and digital-signature-based auth
diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java
index 5a8258d..2bff63a 100644
--- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java
+++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeTunUtils.java
@@ -26,6 +26,8 @@
import static android.net.ipsec.ike.cts.PacketUtils.UdpHeader;
import static android.system.OsConstants.IPPROTO_UDP;
+import static com.android.internal.util.HexDump.hexStringToByteArray;
+
import static org.junit.Assert.fail;
import android.os.ParcelFileDescriptor;
@@ -35,6 +37,7 @@
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Arrays;
+import java.util.function.Predicate;
public class IkeTunUtils extends TunUtils {
private static final int PORT_LEN = 2;
@@ -54,17 +57,24 @@
/**
* Await the expected IKE request and inject an IKE response.
*
- * @param respIkePkt IKE response packet without IP/UDP headers or NON ESP MARKER.
+ * @param ikeRespDataHex IKE response hex without IP/UDP headers or NON ESP MARKER.
*/
public byte[] awaitReqAndInjectResp(
- long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, byte[] respIkePkt)
+ long expectedInitIkeSpi,
+ int expectedMsgId,
+ boolean expectedUseEncap,
+ String ikeRespDataHex)
throws Exception {
byte[] request =
awaitIkePacket(
- expectedInitIkeSpi,
- expectedMsgId,
- false /* expectedResp */,
- expectedUseEncap);
+ (pkt) -> {
+ return isExpectedIkePkt(
+ pkt,
+ expectedInitIkeSpi,
+ expectedMsgId,
+ false /* expectedResp */,
+ expectedUseEncap);
+ });
// Build response header by flipping address and port
InetAddress srcAddr = getAddress(request, false /* shouldGetSource */);
@@ -73,32 +83,26 @@
int dstPort = getPort(request, true /* shouldGetSource */);
byte[] response =
- buildIkePacket(srcAddr, dstAddr, srcPort, dstPort, expectedUseEncap, respIkePkt);
+ buildIkePacket(
+ srcAddr,
+ dstAddr,
+ srcPort,
+ dstPort,
+ expectedUseEncap,
+ hexStringToByteArray(ikeRespDataHex));
injectPacket(response);
return request;
}
- private byte[] awaitIkePacket(
- long expectedInitIkeSpi,
- int expectedMsgId,
- boolean expectedResp,
- boolean expectedUseEncap)
- throws Exception {
+ // TODO: Implemented in followup CL (aosp/1308675) to support awaiting multiple
+ // request fragments and injecting multiple response fragments
+
+ private byte[] awaitIkePacket(Predicate<byte[]> pktVerifier) throws Exception {
long endTime = System.currentTimeMillis() + TIMEOUT;
int startIndex = 0;
synchronized (mPackets) {
while (System.currentTimeMillis() < endTime) {
- byte[] ikePkt =
- getFirstMatchingPacket(
- (pkt) -> {
- return isIke(
- pkt,
- expectedInitIkeSpi,
- expectedMsgId,
- expectedResp,
- expectedUseEncap);
- },
- startIndex);
+ byte[] ikePkt = getFirstMatchingPacket(pktVerifier, startIndex);
if (ikePkt != null) {
return ikePkt; // We've found the packet we're looking for.
}
@@ -112,19 +116,14 @@
}
}
- String direction = expectedResp ? "response" : "request";
- fail(
- "No such IKE "
- + direction
- + " found with Initiator SPI "
- + expectedInitIkeSpi
- + " and message ID "
- + expectedMsgId);
+ fail("No matching packet found");
}
- return null;
+
+ throw new IllegalStateException(
+ "Hit an impossible case where fail() didn't throw an exception");
}
- private static boolean isIke(
+ private static boolean isExpectedIkePkt(
byte[] pkt,
long expectedInitIkeSpi,
int expectedMsgId,
@@ -151,7 +150,7 @@
}
return pkt[ipProtocolOffset] == IPPROTO_UDP
- && areSpiAndMsgIdEqual(
+ && isExpectedSpiAndMsgId(
pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp);
}
@@ -168,10 +167,10 @@
return Arrays.equals(NON_ESP_MARKER, nonEspMarker);
}
- private static boolean areSpiAndMsgIdEqual(
+ private static boolean isExpectedSpiAndMsgId(
byte[] pkt,
int ikeOffset,
- long expectedIkeInitSpi,
+ long expectedInitIkeSpi,
int expectedMsgId,
boolean expectedResp) {
if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false;
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index 4418e17..0816aba 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
+++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -16,6 +16,7 @@
package android.net.cts
+import android.Manifest.permission.CONNECTIVITY_INTERNAL
import android.Manifest.permission.NETWORK_SETTINGS
import android.Manifest.permission.READ_DEVICE_CONFIG
import android.Manifest.permission.WRITE_DEVICE_CONFIG
@@ -31,6 +32,7 @@
import android.net.Uri
import android.net.cts.util.CtsNetUtils
import android.net.wifi.WifiManager
+import android.os.Build
import android.os.ConditionVariable
import android.platform.test.annotations.AppModeFull
import android.provider.DeviceConfig
@@ -164,7 +166,10 @@
"access."
assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage)
- doAsShell(NETWORK_SETTINGS) { cm.startCaptivePortalApp(network) }
+ val startPortalAppPermission =
+ if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) CONNECTIVITY_INTERNAL
+ else NETWORK_SETTINGS
+ doAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) }
assertTrue(portalContentRequestCv.block(TEST_TIMEOUT_MS), "The captive portal login " +
"page was still not fetched ${TEST_TIMEOUT_MS}ms after startCaptivePortalApp.")
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 1ee08ff..d498ed9 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -16,13 +16,17 @@
package android.net.cts;
+import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.content.pm.PackageManager.FEATURE_ETHERNET;
import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
-import static android.content.pm.PackageManager.FEATURE_WIFI;
import static android.content.pm.PackageManager.FEATURE_USB_HOST;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver;
import static android.net.cts.util.CtsNetUtils.HTTP_PORT;
@@ -36,6 +40,16 @@
import static android.system.OsConstants.AF_UNSPEC;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import android.annotation.NonNull;
import android.app.Instrumentation;
@@ -45,6 +59,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.ConnectivityManager;
@@ -59,10 +74,12 @@
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
import android.net.NetworkRequest;
+import android.net.NetworkUtils;
import android.net.SocketKeepalive;
import android.net.cts.util.CtsNetUtils;
import android.net.util.KeepaliveUtils;
import android.net.wifi.WifiManager;
+import android.os.Binder;
import android.os.Build;
import android.os.Looper;
import android.os.MessageQueue;
@@ -71,15 +88,22 @@
import android.os.VintfRuntimeInfo;
import android.platform.test.annotations.AppModeFull;
import android.provider.Settings;
-import android.test.AndroidTestCase;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.ArrayUtils;
import libcore.io.Streams;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
@@ -105,7 +129,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class ConnectivityManagerTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class ConnectivityManagerTest {
private static final String TAG = ConnectivityManagerTest.class.getSimpleName();
@@ -117,7 +142,10 @@
private static final int INTERVAL_KEEPALIVE_RETRY_MS = 500;
private static final int MAX_KEEPALIVE_RETRY_COUNT = 3;
private static final int MIN_KEEPALIVE_INTERVAL = 10;
- private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000;
+
+ // Changing meteredness on wifi involves reconnecting, which can take several seconds (involves
+ // re-associating, DHCP...)
+ private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 30_000;
private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20;
private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500;
// device could have only one interface: data, wifi.
@@ -141,22 +169,19 @@
private PackageManager mPackageManager;
private final HashMap<Integer, NetworkConfig> mNetworks =
new HashMap<Integer, NetworkConfig>();
- boolean mWifiConnectAttempted;
+ boolean mWifiWasDisabled;
private UiAutomation mUiAutomation;
private CtsNetUtils mCtsNetUtils;
- private boolean mShellPermissionIdentityAdopted;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- Looper.prepare();
- mContext = getContext();
+ @Before
+ public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = mInstrumentation.getContext();
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
mPackageManager = mContext.getPackageManager();
mCtsNetUtils = new CtsNetUtils(mContext);
- mWifiConnectAttempted = false;
+ mWifiWasDisabled = false;
// Get com.android.internal.R.array.networkAttributes
int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android");
@@ -173,20 +198,17 @@
} catch (Exception e) {}
}
mUiAutomation = mInstrumentation.getUiAutomation();
- mShellPermissionIdentityAdopted = false;
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
// Return WiFi to its original disabled state after tests that explicitly connect.
- if (mWifiConnectAttempted) {
+ if (mWifiWasDisabled) {
mCtsNetUtils.disconnectFromWifi(null);
}
if (mCtsNetUtils.cellConnectAttempted()) {
mCtsNetUtils.disconnectFromCell();
}
- dropShellPermissionIdentity();
- super.tearDown();
}
/**
@@ -195,13 +217,12 @@
* automatically in tearDown().
*/
private Network ensureWifiConnected() {
- if (mWifiManager.isWifiEnabled()) {
- return mCtsNetUtils.getWifiNetwork();
- }
- mWifiConnectAttempted = true;
+ mWifiWasDisabled = !mWifiManager.isWifiEnabled();
+ // Even if wifi is enabled, the network may not be connected or ready yet
return mCtsNetUtils.connectToWifi();
}
+ @Test
public void testIsNetworkTypeValid() {
assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE));
assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI));
@@ -231,12 +252,14 @@
}
+ @Test
public void testSetNetworkPreference() {
// getNetworkPreference() and setNetworkPreference() are both deprecated so they do
// not preform any action. Verify they are at least still callable.
mCm.setNetworkPreference(mCm.getNetworkPreference());
}
+ @Test
public void testGetActiveNetworkInfo() {
NetworkInfo ni = mCm.getActiveNetworkInfo();
@@ -245,6 +268,7 @@
assertTrue(ni.getState() == State.CONNECTED);
}
+ @Test
public void testGetActiveNetwork() {
Network network = mCm.getActiveNetwork();
assertNotNull("You must have an active network connection to complete CTS", network);
@@ -257,6 +281,7 @@
assertTrue(ni.getState() == State.CONNECTED);
}
+ @Test
public void testGetNetworkInfo() {
for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) {
if (shouldBeSupported(type)) {
@@ -275,6 +300,7 @@
}
}
+ @Test
public void testGetAllNetworkInfo() {
NetworkInfo[] ni = mCm.getAllNetworkInfo();
assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES);
@@ -298,6 +324,7 @@
* and that they are made from different IP addresses.
*/
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
public void testOpenConnection() throws Exception {
boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
&& mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
@@ -377,6 +404,7 @@
} catch (UnsupportedOperationException expected) {}
}
+ @Test
public void testStartUsingNetworkFeature() {
final String invalidateFeature = "invalidateFeature";
@@ -406,6 +434,7 @@
(networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported());
}
+ @Test
public void testIsNetworkSupported() {
for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
boolean supported = mCm.isNetworkSupported(type);
@@ -417,12 +446,14 @@
}
}
+ @Test
public void testRequestRouteToHost() {
for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
assertRequestRouteToHostUnsupported(type, HOST_ADDRESS);
}
}
+ @Test
public void testTest() {
mCm.getBackgroundDataSetting();
}
@@ -443,6 +474,7 @@
* that it would increase test coverage by much (how many devices have 3G radio but not Wifi?).
*/
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
public void testRegisterNetworkCallback() {
if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
@@ -484,6 +516,7 @@
* of a {@code NetworkCallback}.
*/
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
public void testRegisterNetworkCallback_withPendingIntent() {
if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
@@ -529,6 +562,7 @@
* see if we get a callback for an INTERNET request.
*/
@AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
+ @Test
public void testRequestNetworkCallback() {
final TestNetworkCallback callback = new TestNetworkCallback();
mCm.requestNetwork(new NetworkRequest.Builder()
@@ -552,6 +586,7 @@
* fail. Use WIFI and switch Wi-Fi off.
*/
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
public void testRequestNetworkCallback_onUnavailable() {
final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
if (previousWifiEnabledState) {
@@ -589,6 +624,7 @@
/** Verify restricted networks cannot be requested. */
@AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
+ @Test
public void testRestrictedNetworks() {
// Verify we can request unrestricted networks:
NetworkRequest request = new NetworkRequest.Builder()
@@ -710,6 +746,7 @@
* for metered and unmetered networks.
*/
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
public void testGetMultipathPreference() throws Exception {
final ContentResolver resolver = mContext.getContentResolver();
ensureWifiConnected();
@@ -878,18 +915,6 @@
keepalivesPerTransport, nc);
}
- private void adoptShellPermissionIdentity() {
- mUiAutomation.adoptShellPermissionIdentity();
- mShellPermissionIdentityAdopted = true;
- }
-
- private void dropShellPermissionIdentity() {
- if (mShellPermissionIdentityAdopted) {
- mUiAutomation.dropShellPermissionIdentity();
- mShellPermissionIdentityAdopted = false;
- }
- }
-
private static boolean isTcpKeepaliveSupportedByKernel() {
final String kVersionString = VintfRuntimeInfo.getKernelVersion();
return compareMajorMinorVersion(kVersionString, "4.8") >= 0;
@@ -924,6 +949,7 @@
* Verifies that version string compare logic returns expected result for various cases.
* Note that only major and minor number are compared.
*/
+ @Test
public void testMajorMinorVersionCompare() {
assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8"));
assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1"));
@@ -943,6 +969,7 @@
* keepalives is set to 0.
*/
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
public void testKeepaliveWifiUnsupported() throws Exception {
if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device"
@@ -952,32 +979,36 @@
final Network network = ensureWifiConnected();
if (getSupportedKeepalivesForNet(network) != 0) return;
+ final InetAddress srcAddr = getFirstV4Address(network);
+ assumeTrue("This test requires native IPv4", srcAddr != null);
- adoptShellPermissionIdentity();
-
- assertEquals(0, createConcurrentSocketKeepalives(network, 1, 0));
- assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1));
-
- dropShellPermissionIdentity();
+ runWithShellPermissionIdentity(() -> {
+ assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 1, 0));
+ assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1));
+ });
}
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
public void testCreateTcpKeepalive() throws Exception {
if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi");
return;
}
- adoptShellPermissionIdentity();
-
final Network network = ensureWifiConnected();
if (getSupportedKeepalivesForNet(network) == 0) return;
+ final InetAddress srcAddr = getFirstV4Address(network);
+ assumeTrue("This test requires native IPv4", srcAddr != null);
+
// If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support
// NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive
// needs to be supported except if the kernel doesn't support it.
if (!isTcpKeepaliveSupportedByKernel()) {
// Sanity check to ensure the callback result is expected.
- assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1));
+ runWithShellPermissionIdentity(() -> {
+ assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1));
+ });
Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel "
+ VintfRuntimeInfo.getKernelVersion());
return;
@@ -991,6 +1022,8 @@
// Should able to start keep alive offload when socket is idle.
final Executor executor = mContext.getMainExecutor();
final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
+
+ mUiAutomation.adoptShellPermissionIdentity();
try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) {
sk.start(MIN_KEEPALIVE_INTERVAL);
callback.expectStarted();
@@ -1012,6 +1045,8 @@
// Stop.
sk.stop();
callback.expectStopped();
+ } finally {
+ mUiAutomation.dropShellPermissionIdentity();
}
// Ensure socket is still connected.
@@ -1040,9 +1075,12 @@
// Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue
// that has not been read.
+ mUiAutomation.adoptShellPermissionIdentity();
try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) {
sk.start(MIN_KEEPALIVE_INTERVAL);
callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE);
+ } finally {
+ mUiAutomation.dropShellPermissionIdentity();
}
}
}
@@ -1087,7 +1125,7 @@
}
private @NonNull ArrayList<SocketKeepalive> createConcurrentNattSocketKeepalives(
- @NonNull Network network, int requestCount,
+ @NonNull Network network, @NonNull InetAddress srcAddr, int requestCount,
@NonNull TestSocketKeepaliveCallback callback) throws Exception {
final Executor executor = mContext.getMainExecutor();
@@ -1095,7 +1133,6 @@
// Initialize a real NaT-T socket.
final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket();
- final InetAddress srcAddr = getFirstV4Address(network);
final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET);
assertNotNull(srcAddr);
assertNotNull(dstAddr);
@@ -1136,11 +1173,12 @@
* @return the total number of keepalives created.
*/
private int createConcurrentSocketKeepalives(
- @NonNull Network network, int nattCount, int tcpCount) throws Exception {
+ @NonNull Network network, @NonNull InetAddress srcAddr, int nattCount, int tcpCount)
+ throws Exception {
final ArrayList<SocketKeepalive> kalist = new ArrayList<>();
final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
- kalist.addAll(createConcurrentNattSocketKeepalives(network, nattCount, callback));
+ kalist.addAll(createConcurrentNattSocketKeepalives(network, srcAddr, nattCount, callback));
kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback));
final int ret = kalist.size();
@@ -1160,6 +1198,7 @@
* get leaked after iterations.
*/
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
public void testSocketKeepaliveLimitWifi() throws Exception {
if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device"
@@ -1172,33 +1211,39 @@
if (supported == 0) {
return;
}
+ final InetAddress srcAddr = getFirstV4Address(network);
+ assumeTrue("This test requires native IPv4", srcAddr != null);
- adoptShellPermissionIdentity();
+ runWithShellPermissionIdentity(() -> {
+ // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT.
+ assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT);
- // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT.
- assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT);
-
- // Verifies that Nat-T keepalives can be established.
- assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0));
- // Verifies that keepalives don't get leaked in second round.
- assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0));
+ // Verifies that Nat-T keepalives can be established.
+ assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
+ supported + 1, 0));
+ // Verifies that keepalives don't get leaked in second round.
+ assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported,
+ 0));
+ });
// If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support
// NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel.
- if (isTcpKeepaliveSupportedByKernel()) {
- assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported + 1));
+ if (!isTcpKeepaliveSupportedByKernel()) return;
+
+ runWithShellPermissionIdentity(() -> {
+ assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0,
+ supported + 1));
// Verifies that different types can be established at the same time.
- assertEquals(supported, createConcurrentSocketKeepalives(network,
+ assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
supported / 2, supported - supported / 2));
// Verifies that keepalives don't get leaked in second round.
- assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported));
- assertEquals(supported, createConcurrentSocketKeepalives(network,
+ assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0,
+ supported));
+ assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
supported / 2, supported - supported / 2));
- }
-
- dropShellPermissionIdentity();
+ });
}
/**
@@ -1206,6 +1251,7 @@
* don't get leaked after iterations.
*/
@AppModeFull(reason = "Cannot request network in instant app mode")
+ @Test
public void testSocketKeepaliveLimitTelephony() throws Exception {
if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) {
Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device"
@@ -1222,18 +1268,19 @@
final Network network = mCtsNetUtils.connectToCell();
final int supported = getSupportedKeepalivesForNet(network);
+ final InetAddress srcAddr = getFirstV4Address(network);
+ assumeTrue("This test requires native IPv4", srcAddr != null);
- adoptShellPermissionIdentity();
-
- // Verifies that the supported keepalive slots meet minimum requirement.
- assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT);
-
- // Verifies that Nat-T keepalives can be established.
- assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0));
- // Verifies that keepalives don't get leaked in second round.
- assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0));
-
- dropShellPermissionIdentity();
+ runWithShellPermissionIdentity(() -> {
+ // Verifies that the supported keepalive slots meet minimum requirement.
+ assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT);
+ // Verifies that Nat-T keepalives can be established.
+ assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
+ supported + 1, 0));
+ // Verifies that keepalives don't get leaked in second round.
+ assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported,
+ 0));
+ });
}
private int getIntResourceForName(@NonNull String resName) {
@@ -1246,6 +1293,7 @@
* Verifies that the keepalive slots are limited as customized for unprivileged requests.
*/
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
public void testSocketKeepaliveUnprivileged() throws Exception {
if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device"
@@ -1258,6 +1306,8 @@
if (supported == 0) {
return;
}
+ final InetAddress srcAddr = getFirstV4Address(network);
+ assumeTrue("This test requires native IPv4", srcAddr != null);
// Resource ID might be shifted on devices that compiled with different symbols.
// Thus, resolve ID at runtime is needed.
@@ -1273,11 +1323,46 @@
final int expectedUnprivileged =
Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots);
assertEquals(expectedUnprivileged,
- createConcurrentSocketKeepalives(network, supported + 1, 0));
+ createConcurrentSocketKeepalives(network, srcAddr, supported + 1, 0));
}
private static void assertGreaterOrEqual(long greater, long lesser) {
assertTrue("" + greater + " expected to be greater than or equal to " + lesser,
greater >= lesser);
}
+
+ /**
+ * Verifies that apps are not allowed to access restricted networks even if they declare the
+ * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission in their manifests.
+ * See. b/144679405.
+ */
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test
+ public void testRestrictedNetworkPermission() throws Exception {
+ // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package.
+ final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(),
+ GET_PERMISSIONS);
+ final int index = ArrayUtils.indexOf(
+ app.requestedPermissions, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ assertTrue(index >= 0);
+ assertTrue(app.requestedPermissionsFlags[index] != PERMISSION_GRANTED);
+
+ // Ensure that NetworkUtils.queryUserAccess always returns false since this package should
+ // not have netd system permission to call this function.
+ final Network wifiNetwork = ensureWifiConnected();
+ assertFalse(NetworkUtils.queryUserAccess(Binder.getCallingUid(), wifiNetwork.netId));
+
+ // Ensure that this package cannot bind to any restricted network that's currently
+ // connected.
+ Network[] networks = mCm.getAllNetworks();
+ for (Network network : networks) {
+ NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
+ if (nc != null && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
+ try {
+ network.bindSocket(new Socket());
+ fail("Bind to restricted network " + network + " unexpectedly succeeded");
+ } catch (IOException expected) {}
+ }
+ }
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java
index 1cc49f9..28753ff 100644
--- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java
+++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java
@@ -86,7 +86,6 @@
static final int CANCEL_RETRY_TIMES = 5;
static final int QUERY_TIMES = 10;
static final int NXDOMAIN = 3;
- static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000;
private ContentResolver mCR;
private ConnectivityManager mCM;
@@ -107,32 +106,15 @@
mExecutorInline = (Runnable r) -> r.run();
mCR = getContext().getContentResolver();
mCtsNetUtils = new CtsNetUtils(getContext());
- storePrivateDnsSetting();
+ mCtsNetUtils.storePrivateDnsSetting();
}
@Override
protected void tearDown() throws Exception {
- restorePrivateDnsSetting();
+ mCtsNetUtils.restorePrivateDnsSetting();
super.tearDown();
}
- private void storePrivateDnsSetting() {
- // Store private DNS setting
- mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE);
- mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER);
- }
-
- private void restorePrivateDnsSetting() throws InterruptedException {
- // restore private DNS setting
- Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode);
- if ("hostname".equals(mOldMode)) {
- Settings.Global.putString(
- mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier);
- mCtsNetUtils.awaitPrivateDnsSetting("restorePrivateDnsSetting timeout",
- mCM.getActiveNetwork(), mOldDnsSpecifier, PRIVATE_DNS_SETTING_TIMEOUT_MS, true);
- }
- }
-
private static String byteArrayToHexString(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int i = 0; i < bytes.length; ++i) {
@@ -416,16 +398,13 @@
final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS";
// Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
// b/144521720
- Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
- Settings.Global.putString(mCR,
- Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER);
+ mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER);
for (Network network : getTestableNetworks()) {
final Network networkForPrivateDns =
(network != null) ? network : mCM.getActiveNetwork();
assertNotNull("Can't find network to await private DNS on", networkForPrivateDns);
mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
- networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER,
- PRIVATE_DNS_SETTING_TIMEOUT_MS, true);
+ networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, true);
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
executor, null, callback);
@@ -688,9 +667,7 @@
final Network[] testNetworks = getTestableNetworks();
// Set an invalid private DNS server
- Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
- Settings.Global.putString(mCR,
- Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER);
+ mCtsNetUtils.setPrivateDnsStrictMode(INVALID_PRIVATE_DNS_SERVER);
final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN;
for (Network network : testNetworks) {
// This test cannot be ran with null network because we need to explicitly pass a
@@ -699,7 +676,7 @@
// wait for private DNS setting propagating
mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
- network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, false);
+ network, INVALID_PRIVATE_DNS_SERVER, false);
final CountDownLatch latch = new CountDownLatch(1);
final DnsResolver.Callback<List<InetAddress>> errorCallback =
diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java
index f123187..985e313 100644
--- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java
+++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java
@@ -41,7 +41,6 @@
private static final String TAG = "MultinetworkNativeApiTest";
static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google";
- static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000;
/**
* @return 0 on success
@@ -69,7 +68,7 @@
mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
mCR = getContext().getContentResolver();
mCtsNetUtils = new CtsNetUtils(getContext());
- storePrivateDnsSetting();
+ mCtsNetUtils.storePrivateDnsSetting();
}
@Override
@@ -77,18 +76,6 @@
super.tearDown();
}
- private void storePrivateDnsSetting() {
- // Store private DNS setting
- mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE);
- mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER);
- }
-
- private void restorePrivateDnsSetting() {
- // restore private DNS setting
- Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode);
- Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier);
- }
-
private Network[] getTestableNetworks() {
final ArrayList<Network> testableNetworks = new ArrayList<Network>();
for (Network network : mCM.getAllNetworks()) {
@@ -239,17 +226,15 @@
// Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
// b/144521720
try {
- Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
- Settings.Global.putString(mCR,
- Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER);
+ mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER);
for (Network network : getTestableNetworks()) {
// Wait for private DNS setting to propagate.
mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout",
- network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, true);
+ network, GOOGLE_PRIVATE_DNS_SERVER, true);
runResNnxDomainCheck(network.getNetworkHandle());
}
} finally {
- restorePrivateDnsSetting();
+ mCtsNetUtils.restorePrivateDnsSetting();
}
}
}
diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java
index f32ee9e..d118c8a 100644
--- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java
+++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java
@@ -18,6 +18,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
@@ -86,6 +87,16 @@
verifyNoCapabilities(nr);
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testTemporarilyNotMeteredCapability() {
+ assertTrue(new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build()
+ .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ assertFalse(new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build()
+ .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ }
+
private void verifyNoCapabilities(NetworkRequest nr) {
// NetworkCapabilities.mNetworkCapabilities is defined as type long
final int MAX_POSSIBLE_CAPABILITY = Long.SIZE;
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index 824146f..f39b184 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -17,6 +17,7 @@
package android.net.cts.util;
import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -28,6 +29,7 @@
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
@@ -39,6 +41,7 @@
import android.net.NetworkInfo.State;
import android.net.NetworkRequest;
import android.net.wifi.WifiManager;
+import android.provider.Settings;
import android.system.Os;
import android.system.OsConstants;
import android.util.Log;
@@ -59,6 +62,7 @@
private static final int SOCKET_TIMEOUT_MS = 2000;
private static final int PRIVATE_DNS_PROBE_MS = 1_000;
+ public static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000;
public static final int HTTP_PORT = 80;
public static final String TEST_HOST = "connectivitycheck.gstatic.com";
public static final String HTTP_REQUEST =
@@ -69,15 +73,19 @@
public static final String NETWORK_CALLBACK_ACTION =
"ConnectivityManagerTest.NetworkCallbackAction";
- private Context mContext;
- private ConnectivityManager mCm;
- private WifiManager mWifiManager;
+ private final Context mContext;
+ private final ConnectivityManager mCm;
+ private final ContentResolver mCR;
+ private final WifiManager mWifiManager;
private TestNetworkCallback mCellNetworkCallback;
+ private String mOldPrivateDnsMode;
+ private String mOldPrivateDnsSpecifier;
public CtsNetUtils(Context context) {
mContext = context;
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ mCR = context.getContentResolver();
}
// Toggle WiFi twice, leaving it in the state it started in
@@ -249,9 +257,51 @@
return s;
}
+ public void storePrivateDnsSetting() {
+ // Store private DNS setting
+ mOldPrivateDnsMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE);
+ mOldPrivateDnsSpecifier = Settings.Global.getString(mCR,
+ Settings.Global.PRIVATE_DNS_SPECIFIER);
+ // It's possible that there is no private DNS default value in Settings.
+ // Give it a proper default mode which is opportunistic mode.
+ if (mOldPrivateDnsMode == null) {
+ mOldPrivateDnsSpecifier = "";
+ mOldPrivateDnsMode = PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ Settings.Global.putString(mCR,
+ Settings.Global.PRIVATE_DNS_SPECIFIER, mOldPrivateDnsSpecifier);
+ Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode);
+ }
+ }
+
+ public void restorePrivateDnsSetting() throws InterruptedException {
+ if (mOldPrivateDnsMode == null || mOldPrivateDnsSpecifier == null) {
+ return;
+ }
+ // restore private DNS setting
+ if ("hostname".equals(mOldPrivateDnsMode)) {
+ setPrivateDnsStrictMode(mOldPrivateDnsSpecifier);
+ awaitPrivateDnsSetting("restorePrivateDnsSetting timeout",
+ mCm.getActiveNetwork(),
+ mOldPrivateDnsSpecifier, true);
+ } else {
+ Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode);
+ }
+ }
+
+ public void setPrivateDnsStrictMode(String server) {
+ // To reduce flake rate, set PRIVATE_DNS_SPECIFIER before PRIVATE_DNS_MODE. This ensures
+ // that if the previous private DNS mode was not "hostname", the system only sees one
+ // EVENT_PRIVATE_DNS_SETTINGS_CHANGED event instead of two.
+ Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, server);
+ final String mode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE);
+ // If current private DNS mode is "hostname", we only need to set PRIVATE_DNS_SPECIFIER.
+ if (!"hostname".equals(mode)) {
+ Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
+ }
+ }
+
public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network,
- @NonNull String server, int timeoutMs,
- boolean requiresValidatedServers) throws InterruptedException {
+ @NonNull String server, boolean requiresValidatedServers) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
NetworkCallback callback = new NetworkCallback() {
@@ -266,7 +316,7 @@
}
};
mCm.registerNetworkCallback(request, callback);
- assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS));
+ assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS));
mCm.unregisterNetworkCallback(callback);
// Wait some time for NetworkMonitor's private DNS probe to complete. If we do not do
// this, then the test could complete before the NetworkMonitor private DNS probe