Merge "Skip unsupported hardware for testB141603906"
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
index d312f18..81a431c 100755
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -17,13 +17,26 @@
package com.android.cts.net.hostside;
import static android.os.Process.INVALID_UID;
-import static android.system.OsConstants.*;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.ECONNABORTED;
+import static android.system.OsConstants.IPPROTO_ICMP;
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.POLLIN;
+import static android.system.OsConstants.SOCK_DGRAM;
import android.annotation.Nullable;
+import android.app.DownloadManager;
+import android.app.DownloadManager.Query;
+import android.app.DownloadManager.Request;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.LinkProperties;
@@ -32,12 +45,13 @@
import android.net.NetworkRequest;
import android.net.Proxy;
import android.net.ProxyInfo;
+import android.net.Uri;
import android.net.VpnService;
import android.net.wifi.WifiManager;
-import android.provider.Settings;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiSelector;
@@ -64,12 +78,12 @@
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
-import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Random;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -1090,4 +1104,62 @@
received = true;
}
}
+
+ /**
+ * Verifies that DownloadManager has CONNECTIVITY_USE_RESTRICTED_NETWORKS permission that can
+ * bind socket to VPN when it is in VPN disallowed list but requested downloading app is in VPN
+ * allowed list.
+ * See b/165774987.
+ */
+ public void testDownloadWithDownloadManagerDisallowed() throws Exception {
+ if (!supportedHardware()) return;
+
+ // Start a VPN with DownloadManager package in disallowed list.
+ startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
+ new String[] {"192.0.2.0/24", "2001:db8::/32"},
+ "" /* allowedApps */, "com.android.providers.downloads", null /* proxyInfo */,
+ null /* underlyingNetworks */, false /* isAlwaysMetered */);
+
+ final Context context = VpnTest.this.getInstrumentation().getContext();
+ final DownloadManager dm = context.getSystemService(DownloadManager.class);
+ final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
+ try {
+ context.registerReceiver(receiver,
+ new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+
+ // Enqueue a request and check only one download.
+ final long id = dm.enqueue(new Request(Uri.parse("https://www.google.com")));
+ assertEquals(1, getTotalNumberDownloads(dm, new Query()));
+ assertEquals(1, getTotalNumberDownloads(dm, new Query().setFilterById(id)));
+
+ // Wait for download complete and check status.
+ assertEquals(id, receiver.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(1, getTotalNumberDownloads(dm,
+ new Query().setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL)));
+
+ // Remove download.
+ assertEquals(1, dm.remove(id));
+ assertEquals(0, getTotalNumberDownloads(dm, new Query()));
+ } finally {
+ context.unregisterReceiver(receiver);
+ }
+ }
+
+ private static int getTotalNumberDownloads(final DownloadManager dm, final Query query) {
+ try (Cursor cursor = dm.query(query)) { return cursor.getCount(); }
+ }
+
+ private static class DownloadCompleteReceiver extends BroadcastReceiver {
+ private final CompletableFuture<Long> future = new CompletableFuture<>();
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ future.complete(intent.getLongExtra(
+ DownloadManager.EXTRA_DOWNLOAD_ID, -1 /* defaultValue */));
+ }
+
+ public long get(long timeout, TimeUnit unit) throws Exception {
+ return future.get(timeout, unit);
+ }
+ }
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
index 62925ad..49b5f9d 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
@@ -95,4 +95,9 @@
public void testB141603906() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testB141603906");
}
+
+ public void testDownloadWithDownloadManagerDisallowed() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest",
+ "testDownloadWithDownloadManagerDisallowed");
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 0790acb..70b1bbe 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -97,7 +97,9 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ArrayUtils;
+import com.android.testutils.RecorderCallback.CallbackEntry;
import com.android.testutils.SkipPresubmit;
+import com.android.testutils.TestableNetworkCallback;
import libcore.io.Streams;
@@ -155,7 +157,7 @@
private static final int MIN_NUM_NETWORK_TYPES = 1;
// Airplane Mode BroadcastReceiver Timeout
- private static final int AIRPLANE_MODE_CHANGE_TIMEOUT_MS = 5000;
+ private static final long AIRPLANE_MODE_CHANGE_TIMEOUT_MS = 10_000L;
// Minimum supported keepalive counts for wifi and cellular.
public static final int MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT = 1;
@@ -473,6 +475,12 @@
.build();
}
+ private NetworkRequest makeCellNetworkRequest() {
+ return new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build();
+ }
+
/**
* Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
* see if we get a callback for the TRANSPORT_WIFI transport type being available.
@@ -599,7 +607,7 @@
public void testRequestNetworkCallback_onUnavailable() {
final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
if (previousWifiEnabledState) {
- mCtsNetUtils.disconnectFromWifi(null);
+ mCtsNetUtils.ensureWifiDisconnected(null);
}
final TestNetworkCallback callback = new TestNetworkCallback();
@@ -1387,11 +1395,19 @@
@AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps")
@Test
public void testSetAirplaneMode() throws Exception{
+ final boolean supportWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI);
+ final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
// store the current state of airplane mode
final boolean isAirplaneModeEnabled = isAirplaneModeEnabled();
-
+ final TestableNetworkCallback wifiCb = new TestableNetworkCallback();
+ final TestableNetworkCallback telephonyCb = new TestableNetworkCallback();
// disable airplane mode to reach a known state
runShellCommand("cmd connectivity airplane-mode disable");
+ // Verify that networks are available as expected if wifi or cell is supported. Continue the
+ // test if none of them are supported since test should still able to verify the permission
+ // mechanism.
+ if (supportWifi) requestAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb);
+ if (supportTelephony) requestAndWaitForAvailable(makeCellNetworkRequest(), telephonyCb);
try {
// Verify we cannot set Airplane Mode without correct permission:
@@ -1414,6 +1430,11 @@
fail("SecurityException should not have been thrown when setAirplaneMode(true) was"
+ "called whilst holding the NETWORK_AIRPLANE_MODE permission.");
}
+ // Verify that the enabling airplane mode takes effect as expected to prevent flakiness
+ // caused by fast airplane mode switches. Ensure network lost before turning off
+ // airplane mode.
+ if (supportWifi) waitForLost(wifiCb);
+ if (supportTelephony) waitForLost(telephonyCb);
// Verify we can disable Airplane Mode with correct permission:
try {
@@ -1422,8 +1443,12 @@
fail("SecurityException should not have been thrown when setAirplaneMode(false) was"
+ "called whilst holding the NETWORK_AIRPLANE_MODE permission.");
}
-
+ // Verify that turning airplane mode off takes effect as expected.
+ if (supportWifi) waitForAvailable(wifiCb);
+ if (supportTelephony) waitForAvailable(telephonyCb);
} finally {
+ if (supportWifi) mCm.unregisterNetworkCallback(wifiCb);
+ if (supportTelephony) mCm.unregisterNetworkCallback(telephonyCb);
// Restore the previous state of airplane mode and permissions:
runShellCommand("cmd connectivity airplane-mode "
+ (isAirplaneModeEnabled ? "enable" : "disable"));
@@ -1431,6 +1456,22 @@
}
}
+ private void requestAndWaitForAvailable(@NonNull final NetworkRequest request,
+ @NonNull final TestableNetworkCallback cb) {
+ mCm.registerNetworkCallback(request, cb);
+ waitForAvailable(cb);
+ }
+
+ private void waitForAvailable(@NonNull final TestableNetworkCallback cb) {
+ cb.eventuallyExpect(CallbackEntry.AVAILABLE, AIRPLANE_MODE_CHANGE_TIMEOUT_MS,
+ c -> c instanceof CallbackEntry.Available);
+ }
+
+ private void waitForLost(@NonNull final TestableNetworkCallback cb) {
+ cb.eventuallyExpect(CallbackEntry.LOST, AIRPLANE_MODE_CHANGE_TIMEOUT_MS,
+ c -> c instanceof CallbackEntry.Lost);
+ }
+
private void setAndVerifyAirplaneMode(Boolean expectedResult)
throws Exception {
final CompletableFuture<Boolean> actualResult = new CompletableFuture();